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:
Erich Blume 2026-02-20 12:55:59 -08:00
commit 71cb256527
46 changed files with 848 additions and 395 deletions

View file

@ -0,0 +1,54 @@
# Nix-built Authentik identity provider
# Uses nixpkgs authentik package (ak entrypoint wrapping Go server + Python worker)
# Built with dockerTools.buildLayeredImage for efficient layer caching
{ pkgs ? import <nixpkgs> { } }:
let
# Wrapper entrypoint that sets up /blueprints symlinks before running ak.
# buildLayeredImage's extraCommands can't access store paths from contents (they're
# in separate layers), so we create the symlinks at container start instead.
entrypoint = pkgs.writeShellScript "authentik-entrypoint" ''
# Link built-in blueprint dirs from the Nix store into /blueprints
for item in /nix/store/*authentik-django*/blueprints/*/; do
name=$(basename "$item")
[ ! -e "/blueprints/$name" ] && ln -s "$item" "/blueprints/$name" 2>/dev/null || true
done
exec ${pkgs.authentik}/bin/ak "$@"
'';
in
pkgs.dockerTools.buildLayeredImage {
name = "blumeops/authentik";
tag = "latest";
contents = [
pkgs.authentik
pkgs.bashInteractive
pkgs.coreutils
pkgs.cacert
pkgs.tzdata
];
# Create /blueprints as world-writable so user 65534 can create symlinks at runtime.
# The nixpkgs authentik-django package hardcodes blueprints_dir to its Nix store path,
# making custom blueprints mounted at /blueprints/custom invisible. The entrypoint
# wrapper populates this directory with symlinks to built-in blueprints on each start.
extraCommands = ''
mkdir -p blueprints
chmod 777 blueprints
'';
config = {
Entrypoint = [ "${entrypoint}" ];
Env = [
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
"TZDIR=${pkgs.tzdata}/share/zoneinfo"
"AUTHENTIK_BLUEPRINTS_DIR=/blueprints"
];
ExposedPorts = {
"9000/tcp" = { };
"9443/tcp" = { };
};
User = "65534";
};
}