add auth support
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-04-17 13:19:08 +10:00
parent 9a561f3b07
commit ae3e2be89a
22 changed files with 2479 additions and 40 deletions
+156
View File
@@ -0,0 +1,156 @@
# 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.