New identity subsystem, and resolves the C2 auth open question: - docs/15-identity-and-access.md + ADR-0014: Keycloak as central IdP; native OIDC where supported (Gitea, Nextcloud, Grafana, Kasm, Semaphore, Headlamp) and oauth2-proxy forward-auth for bare UIs (PiHole, *arr, qBittorrent, Homepage, Prometheus, Alertmanager, Hubble). Group-based authz + MFA; declarative realm/clients (GitOps); PostgreSQL on Longhorn, DR-critical + break-glass; hardened public exposure. Plex/Seerr use Plex auth; Minecraft N/A. - Requirements R-IDP-01..06; ServiceDefinition gains an block. - Onboarded early (with Gitea) so services adopt SSO as they come up. - Threaded through: docs 00,01,07,10,12,13; roadmap phases+workstreams; task board (T-6.1c/T-6.1d); glossary; ADR index; README. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2.7 KiB
2.7 KiB
ADR-0014 — Identity Provider: Keycloak (SSO via OIDC + forward-auth)
- Status: Accepted
- Date: 2026-08-15
- Serves: R-IDP-01, R-IDP-02, R-IDP-03, R-IDP-04, R-IDP-05, R-IDP-06
- Supersedes: —
Context
The platform needs one identity and single sign-on: a central user directory, group-based authorization, MFA, and a way to protect both OIDC-capable apps and bare management UIs — without per-app passwords scattered across services. This also resolves the previously-open C2 auth question (12).
Decision
Use Keycloak as the platform IdP, integrated two ways behind one identity:
- Native OIDC for apps that support it (Gitea, Nextcloud, Grafana, Kasm, Semaphore, Headlamp).
- Forward-auth proxy (oauth2-proxy → Keycloak) at the Gateway for apps without usable OIDC (PiHole, *arr UIs, qBittorrent, Homepage, Prometheus, Alertmanager, Hubble UI).
Supporting decisions:
- Config as code: realms/clients/groups are declarative and GitOps-reconciled (Keycloak Operator/
Helm for the instance;
keycloak-config-clior realm-import for config). Secrets SOPS-encrypted. - Authorization by groups; MFA required for privileged groups.
- PostgreSQL on Longhorn, DR-critical, backed up off-cluster; Keycloak rebuilds from DB + git.
publicexposure (hardened) so login flows work for internet-exposed services.- Exceptions: Plex/Seerr use Plex auth; Minecraft uses Mojang/Microsoft; UniFi keeps native auth.
Alternatives considered
- Authelia / Authentik — lighter, and Authelia pairs cleanly with forward-auth; but Keycloak is the operator's explicit choice and offers the broadest OIDC/SAML, realm, and federation feature set for heterogeneous apps. (Chosen.)
- Per-app local auth only — rejected: no SSO, password sprawl, weak central policy/MFA (fails R-IDP-01/06).
- Cloud IdP (e.g. hosted OIDC) — rejected: this is a self-hosted, offline-capable home platform; identity should not depend on an external SaaS.
Consequences
- One login, one directory, central MFA and group policy; management UIs are never unauthenticated on the network (R-IDP-02).
- Keycloak becomes a critical dependency: an IdP outage impairs SSO logins → DR-critical storage
- a documented break-glass local-admin path (e.g. on Gitea) so recovery tools stay reachable.
- New platform components to run and secure: Keycloak, PostgreSQL, oauth2-proxy — all under default-deny with explicit allows and trusted TLS.
- Onboarded early (with PiHole/Gitea) so later services integrate SSO as they come up.
- Adds an
authblock to the ServiceDefinition (13) so SSO mode + allowed groups are declarative per service.