diff --git a/API.md b/API.md index 74b9288..af944de 100644 --- a/API.md +++ b/API.md @@ -633,17 +633,104 @@ Authentik tokens include these custom claims: } ``` -### Capabilities (RBAC) +### Service Account Auth (Recommended for Services) -The `permissions` claim contains capabilities. Gateway checks these: +Service accounts use **roles** stored in user attributes. Simpler than groups. -| Capability | Required for | Granted to | -|------------|--------------|------------| -| `llm:inference` | `/v1/chat/completions`, `/v1/embeddings`, `/v1/rerank` | llm-admins, llm-users | -| `memory:read` | Memory queries | memory-users, memory-writers, poimen-memory-admins | -| `memory:write` | Memory ingest | memory-writers, poimen-memory-admins | -| `memory:admin` | Memory admin ops | poimen-memory-admins | -| `*` | Everything | homelab-admins | +**JWT claims (client_credentials flow):** +```json +{ + "azp": "portfolio-agent", + "roles": ["llm:inference", "memory:read"] +} +``` + +**Gateway checks `roles` claim:** +```go +if hasRole(claims.Roles, "llm:inference") { + // allow +} +``` + +**Available roles:** + +| Role | Grants access to | +|------|------------------| +| `llm:inference` | `/v1/chat/completions`, `/v1/embeddings`, `/v1/rerank` | +| `memory:read` | Memory queries | +| `memory:write` | Memory ingest | +| `s3:read` | S3/MinIO read | +| `s3:write` | S3/MinIO write | + +--- + +### Onboarding a New Service + +1. **Add to provisioning script** (`homelab/scripts/iam/authentik-provision.py`): + +```python +SERVICE_ACCOUNTS = { + # ... existing ... + "my-new-service": { + "roles": ["llm:inference", "memory:read"], # what APIs it can call + "attributes": { + "memory_projects": ["my-project"], # optional: memory access scope + "memory_visibility": "public", + }, + "secret_ns": "my-namespace", # k8s namespace for credentials + "secret_name": "my-service-oidc", # k8s secret name + }, +} +``` + +2. **Run provisioning:** + +```bash +export AUTHENTIK_BOOTSTRAP_TOKEN=$(kubectl -n iam get secret authentik-secrets \ + -o jsonpath='{.data.AUTHENTIK_BOOTSTRAP_TOKEN}' | base64 -d) +python3 scripts/iam/authentik-provision.py +``` + +3. **Use credentials in your service:** + +```bash +# Credentials stored in k8s secret +kubectl -n my-namespace get secret my-service-oidc -o yaml +# Contains: CLIENT_ID, CLIENT_SECRET, TOKEN_URL, ISSUER + +# Get token +TOKEN=$(curl -s -X POST $TOKEN_URL \ + -d "grant_type=client_credentials" \ + -d "client_id=$CLIENT_ID" \ + -d "client_secret=$CLIENT_SECRET" \ + -d "scope=openid roles" | jq -r '.access_token') + +# Call API +curl -H "Authorization: Bearer $TOKEN" https://api.riotpiao.com/v1/models +``` + +--- + +### User Auth (Groups → Permissions) + +Human users use **groups** which map to **permissions**. Used for browser-based apps. + +**JWT claims (authorization_code flow):** +```json +{ + "groups": ["homelab-admins", "llm-admins"], + "permissions": ["*", "llm:inference", "llm:read", "llm:write"] +} +``` + +| Group | Permissions granted | +|-------|---------------------| +| `homelab-admins` | `*` (everything) | +| `llm-admins` | `llm:inference`, `llm:read`, `llm:write` | +| `llm-users` | `llm:inference` | +| `memory-users` | `memory:read` | +| `memory-writers` | `memory:read`, `memory:write` | +| `poimen-memory-admins` | `memory:*`, `memory:admin` | **Memory-specific claims:**