Deploy Authentik identity provider (C2 Mikado) (#227)
## Summary C2 Mikado chain for deploying Authentik as the SSO identity provider, replacing Dex. This PR will evolve over multiple sessions. Each iteration adds documentation (prerequisite cards) and eventually code as leaf nodes are resolved. ## Current Mikado State - **Goal:** `deploy-authentik` (active) - **Leaf prerequisites:** - `build-authentik-container` — Build Nix container image - `provision-authentik-database` — Create PostgreSQL database on CNPG cluster - `create-authentik-secrets` — Create 1Password item with credentials ## Process refinements - Updated agent-change-process with lessons from first attempt: reset code before committing cards, open PRs early ## Test plan - [ ] `mise run docs-mikado` shows correct dependency chain - [ ] Leaf nodes can be worked independently - [ ] Container builds on ringtail - [ ] Authentik starts and reaches healthy state - [ ] Forgejo OAuth2 connector works Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/227
This commit is contained in:
parent
174c6414ac
commit
71cb256527
46 changed files with 848 additions and 395 deletions
|
|
@ -21,5 +21,5 @@ Understanding-oriented content explaining the "why" behind BlumeOps design decis
|
|||
| Article | Description |
|
||||
|---------|-------------|
|
||||
| [[architecture]] | How all the pieces fit together |
|
||||
| [[federated-login]] | How SSO works across BlumeOps (Dex + Forgejo) |
|
||||
| [[federated-login]] | How SSO works across BlumeOps (Authentik) |
|
||||
| [[security-model]] | Network security, secrets, and access control |
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
title: Federated Login
|
||||
modified: 2026-02-19
|
||||
last-reviewed: 2026-02-19
|
||||
modified: 2026-02-20
|
||||
last-reviewed: 2026-02-20
|
||||
tags:
|
||||
- explanation
|
||||
- security
|
||||
|
|
@ -23,65 +23,53 @@ Without centralized authentication, every service manages its own users independ
|
|||
- **No single sign-on** — logging into Grafana doesn't help you access ArgoCD
|
||||
- **Inconsistent security** — some services have auth, some don't, and there's no central audit trail
|
||||
|
||||
## The Solution: Dex + Forgejo
|
||||
## The Solution: Authentik
|
||||
|
||||
BlumeOps uses a two-layer federated authentication model:
|
||||
BlumeOps uses [[authentik]] as the central OIDC identity provider. Authentik is the **source of truth** for user identity — users are created and managed in Authentik, and services authenticate against it via OpenID Connect.
|
||||
|
||||
1. **[[dex]]** is the OIDC identity provider (IdP). Services like [[grafana]] delegate their login flow to Dex using the OpenID Connect protocol. Dex issues standardized tokens that carry user identity.
|
||||
|
||||
2. **[[forgejo]]** is the upstream identity source. Dex doesn't store users itself — it delegates authentication to Forgejo via OAuth2. Users log in with their Forgejo credentials.
|
||||
|
||||
This separation is intentional. Dex handles the OIDC protocol (token issuance, discovery endpoints, client registration), while Forgejo handles user management (accounts, passwords, 2FA). Each does what it's good at.
|
||||
This is a deliberate choice: Authentik provides a full-featured identity management UI, Blueprint-driven GitOps configuration, and support for multiple authentication protocols. Services like [[grafana]] delegate their login flow to Authentik using OIDC, and Authentik issues standardized tokens that carry user identity.
|
||||
|
||||
## The Login Flow
|
||||
|
||||
When a user clicks "Sign in with Dex" on Grafana:
|
||||
When a user clicks "Sign in with Authentik" on Grafana:
|
||||
|
||||
```
|
||||
1. Grafana redirects browser to Dex (dex.ops.eblu.me/auth)
|
||||
2. Dex redirects browser to Forgejo (forge.ops.eblu.me/login/oauth/authorize)
|
||||
3. User logs in at Forgejo (or is already logged in)
|
||||
4. Forgejo redirects back to Dex (dex.ops.eblu.me/callback)
|
||||
5. Dex issues an OIDC token
|
||||
6. Dex redirects back to Grafana (grafana.ops.eblu.me/login/generic_oauth)
|
||||
7. Grafana accepts the token, user is logged in
|
||||
1. Grafana redirects browser to Authentik (authentik.ops.eblu.me/application/o/authorize/)
|
||||
2. User logs in at Authentik (or is already logged in)
|
||||
3. Authentik issues an OIDC token
|
||||
4. Authentik redirects back to Grafana (grafana.ops.eblu.me/login/generic_oauth)
|
||||
5. Grafana accepts the token, user is logged in
|
||||
```
|
||||
|
||||
After step 3, if the user is already logged into Forgejo, the remaining steps happen instantly — it feels like a single click.
|
||||
|
||||
## Why Not Just Use Forgejo Directly?
|
||||
|
||||
Forgejo supports OAuth2 provider mode, so services could authenticate against it directly. Dex adds a layer of indirection, which provides:
|
||||
|
||||
- **Protocol translation** — Dex speaks OIDC (a standardized protocol) to downstream services. Not all services speak the same OAuth2 dialect that Forgejo does, but most speak OIDC.
|
||||
- **Connector flexibility** — Dex can federate to multiple identity sources simultaneously. If a Google or GitHub connector is added later, downstream services don't change at all — they still talk to Dex.
|
||||
- **Separation of concerns** — Forgejo is a git forge first. Its OAuth2 provider is a secondary feature. Dex is purpose-built for identity federation and handles edge cases (token refresh, JWKS rotation, discovery) more robustly.
|
||||
|
||||
For a single-user homelab, the indirection is admittedly overkill today. But it keeps the architecture clean for future growth — adding a second identity source or a new downstream service is a config change, not an architecture change.
|
||||
If the user is already logged into Authentik, the flow happens instantly — it feels like a single click.
|
||||
|
||||
## Break-Glass Access
|
||||
|
||||
Every service that uses Dex SSO also keeps a local admin login. If Dex goes down (or ringtail is offline), recovery works through:
|
||||
Every service that uses Authentik SSO also keeps a local admin login. If Authentik goes down (or ringtail is offline), recovery works through:
|
||||
|
||||
1. SSH to indri
|
||||
2. Log into ArgoCD with local admin password (from 1Password)
|
||||
3. Fix whatever is broken
|
||||
|
||||
Dex is additive — it's a convenience layer, not a hard dependency. Services never lose their local auth capability.
|
||||
Authentik is additive — it's a convenience layer, not a hard dependency. Services never lose their local auth capability.
|
||||
|
||||
## Cross-Cluster Communication
|
||||
|
||||
Dex runs on [[ringtail]]'s k3s cluster while most services run on indri's minikube. This is deliberate — the IdP is independent of the main services cluster. Communication happens via the Tailscale network:
|
||||
Authentik runs on [[ringtail]]'s k3s cluster while most services run on indri's minikube. This is deliberate — the IdP is independent of the main services cluster. Communication happens via the Tailscale network:
|
||||
|
||||
- Grafana (minikube) → `dex.ops.eblu.me` → Caddy (indri) → Tailscale → Dex (ringtail k3s)
|
||||
- Browser redirects go through `dex.ops.eblu.me` and `forge.ops.eblu.me`, both resolved via Caddy
|
||||
- Grafana (minikube) → `authentik.ops.eblu.me` → Caddy (indri) → Tailscale → Authentik (ringtail k3s)
|
||||
- Browser redirects go through `authentik.ops.eblu.me`, resolved via Caddy
|
||||
|
||||
No k8s-internal DNS crosses cluster boundaries. Everything uses the `*.ops.eblu.me` domain.
|
||||
|
||||
## Future Work
|
||||
|
||||
- **Forgejo OIDC:** Make Forgejo an OIDC client of Authentik (deferred — existing `eblume` account needs careful migration)
|
||||
- **Additional services:** ArgoCD, Miniflux, Immich, Zot (see [[harden-zot-registry]])
|
||||
|
||||
## Related
|
||||
|
||||
- [[dex]] - OIDC identity provider reference
|
||||
- [[forgejo]] - Upstream OAuth2 provider
|
||||
- [[authentik]] - OIDC identity provider reference
|
||||
- [[grafana]] - First OIDC client
|
||||
- [[security-model]] - Network security and access control
|
||||
- [[adopt-oidc-provider]] - Implementation plan (completed)
|
||||
- [[deploy-authentik]] - Deployment how-to
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue