# VCTP Auth Design TODO (LDAP + JWT) ## 1. Goal Add authentication and authorization to VCTP for sensitive endpoints, using the LDAP bind + JWT pattern from `cbs2` as a reference, adapted to VCTP's `net/http` architecture. ## 2. Reference Findings from `cbs2` ### 2.1 Where auth lives in `cbs2` - Login handler: `/tmp/cbs2/server/handler/auth.go` - JWT middleware: `/tmp/cbs2/server/handler/middlewares.go` - Token utilities: `/tmp/cbs2/utils/token/token.go` - LDAP bind + group lookup: `/tmp/cbs2/internal/ldap/ldap.go` - Route protection split (public vs protected): `/tmp/cbs2/server/router/router.go` - Settings fields for LDAP/JWT: `/tmp/cbs2/internal/settings/settings.go` and `/tmp/cbs2/src/cbs.yml` ### 2.2 Pattern to reuse - LDAP username/password bind for authentication. - LDAP group membership check for authorization at login. - Signed JWT access token with expiry. - Middleware that validates `Authorization: Bearer `. - Router-level grouping for protected routes. ### 2.3 Things to improve (do not copy as-is) - Avoid hardcoded fallback JWT secret (present in `cbs2` middleware). - Avoid logging sensitive token/key values. - Avoid weak/ambiguous claim model; use explicit issuer/audience/subject/exp/iat. - Keep strict method/endpoint policy in one place instead of ad-hoc checks. ## 3. Proposed VCTP Auth Architecture ### 3.1 New packages/modules 1. `internal/auth/ldap.go` - LDAP setup/connection helpers. - `AuthenticateAndFetchGroups(username, password) ([]string, error)`. 2. `internal/auth/jwt.go` - JWT issue and verify. - Claims struct with: - `sub` (username) - `roles` (derived roles) - `groups` (optional raw LDAP groups) - `iss`, `aud`, `iat`, `exp`, `nbf`, `jti` 3. `server/middleware/auth.go` - `RequireAuth(...)` for token validation. - `RequireRole(...)` for endpoint authorization. - Context injection for user identity and roles. 4. `server/handler/auth.go` - `POST /api/auth/login` - Optional `GET /api/auth/me` for debugging/whoami. ### 3.2 Route protection model Define a central policy map in router startup (single source of truth): - Public (no auth): - `/assets/*`, `/favicon*`, `/swagger*` (optional decision), `/` (optional decision) - Authenticated read-only (viewer role): - `/vcenters*`, `/snapshots/*`, `/vm/trace`, `/api/report/*`, `/metrics` (optional decision) - Privileged write/admin (admin role): - `/api/snapshots/*` mutating endpoints - `/api/vcenters/cache/rebuild` - `/api/encrypt` - legacy mutating endpoints (`/api/event/*`, `/api/import/vm`, `/api/inventory/vm/*`, `/api/cleanup/*`) - Debug endpoints (`/debug/pprof/*`): - disabled by default via config - if enabled, require admin ## 4. VCTP Settings Additions Add under `settings:` in `internal/settings/settings.go` and `src/vctp.yml`: 1. `auth_enabled: false` 2. `auth_mode: "disabled"` (`disabled|optional|required`) 3. `auth_jwt_signing_key: ""` (base64-encoded, required when auth enabled) 4. `auth_token_lifespan_minutes: 120` 5. `auth_jwt_issuer: "vctp"` 6. `auth_jwt_audience: "vctp-api"` 7. `auth_clock_skew_seconds: 60` 8. `ldap_groups: []` 9. `ldap_bind_address: ""` 10. `ldap_base_dn: ""` 11. `ldap_trust_cert_file: ""` 12. `ldap_disable_validation: false` 13. `ldap_insecure: false` 14. `enable_pprof: false` ## 5. Role Mapping Use LDAP group DN mapping to roles (config-driven): - `auth_group_role_mappings` map/list, e.g.: - group DN -> `admin` - group DN -> `viewer` Default behavior: - No mapped group: deny login. - Multiple matches: union roles. ## 6. API Contract ### 6.1 Login `POST /api/auth/login` - Request: `{ "username": "...", "password": "..." }` - Success: `{ "access_token": "...", "expires_at": , "token_type": "Bearer" }` - Failure: `401` with generic message (no user/group leakage) ### 6.2 Auth header - `Authorization: Bearer ` ### 6.3 Error behavior - Missing/invalid token: `401` - Valid token but insufficient role: `403` ## 7. Rollout Plan ### Phase 1: Foundation 1. Implement settings fields and validation. 2. Implement LDAP and JWT services. 3. Add `/api/auth/login`. 4. Add unit tests for token generation/validation and LDAP auth abstraction. ### Phase 2: Middleware + policy 1. Add auth middleware for `net/http`. 2. Protect sensitive routes via central policy map. 3. Keep `auth_mode=optional` initially for safe rollout. ### Phase 3: Enforce + harden 1. Switch production to `auth_mode=required`. 2. Gate/disable pprof by config. 3. Add structured audit logs for auth events. 4. Update Swagger security docs and README. ## 8. Validation and Tests 1. Unit tests - JWT: expired token, wrong signature, wrong issuer/audience, clock skew. - Role extraction and mapping. 2. Integration tests (handler/middleware) - Unauthenticated access blocked on protected endpoints. - Viewer can read but cannot mutate. - Admin can mutate. 3. Regression checks - Existing legacy endpoint gating (`enable_legacy_api`) still behaves correctly after auth layering. ## 9. Open Decisions 1. Should `/metrics` require auth in your deployment? No there is no need for auth for this endpoint 2. Should UI pages (`/`, `/vcenters`, `/snapshots/*`, `/vm/trace`) require login or stay public? These should stay public 3. Should Swagger UI be public, authenticated, or disabled in production? These should stay public 4. Do you want short-lived access tokens only, or access + refresh token flow? Short lived access tokens please, 2 hours is good enough ## 10. Implementation Notes for VCTP 1. Reuse `cbs2` LDAP flow shape, but avoid its fallback secret behavior. 2. Keep all secret material redacted in logs. 3. Validate required auth settings at startup when `auth_enabled=true`. 4. Prefer fail-closed: if auth is enabled and misconfigured, abort startup.