157 lines
5.6 KiB
Markdown
157 lines
5.6 KiB
Markdown
# 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 <token>`.
|
|
- 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": <unix>, "token_type": "Bearer" }`
|
|
- Failure: `401` with generic message (no user/group leakage)
|
|
|
|
### 6.2 Auth header
|
|
- `Authorization: Bearer <jwt>`
|
|
|
|
### 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.
|
|
|