From ab348932ff8ccffdc80d2fb2a47e1873aa6778ac Mon Sep 17 00:00:00 2001 From: Fizzlepoof Date: Sat, 23 May 2026 19:37:28 +0000 Subject: [PATCH] Add staged Authentik stack and Grafana OIDC wiring --- identity-authentik/.env.example | 6 ++ identity-authentik/README.md | 64 ++++++++++++++++++ identity-authentik/custom-templates/.gitkeep | 0 identity-authentik/docker-compose.yaml | 70 ++++++++++++++++++++ monitoring/.env.example | 5 +- monitoring/docker-compose.yaml | 7 +- 6 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 identity-authentik/.env.example create mode 100644 identity-authentik/README.md create mode 100644 identity-authentik/custom-templates/.gitkeep create mode 100644 identity-authentik/docker-compose.yaml diff --git a/identity-authentik/.env.example b/identity-authentik/.env.example new file mode 100644 index 0000000..72c7c1c --- /dev/null +++ b/identity-authentik/.env.example @@ -0,0 +1,6 @@ +AUTHENTIK_POSTGRES_DB=authentik +AUTHENTIK_POSTGRES_USER=authentik +AUTHENTIK_POSTGRES_PASSWORD=CHANGE_ME +AUTHENTIK_SECRET_KEY=CHANGE_ME +AUTHENTIK_BOOTSTRAP_PASSWORD=CHANGE_ME +AUTHENTIK_BOOTSTRAP_TOKEN=CHANGE_ME diff --git a/identity-authentik/README.md b/identity-authentik/README.md new file mode 100644 index 0000000..88b3aee --- /dev/null +++ b/identity-authentik/README.md @@ -0,0 +1,64 @@ +# Identity / SSO - Authentik + +This stack stages an Authentik migration in parallel with the current Authelia deployment so cutover can happen app-by-app with easy rollback. + +Current design choices: + +- Authentik server + worker only +- shared Postgres for durable storage +- embedded outpost for Traefik forward-auth +- no Redis dependency +- no Docker socket mount +- keep Authelia alive until all apps validate cleanly + +Why this shape: + +- it future-proofs the identity plane without turning migration into a flag day +- it preserves easy rollback while Authentik is proven per app +- it matches the homelab preference for shared database infra over one-off local state +- embedded outpost is enough for this size and avoids extra moving parts + +Files: + +- docker-compose.yaml +- .env.example +- custom-templates/.gitkeep + +Bootstrap: + +1. Copy this directory to PD at /mnt/docker-ssd/docker/compose/identity-authentik +2. Copy .env.example to .env and replace every CHANGE_ME +3. Create the Authentik database/user in shared Postgres +4. Validate and start: + + cd /mnt/docker-ssd/docker/compose/identity-authentik + docker compose --env-file .env config + docker compose --env-file .env up -d + +5. Verify readiness: + + docker compose ps + docker logs authentik-server --tail=50 + curl -fsS http://127.0.0.1:9000/-/health/ready/ + +6. Complete initial login with the bootstrap admin on the internal URL first, then wire the public auth route. +7. Build providers before cutover: + + - Grafana: OAuth2/OIDC provider + - Gitea: proxy provider, forward auth, single application + - Technitium: proxy provider, forward auth, single application + - Traefik dashboard: proxy provider, forward auth, single application + +8. Bind those proxy providers to the embedded outpost. +9. Cut apps over one at a time from Authelia forward-auth to Authentik forward-auth. +10. Only remove Authelia after every migrated app and logout flow is verified. + +Notes: + +- Authentik listens internally on port 9000 for HTTP and serves the embedded outpost paths there too. +- The Traefik middleware should call: + http://authentik-server:9000/outpost.goauthentik.io/auth/traefik +- Each forward-auth protected app also needs a higher-priority router for: + PathPrefix(`/outpost.goauthentik.io/`) + routed to Authentik, or the login flow will break. +- Grafana should end on native OIDC instead of remaining behind forward-auth long-term. diff --git a/identity-authentik/custom-templates/.gitkeep b/identity-authentik/custom-templates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/identity-authentik/docker-compose.yaml b/identity-authentik/docker-compose.yaml new file mode 100644 index 0000000..24223f9 --- /dev/null +++ b/identity-authentik/docker-compose.yaml @@ -0,0 +1,70 @@ +name: identity-authentik + +services: + authentik-server: + image: ghcr.io/goauthentik/server:2026.5.0 + container_name: authentik-server + command: server + restart: unless-stopped + ports: + - "9000:9000" + environment: + AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} + AUTHENTIK_ERROR_REPORTING__ENABLED: "false" + AUTHENTIK_POSTGRESQL__HOST: shared-postgres + AUTHENTIK_POSTGRESQL__PORT: 5432 + AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB} + AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER} + AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD} + AUTHENTIK_POSTGRESQL__SSLMODE: disable + AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD} + AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN} + volumes: + - /mnt/tank/docker/appdata/authentik:/data + - /mnt/docker-ssd/docker/compose/identity-authentik/custom-templates:/templates + healthcheck: + test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:9000/-/health/ready/ >/dev/null || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 45s + shm_size: 512mb + networks: + - ix-databases_shared-databases + - pangolin + + authentik-worker: + image: ghcr.io/goauthentik/server:2026.5.0 + container_name: authentik-worker + command: worker + restart: unless-stopped + environment: + AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY} + AUTHENTIK_ERROR_REPORTING__ENABLED: "false" + AUTHENTIK_POSTGRESQL__HOST: shared-postgres + AUTHENTIK_POSTGRESQL__PORT: 5432 + AUTHENTIK_POSTGRESQL__NAME: ${AUTHENTIK_POSTGRES_DB} + AUTHENTIK_POSTGRESQL__USER: ${AUTHENTIK_POSTGRES_USER} + AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_POSTGRES_PASSWORD} + AUTHENTIK_POSTGRESQL__SSLMODE: disable + AUTHENTIK_BOOTSTRAP_PASSWORD: ${AUTHENTIK_BOOTSTRAP_PASSWORD} + AUTHENTIK_BOOTSTRAP_TOKEN: ${AUTHENTIK_BOOTSTRAP_TOKEN} + volumes: + - /mnt/tank/docker/appdata/authentik:/data + - /mnt/docker-ssd/docker/compose/identity-authentik/custom-templates:/templates + healthcheck: + test: ["CMD-SHELL", "ak healthcheck >/dev/null 2>&1 || exit 1"] + interval: 30s + timeout: 30s + retries: 5 + start_period: 60s + shm_size: 512mb + networks: + - ix-databases_shared-databases + - pangolin + +networks: + ix-databases_shared-databases: + external: true + pangolin: + external: true diff --git a/monitoring/.env.example b/monitoring/.env.example index bb044b1..e25e454 100644 --- a/monitoring/.env.example +++ b/monitoring/.env.example @@ -5,9 +5,10 @@ GF_ADMIN_USER=admin GF_ADMIN_PASS=CHANGE_ME GF_HOST=grafana.paccoco.com LOKI_HOST=loki.paccoco.com -AUTHELIA_HOST=auth.paccoco.com +AUTHENTIK_HOST=auth.paccoco.com +GF_AUTHENTIK_APP_SLUG=grafana GF_AUTH_GENERIC_OAUTH_ENABLED=true -GF_AUTH_GENERIC_OAUTH_NAME=Authelia +GF_AUTH_GENERIC_OAUTH_NAME=Authentik GF_AUTH_GENERIC_OAUTH_ICON=signin GF_AUTH_GENERIC_OAUTH_CLIENT_ID=grafana GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=CHANGE_ME diff --git a/monitoring/docker-compose.yaml b/monitoring/docker-compose.yaml index 00841a4..fa56c3b 100644 --- a/monitoring/docker-compose.yaml +++ b/monitoring/docker-compose.yaml @@ -49,9 +49,10 @@ services: GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: ${GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET} GF_AUTH_GENERIC_OAUTH_SCOPES: ${GF_AUTH_GENERIC_OAUTH_SCOPES} GF_AUTH_GENERIC_OAUTH_EMPTY_SCOPES: ${GF_AUTH_GENERIC_OAUTH_EMPTY_SCOPES} - GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://${AUTHELIA_HOST}/api/oidc/authorization - GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://${AUTHELIA_HOST}/api/oidc/token - GF_AUTH_GENERIC_OAUTH_API_URL: https://${AUTHELIA_HOST}/api/oidc/userinfo + GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://${AUTHENTIK_HOST}/application/o/authorize/ + GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://${AUTHENTIK_HOST}/application/o/token/ + GF_AUTH_GENERIC_OAUTH_API_URL: https://${AUTHENTIK_HOST}/application/o/userinfo/ + GF_AUTH_SIGNOUT_REDIRECT_URL: https://${AUTHENTIK_HOST}/application/o/${GF_AUTHENTIK_APP_SLUG}/end-session/ GF_AUTH_GENERIC_OAUTH_USE_PKCE: ${GF_AUTH_GENERIC_OAUTH_USE_PKCE} GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: ${GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP} GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN: ${GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN}