Files
home-network-k3s-impl/platform/oauth2-proxy/helmrelease.yaml
T
jakman85andClaude Opus 4.8 3e7e9386a0 feat(oauth2-proxy): forward-auth ext_authz enforcement mechanism + group floor
Build the deferred forward-auth ENFORCEMENT for non-OIDC UIs (pihole/*arr/
qbittorrent/homepage; Crafty next), gated by Keycloak via oauth2-proxy.

- helmrelease: add `--allowed-groups=platform-admins` (R-IDP-06 floor:
  authenticated AND in group) + `--skip-provider-button` (302 straight to
  Keycloak; verified the interstitial 403 sign-in page otherwise).
- forward-auth-cec.yaml: interim self-authored CiliumClusterwideEnvoyConfig
  ext_authz listener -> oauth2-proxy /oauth2/auth, failure_mode_allow:false,
  per-route opt-in via virtualHost. TEMPLATE — not Flux-wired (PM deploys with
  an L2 VIP + DNS repoint). The ext_authz stanza is verified in-cluster.
- README: document the mechanism, why per-route ext_authz on the shared Gateway
  is NOT clean on Cilium 1.16.5 (machine-owned cilium-gateway-shared CEC; native
  ExternalAuth/GEP-1494 in no released Cilium), the three options + recommendation,
  the opt-in steps, the in-cluster proof, and the human browser test.

Keycloak `oauth2-proxy` client already carries the callback redirect URI + a
bare `groups` claim (full.path=false) — no realm change needed.

Proof (cilium-envoy v1.30.8): a standalone envoy running this exact ext_authz
stanza against the live oauth2-proxy denied unauthenticated requests (403,
oauth2-proxy sign-in body; upstream never served), while a no-filter control
route on the same backend returned 200. R-IDP-02 property holds.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-08-28 15:18:47 -05:00

75 lines
4.2 KiB
YAML

---
# oauth2-proxy — forward-auth for apps WITHOUT usable OIDC (PiHole, *arr UIs, qBittorrent, Homepage,
# Prometheus, Alertmanager, Hubble UI — ADR-0014). Authenticates users against the Keycloak `homelab`
# realm, then the Gateway ext-auth lets the request through only for an authenticated session
# (R-IDP-02: no management UI unauthenticated). Chart image is quay.io/oauth2-proxy (not Bitnami).
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: oauth2-proxy
namespace: oauth2-proxy
spec:
interval: 30m
chart:
spec:
chart: oauth2-proxy
version: ">=7.0.0 <8.0.0" # TODO(WS-SEC): pin at bring-up; Renovate maintains
sourceRef:
kind: HelmRepository
name: oauth2-proxy
namespace: oauth2-proxy
install:
remediation:
retries: 3
upgrade:
remediation:
retries: 3
values:
replicaCount: ${OAUTH2_PROXY_REPLICAS} # overlay knob: dev 1 / prod 2 (HA) — R-ENV-02
config:
# client-id / client-secret / cookie-secret from the SOPS secret (name only). client-id +
# client-secret MUST match the realm's `oauth2-proxy` client (keycloak-realm-clients secret).
existingSecret: oauth2-proxy-credentials
extraArgs:
provider: oidc
oidc-issuer-url: https://keycloak.home.keithjackson.dev/realms/homelab
# Forward-auth (ext-auth) mode: no upstream app; return 202 for an authenticated session so the
# Gateway ext-authz can allow/deny. Auth headers are surfaced to the backend.
reverse-proxy: "true"
upstream: static://202
set-xauthrequest: "true"
pass-access-token: "true"
email-domain: "*"
# Single sign-in/callback host for all forward-auth-protected services on the platform zone.
redirect-url: https://auth.home.keithjackson.dev/oauth2/callback
whitelist-domain: ".home.keithjackson.dev"
cookie-domain: ".home.keithjackson.dev"
cookie-secure: "true"
# Expose group membership so per-service group authorization (R-IDP-06) can be enforced. The
# Keycloak `oauth2-proxy` client emits a `groups` claim (full.path=false => bare names like
# `platform-admins`, keycloak-realm-import.yaml). `--allowed-groups` below is the PLATFORM FLOOR:
# a valid Keycloak session is NOT enough — the user must ALSO be in `platform-admins`, or
# /oauth2/auth returns 403 and ext_authz denies (R-IDP-06). Every currently-onboarded
# forward-auth app (pihole, *arr, qbittorrent, homepage, prometheus, alertmanager, hubble)
# declares `groups: [platform-admins]` in its ServiceDefinition, so this floor matches them all.
# Per-ROUTE group differentiation (a future app allowing a different group) does NOT need a
# second proxy: the ext_authz filter appends `?allowed_groups=<group>` to /oauth2/auth from the
# HTTPRoute's `homelab.keithjackson.dev/auth-groups` annotation — oauth2-proxy honours the
# per-request query on top of this floor. See forward-auth-cec.yaml + README "opt-in".
oidc-groups-claim: groups
allowed-groups: platform-admins # R-IDP-06 floor: authenticated AND in platform-admins
# Single Keycloak provider => skip the oauth2-proxy interstitial "Sign In" button and 302
# straight to Keycloak. Verified in-cluster: WITHOUT this, an ext_authz-denied browser request
# gets oauth2-proxy's HTML sign-in page (HTTP 403) instead of an immediate redirect (docs/15 UX).
skip-provider-button: "true"
scope: "openid email profile"
# Metrics for the ServiceMonitor (../oauth2-proxy servicemonitor in platform-config).
metrics:
enabled: true
# ENFORCEMENT (Phase 6): oauth2-proxy is the AUTHENTICATOR; the per-route ext_authz ENFORCEMENT is
# Gateway-side. On Cilium 1.16.5 the shared Gateway's Envoy config is a machine-owned, constantly
# regenerated CiliumEnvoyConfig (`gateway/cilium-gateway-shared`) that CANNOT be injected into,
# and native Gateway-API ExternalAuth (GEP-1494) ships in NO released Cilium version yet. The
# enforcement mechanism + the three wiring options are documented in README.md; the interim
# self-authored ext_authz listener is forward-auth-cec.yaml (a template, not yet Flux-wired).