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]>
This commit is contained in:
jakman85andClaude Opus 4.8 committed 2026-08-15 23:33:49 -05:00
1 parent 1e0e67f902
commit fb153f0bb5
14 files changed
+243 -14

No files matched your search

+1
View File
@@ -55,3 +55,4 @@ serves. **Do not edit an accepted decision in place** — supersede it with a ne
| [0011](adr-0011-test-tooling-kyverno-chainsaw.md) | Conformance test tooling: Kyverno + Chainsaw | Accepted | R-TEST-01..05 |
| [0012](adr-0012-vpn-egress-single-expressvpn-gateway.md) | VPN egress: single shared in-cluster ExpressVPN gateway | ~~Superseded by 0013~~ | R-NET-05/06/07 |
| [0013](adr-0013-vpn-provider-pia-gluetun-wireguard.md) | VPN provider: PIA via Gluetun (WireGuard + port forwarding) | Accepted | R-NET-05/06/07 |
| [0014](adr-0014-idp-keycloak.md) | Identity Provider: Keycloak (SSO via OIDC + forward-auth) | Accepted | R-IDP-01..06 |
+45
View File
@@ -0,0 +1,45 @@
# 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](../docs/12-command-center-ui.md)).
## 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](../docs/13-service-catalog.md)) so SSO mode +
allowed groups are declarative per service.