Files
home-network-k3s/decisions/adr-0014-idp-keycloak.md
T
jakman85andClaude Opus 4.8 fb153f0bb5 Add Keycloak IdP / SSO (ADR-0014, docs/15, R-IDP-*)
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]>
2026-08-15 23:33:49 -05:00

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-cli or 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.
  • public exposure (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 auth block to the ServiceDefinition (13) so SSO mode + allowed groups are declarative per service.