Deploy Authentik identity provider (C2 Mikado) #227

Merged
eblume merged 23 commits from feature/deploy-authentik into main 2026-02-20 12:56:00 -08:00
Owner

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
## 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
Attempted deployment fails on three independent blockers:
1. Container image doesn't exist (build-authentik-container)
2. PostgreSQL database doesn't exist (provision-authentik-database)
3. 1Password secrets don't exist (create-authentik-secrets)

Created cards for each and added requires to goal card.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lessons learned from first C2 attempt (deploy-authentik):
- When an attempt fails, reset code changes before committing cards
- Cherry-pick doc commits onto clean base if code/docs got mixed
- Open a PR early so the user can review the Mikado graph evolving

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mikado cards are discovered through failed attempts, not designed
upfront — they don't belong in plans/. Cards now live where they
topically belong (how-to/authentik/ for this chain). Updated
agent-change-process to document this convention.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build artifacts (container images, git tags) are independent of branch
lifecycle and don't need to be deferred or reset during Mikado iterations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Authentik container definition (Nix)
All checks were successful
Build Container / build (push) Successful in 3s
Build Container (Nix) / build (push) Successful in 1m57s
ac94cf6c5d
Nix-built container using pkgs.authentik with ak entrypoint.
Includes bashInteractive (ak is a bash wrapper), cacert, tzdata.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Image registry.ops.eblu.me/blumeops/authentik:v1.0.0-nix built
via Nix on ringtail and verified in zot registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add managed role for authentik user on blumeops-pg CNPG cluster,
with ExternalSecret pulling password from 1Password item
"Authentik (blumeops)".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both prerequisites for deploy-authentik are now satisfied:
- CNPG managed role + ExternalSecret for authentik DB user
- 1Password item "Authentik (blumeops)" with all required fields
- Database created and cross-cluster connectivity verified

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server, worker, Redis deployments targeting ringtail k3s cluster.
ExternalSecret pulls config from 1Password "Authentik (blumeops)".
Tailscale Ingress exposes at authentik.tail8d86e.ts.net.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add coreutils to authentik container
All checks were successful
Build Container / build (push) Successful in 2s
Build Container (Nix) / build (push) Successful in 1m9s
41ee4161a9
The ak wrapper script requires mkdir (and likely other coreutils)
to create runtime directories.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mikado chain complete: all three prerequisites resolved, Authentik
server/worker/Redis healthy on k3s, accessible at authentik.ops.eblu.me.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Authentik is deployed but no services use it yet. New leaf node
to migrate Grafana's OIDC from Dex to Authentik, then decommission Dex.
Goal card re-activated with new dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Authentik Blueprint (ConfigMap) defining Grafana OAuth2 provider,
  application, admins group, and policy binding
- Mount blueprint in worker, pass grafana client secret via env
- Switch Grafana auth.generic_oauth from Dex to Authentik endpoints
- Replace dex-oauth ExternalSecret with authentik-oauth

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Nix-built authentik hardcodes blueprints_dir to the Nix store path.
Custom blueprints at /blueprints/custom/ are not discovered.
Need to override AUTHENTIK_BLUEPRINTS_DIR or patch the container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix blueprint loading: create /blueprints symlink dir in container
All checks were successful
Build Container / build (push) Successful in 2s
Build Container (Nix) / build (push) Successful in 1m9s
b99c655c47
The nixpkgs authentik-django package hardcodes blueprints_dir to its
Nix store path, making custom blueprints mounted at /blueprints/custom
invisible to the discovery system. Add extraCommands to create a
/blueprints directory with symlinks to the built-in blueprint dirs,
and set AUTHENTIK_BLUEPRINTS_DIR=/blueprints so authentik scans the
unified directory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix blueprint symlinks: use runtime entrypoint wrapper
All checks were successful
Build Container / build (push) Successful in 3s
Build Container (Nix) / build (push) Successful in 1m8s
3e3fe0b2eb
extraCommands in buildLayeredImage can't access store paths from
contents (they're in separate layers), so the glob matched nothing.
Instead, create a wrapper entrypoint that symlinks built-in blueprint
dirs from the Nix store into /blueprints at container start. The
directory is created world-writable so user 65534 can create links.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
!Env expects a bare string (e.g. !Env FOO), not a YAML sequence
(!Env [FOO]). The list form caused IndexError during blueprint
discovery.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Delete dex manifests, ArgoCD app, container build, and reference doc
- Remove dex from Caddy reverse proxy config
- Create authentik.md reference doc
- Rewrite federated-login.md for Authentik architecture
- Update grafana, forgejo, ringtail, harden-zot-registry docs
- Update services-check: replace dex health/pod checks with authentik
- Fix all broken [[dex]] wiki-links

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
eblume merged commit 71cb256527 into main 2026-02-20 12:56:00 -08:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
eblume/blumeops!227
No description provided.