Authentik¶
Single sign-on and identity provider for the rest of the stack. Services either wire native OIDC/SAML to it, or sit behind its Traefik forward-auth middleware.
| Runtime | Container (Docker Swarm), 4 containers: server, worker, postgresql, redis |
| Tier | Core |
| Node | swarm-core |
| Image | ghcr.io/goauthentik/server:2026.5.5 (server and worker share this image) |
| URL | https://authentik.lab.riversfamily.uk |
| Auth | N/A (is the identity provider) |
| Source | ansible/stacks/core/authentik/ |
Configuration¶
Authentik applications and providers are declarative blueprints (YAML),
applied by the worker on startup from /blueprints/custom, not clicked
together in the UI. 13 blueprint templates live under
ansible/stacks/core/authentik/blueprints/ and are rendered as
stack_extra_templates by deploy-stacks.yml — they are not picked up
automatically, so a new OIDC/SAML consumer needs a blueprint entry added to
that playbook. Each entry's dest must keep the .yaml extension:
Authentik's custom-blueprint auto-discovery under /blueprints/custom only
scans for .yaml, and its dir_mode: "0755" must stay world-readable, since
the worker runs as a non-root user and the shared stack role's directory
default (0750, root-only) would otherwise block it from reading the mount.
The blueprints cover: a per-service OIDC provider for each native-OIDC
consumer (vaultwarden, gitea, mealie, netbox, immich, paperless-ngx, matomo,
linkding, openproject), SAML providers for kimai/snipe-it/fleet plus a shared
saml-signing-cert.yaml.j2 (must render before any SAML provider that
references it — order is enforced in deploy-stacks.yml), and
forward-auth.yaml.j2 defining the single forward_domain proxy provider
used by every forward-auth-gated app.
The reusable forward-auth middleware, authentik@swarm, is defined on the
server service itself:
traefik.http.middlewares.authentik.forwardauth.address=http://authentik_server:9000/outpost.goauthentik.io/auth/traefik
Volumes¶
| Volume | Path | Backing | Contents |
|---|---|---|---|
media |
/media |
Local | Shared by server and worker |
redis |
/data |
Local | Redis persistence |
database |
/var/lib/postgresql/data |
Local | Postgres data — never NFS |
| (rendered) | /blueprints/custom |
— | The 13 blueprint templates |
Networking¶
server joins both the shared traefik network (for its Traefik route) and
this stack's private internal network. worker, postgresql and redis
join internal only — they are unreachable from every other stack.
Secrets¶
| Vault variable | Delivered as | Purpose |
|---|---|---|
vault_authentik_secret_key |
Swarm secret | Django-style secret key |
vault_authentik_postgres_password |
Swarm secret | Postgres password |
vault_authentik_bootstrap_password |
Swarm secret | Initial akadmin password |
vault_authentik_bootstrap_token |
Swarm secret | Initial API token |
vault_authentik_saml_signing_cert / _key |
Env var, embedded in blueprint | Shared SAML signing certificate used by kimai, snipe-it, fleet |
vault_<service>_oidc_client_secret (9 services) |
Env var per service | Client secret shared with each OIDC consumer's blueprint |
Gotchas¶
- The chicken-and-egg problem (Authentik needs to exist before a service can authenticate against it, but the client secret must match on both sides) is resolved by generating each OIDC/SAML client secret once in Vault and writing it into both the Authentik blueprint and the consuming service's config — the secret is set on both sides, never read back from Authentik after the fact.
- The authoritative reference for whether a given service supports OIDC/SAML, and exactly how to wire it, is the Authentik integrations catalogue. If a service has no guide there, it falls back to forward-auth.
- The
authentik@swarmmiddleware trusts the forwarded headers (trustForwardHeader=true) and setsX-authentik-username,-groups,-email,-name,-uid. Any service consuming those headers directly (see Firefly-III) depends on the middleware to stop header spoofing — it is the only thing standing between a client and impersonating another user.