152 lines
5.7 KiB
Markdown
152 lines
5.7 KiB
Markdown
|
|
# 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. ✨
|