docs: add identity & auth documentation — The Guest List 💋
OIDC auth flow, Kratos + Hydra, client registry (12 apps), session management, identity schemas, self-service flows, Vault integration.
This commit is contained in:
151
docs/identity.md
Normal file
151
docs/identity.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# The Guest List 💋
|
||||
|
||||
Every app in The Super Boujee Business Box ✨ authenticates through the same door. One login, every room. You don't re-authenticate because you walked from Docs to Drive — that's not a feature, that's just manners.
|
||||
|
||||
The identity layer is built on **Ory Kratos** (who you are) and **Ory Hydra** (what you're allowed to do). Lightweight Go binaries, no JVM, no XML — they fit k3s like they were born for it. We chose them over Keycloak because we wanted something that didn't need 2GB of RAM to tell you who's logged in.
|
||||
|
||||
---
|
||||
|
||||
## The Auth Flow
|
||||
|
||||
```
|
||||
You → any app (docs.sunbeam.pt, drive.sunbeam.pt, etc.)
|
||||
→ 302 redirect to auth.sunbeam.pt
|
||||
→ Hydra says "who are you?"
|
||||
→ Kratos login UI (password, TOTP, WebAuthn — your pick)
|
||||
→ authenticate
|
||||
→ Hydra issues OIDC token
|
||||
→ 302 back to the app
|
||||
→ app validates via mozilla-django-oidc
|
||||
→ session established ✨
|
||||
```
|
||||
|
||||
That's it. Every La Suite app uses the same `mozilla-django-oidc` library. Swapping from Keycloak (the French government default) to Hydra was transparent at the app level — same OIDC, different provider.
|
||||
|
||||
---
|
||||
|
||||
## The Players
|
||||
|
||||
### Ory Kratos — Identity Management
|
||||
|
||||
Handles the "who are you" part:
|
||||
|
||||
- **Registration** — create accounts (or provision them via `sunbeam auth identity create`)
|
||||
- **Login** — password, TOTP, WebAuthn, lookup secrets
|
||||
- **Profile** — name, email, metadata
|
||||
- **Recovery** — password reset via email (through Postfix)
|
||||
- **Session** — 720 hours (30 days), cookie-scoped to parent domain
|
||||
|
||||
The cookie-scoping is key: setting the session cookie on the parent domain means all `*.sunbeam.pt` subdomains share the session. Log in once, you're everywhere.
|
||||
|
||||
### Identity Schemas
|
||||
|
||||
Three schemas for different types of users:
|
||||
|
||||
| Schema | Purpose |
|
||||
|--------|---------|
|
||||
| `employee` | Core team (Sienna, Amber, Lonni) — full access, all apps |
|
||||
| `default` | Standard users — for when the team grows |
|
||||
| `external` | External collaborators — limited scope |
|
||||
|
||||
### Ory Hydra — OAuth2 / OIDC Provider
|
||||
|
||||
Handles the "what can you do" part:
|
||||
|
||||
- Issues OAuth2 access tokens and OIDC ID tokens
|
||||
- Manages the OIDC client registry
|
||||
- Token lifetimes: access/ID tokens 1h, refresh tokens 720h, auth session 720h
|
||||
- OpenID Connect discovery at `auth.sunbeam.pt/.well-known/openid-configuration`
|
||||
|
||||
### Hydra Maester
|
||||
|
||||
The secret sauce for client management. Watches `HydraOAuth2Client` CRDs in Kubernetes and automatically:
|
||||
|
||||
1. Registers the client with Hydra
|
||||
2. Creates a K8s Secret with `CLIENT_ID` and `CLIENT_SECRET`
|
||||
3. Keeps them in sync if the CRD changes
|
||||
|
||||
No manual client registration. Declare a CRD, get a working OIDC client.
|
||||
|
||||
---
|
||||
|
||||
## The OIDC Client Registry
|
||||
|
||||
Every app is a registered OIDC client. Hydra Maester manages all of them:
|
||||
|
||||
| App | Secret Name | Redirect URI | Notes |
|
||||
|-----|-------------|-------------|-------|
|
||||
| Docs | oidc-docs | `docs.DOMAIN/api/v1.0/callback/` | |
|
||||
| Drive | oidc-drive | `drive.DOMAIN/api/v1.0/callback/` | |
|
||||
| Meet | oidc-meet | `meet.DOMAIN/api/v1.0/callback/` | |
|
||||
| Messages | oidc-messages | `mail.DOMAIN/api/v1.0/callback/` | `offline_access` scope |
|
||||
| People | oidc-people | `people.DOMAIN/api/v1.0/callback/` | |
|
||||
| Find | oidc-find | `find.DOMAIN/oidc/callback/` | |
|
||||
| Gitea | oidc-gitea | `src.DOMAIN/user/oauth2/Sunbeam/callback` | |
|
||||
| Calendars | oidc-calendars | `cal.DOMAIN/api/v1.0/callback/` | |
|
||||
| Projects | oidc-projects | `projects.DOMAIN/oidc-callback` | |
|
||||
| Hive | oidc-hive | *(none)* | `client_credentials` grant |
|
||||
| Tuwunel | oidc-tuwunel | *(matrix namespace)* | Matrix SSO |
|
||||
| Grafana | grafana-oidc | *(monitoring namespace)* | auto-assign Admin role |
|
||||
|
||||
Messages gets `offline_access` to maintain sessions across browser restarts. Hive uses `client_credentials` because it's a service, not a human. Grafana auto-assigns Admin because if you're authenticated, you're on the team.
|
||||
|
||||
---
|
||||
|
||||
## Self-Service Flows
|
||||
|
||||
Users can manage their own security:
|
||||
|
||||
| Method | What it is |
|
||||
|--------|-----------|
|
||||
| **Password** | Classic email + password |
|
||||
| **TOTP** | Time-based one-time passwords (Google Authenticator, etc.) |
|
||||
| **WebAuthn** | Hardware security keys (YubiKey, etc.) |
|
||||
| **Lookup Secrets** | Backup/recovery codes |
|
||||
|
||||
Recovery emails go through Postfix (same SMTP used by Messages) at `postfix.lasuite.svc:25`.
|
||||
|
||||
---
|
||||
|
||||
## Vault Integration
|
||||
|
||||
Secrets don't live in Git. They live in OpenBao (Vault) and sync to Kubernetes via Vault Secrets Operator.
|
||||
|
||||
### OIDC Client Secrets
|
||||
Hydra Maester creates K8s Secrets from HydraOAuth2Client CRDs. These contain `CLIENT_ID` and `CLIENT_SECRET` that apps consume.
|
||||
|
||||
### Dynamic Database Credentials
|
||||
Every app's database password rotates every 5 minutes via `VaultDynamicSecret`. The Vault Secrets Operator:
|
||||
1. Requests new credentials from OpenBao's database engine
|
||||
2. Creates/updates the K8s Secret
|
||||
3. Triggers a rollout restart of the affected Deployment
|
||||
|
||||
### Static Secrets
|
||||
Django secret keys, DKIM keys, API tokens — synced from OpenBao KV v2 with 30-second refresh via `VaultStaticSecret`.
|
||||
|
||||
---
|
||||
|
||||
## Admin Access
|
||||
|
||||
For when you need to manage identities directly:
|
||||
|
||||
```bash
|
||||
# Via sunbeam CLI
|
||||
sunbeam auth identity list
|
||||
sunbeam auth identity create amber@sunbeam.pt --name "Amber"
|
||||
sunbeam auth identity get <id>
|
||||
|
||||
# Via Kratos Admin API (auth-gated through proxy)
|
||||
# Accessible at id.sunbeam.pt (requires Hydra /userinfo auth)
|
||||
|
||||
# Via Hydra Admin API (auth-gated through proxy)
|
||||
# Accessible at hydra.sunbeam.pt (requires Hydra /userinfo auth)
|
||||
```
|
||||
|
||||
Sol☀️ also has Kratos admin access for identity operations within Matrix chat.
|
||||
|
||||
---
|
||||
|
||||
## The Login UI
|
||||
|
||||
Sunbeam-branded login, consent, and recovery pages served by `kratos-admin-ui`. This is what you see at `auth.sunbeam.pt` — the velvet rope. Custom logo, custom colors, same energy as everything else in the box. ✨
|
||||
Reference in New Issue
Block a user