Files
HiveGrid-Wireframes/hivegrid-cloud/docs/improvement-plan/09-authentik-admin-sso/VERIFICATION.md
T

20 KiB

Verification — Phase 09 (Authentik + Admin-SSO)

Verifier: general-purpose subagent (read-only review) Datum: 2026-05-16 Files geprüft: README.md, authentik-setup.md (#81), admin-oidc-login.md (#82) Referenz: ../DETAIL-MD-TEMPLATE.md, ../AGENT-INSTRUCTIONS.md, ../00-execution-order.md


TL;DR

Phase 09 ist inhaltlich exzellent vorbereitet — eine der vollständigsten Phasen im gesamten Improvement-Plan. Beide Detail-MDs decken Crypto-Pflichten (State/PKCE/Nonce/JWKS), JIT-Provisioning, Fallback-Strategie, Disaster-Recovery, Audit-Wiring und Defense-in-Depth-MFA sauber ab. Die Infra-Sizing-Annahmen sind realistisch, Coolify/Traefik-Integration ist konkret, und der Backlog-Hook für #66 (Tenant-SSO) ist explizit über den deaktivierten zweiten Provider verdrahtet.

Findings: 3 Major (Process/Convention), 6 Minor (Konsistenz/Klarheit), 4 Nice-to-have (Empfehlungen). Empfehlung: Mit Minor-Fixes ready für Execution. Major #1 (CLAUDE.md-Routes-Konvention) sollte vor Start adressiert werden.


1. Template-Konformität (Section-Reihenfolge)

Template-Pflichtreihenfolge laut DETAIL-MD-TEMPLATE.md: Frontmatter → Problem → Depends on → Blocks → Approach → Implementation Steps → Test Requirements → Acceptance Criteria → Rollback Strategy → Security Notes → Subagent Recommendations → Staging-Deployment-Steps → Deviations from Plan → Progress Log → Lessons Learned

Datei Sections vollständig Reihenfolge korrekt Frontmatter komplett
authentik-setup.md Ja (alle 15) Ja Ja (Status/Task-ID/Phase/Effort/Owner)
admin-oidc-login.md Ja (alle 15) Ja Ja

README.md ist keine Detail-MD und folgt einer eigenen Phase-Übersichts-Struktur (Phase-Done-Definition, Dependency-Graph, Phase-Summary-Slot) — passt zum Stil der anderen Phase-READMEs und ist gut.

Ergebnis: Konform.


2. Dependency-Konsistenz

2.1 Interne Reihenfolge

  • authentik-setup.md (#81) deklariert sich als Blocker für admin-oidc-login.md (#82) — korrekt
  • admin-oidc-login.md (#82) führt #81 als Dependency — korrekt
  • 00-execution-order.md listet beide in dieser Reihenfolge ("sequenziell") — konsistent
  • README.md Task-Reihenfolge-Tabelle matched

2.2 Cross-Phase-Dependencies (deklariert vs. tatsächlich)

Deklariert in #81/#82 Cross-Check Status
02-observability/sentry-selfhost-setup.md (#29) 00-execution-order.md Phase-09-Sektion bestätigt OK
02-observability/sentry-wiring-api-worker.md (#30) (in #81 als "best practice") Konsistent OK
01-tech-debt-foundation/dep-updates.md (#28) ("best practice, kein hartes Block") Konsistent OK
01-tech-debt-foundation/totp-consolidation.md (#26) in #82 Korrekt verlinkt OK
11-backlog/customer-tenant-sso.md (#66) als Blocked-By beider Konsistent in README + beiden Detail-MDs OK

2.3 Diskrepanz 00-execution-order.md

00-execution-order.md §"Phase 09 — Authentik + Admin-SSO":

Depends on: Phase 02 (Sentry für Authentik-Container)

Nennt nur Phase 02. Die Detail-MD authentik-setup.md listet zusätzlich dep-updates.md aus Phase 01 (als "best practice, kein hartes Block"), und admin-oidc-login.md listet totp-consolidation.md (#26) aus Phase 01 als hart abhängig. → Inkonsistenz Minor #M1.

00-execution-order.md sollte zusätzlich Phase 01 (mind. #26) als Hard-Dependency für Phase 09 nennen, sonst kann ein Agent #82 starten ohne dass #26 fertig ist.


3. Implementation-Steps — Qualitäts-Review

3.1 Authentik docker-compose (4 Container, 2 GB RAM Minimum)

  • 4 Container (server/worker/postgres/redis) — entspricht dem offiziellen Authentik-Compose. Korrekt.
  • Sizing-Annahme 2 GB RAM hartes Minimum, 4 GB empfohlen — realistisch. Authentik-Docs nennen für Production tatsächlich ~2 GB Floor; Worker + Server zusammen sind die größten Verbraucher. Healthchecks (/-/health/live/, ak healthcheck, pg_isready, redis-cli ping) sauber spezifiziert.
  • mem_limit: 2g pro Container ist im Override-Compose erwähnt — klar.
  • Lücke Minor #M2: Es fehlt eine Notiz zu Hetzner-Server-Mindestgröße. Bei Co-Location mit der App + Sentry + Authentik auf einem CX31 (8 GB) wird's eng. Im README wird "separater gehärteter Server für Production" empfohlen, aber für Staging fehlt ein expliziter Mindest-vCPU/RAM-Hinweis.

3.2 Traefik/TLS auf auth.<domain>

  • Step 4 dokumentiert Traefik-Labels (Host-Rule, websecure-Entrypoint, letsencrypt-Cert-Resolver, HSTS, X-Frame-Options=DENY, Referrer-Policy)
  • CSP-Header explizit über Traefik-Middleware (nicht im Container) — gute Entscheidung wegen Authentik-Eigen-CSP-Konflikt-Potenzial
  • Lücke Minor #M3: Wildcard-Cert-Hinweis für auth.*-Subdomain ist nur in "Lessons Learned" als typische Stolperfalle erwähnt. Sollte in Implementation-Step 4 explizit dokumentiert sein (DNS-Challenge vs. HTTP-Challenge bei Subdomain-Setup).

3.3 Bootstrap-Script + Blueprints

  • 7 Blueprints (00-flows, 10-groups, 20-policies, 30-providers, 40-applications, 50-outposts, 60-tenants, 70-brute-force, 80-notifications)
  • Idempotenz erwähnt, bootstrap.sh wartet auf /-/health/ready/
  • Zwei OIDC-Provider-Definitions im 30-providers-Blueprint: toolctrl-admin-panel (aktiv) + toolctrl-tenant-sso (Platzhalter, enabled: false) — perfekt für #66-Vorbereitung
  • Token-TTLs explizit: access_code=1min, access_token=10min, refresh=7d, id_token=10min — RFC-konform und konservativ
  • Sinnvoll und sauber.

3.4 Authentik-Groups + Mapping zu AdminUser

  • toolctrl-admin (attribute role: super_admin) und toolctrl-staff (attribute role: staff)
  • Mapping in #82 step 7 (mapGroupsToRole): höchste Priorität super_admin, sonst staff, sonst null → 403
  • Re-Sync bei jedem Login (Authentik = Source-of-Truth) — korrekt, dokumentiert in Approach + Tests
  • Sauber.

3.5 MFA-Pflicht für Admin-Group

  • 20-policies.yaml enthält Expression-Policy require-mfa-totp-for-admin
  • Im Flow vor Success-Stage — Security-Notes bestätigt dass das MUSS ist
  • E2E-Test "MFA-Enrollment-Flow durchspielbar" deckt das ab
  • Pflicht durchgesetzt, gut.

3.6 OIDC-Client in apps/web/app/modules/admin-sso/ mit openid-client

  • Library-Wahl mit klarer Begründung (vs. oidc-client-ts/next-auth/eigenbau)
  • Modul-Struktur: client.server.ts, state.server.ts, jit-provisioning.server.ts, claims.server.ts, logout.server.ts, audit.server.ts — klare Separation-of-Concerns
  • Discovery via Issuer.discover(env.AUTHENTIK_ISSUER_URL), JWKS-Auto-Cache durch Library
  • Korrekt.

3.7 Routes /auth/admin/login + /auth/admin/callback

  • PKCE (generators.codeVerifier/codeChallenge), State, Nonce alle drei in createLoginChallenge()
  • Single-use Cookie admin_sso_challenge mit HttpOnly+Secure+SameSite=Lax+Path=/auth/admin+MaxAge=600s — sauber
  • Callback verifiziert State/Nonce/Signature/iss/aud/exp + email_verified (in Security-Notes explizit)
  • Session-Fixation-Schutz (Session-ID-Rotation nach Callback) in Security-Notes — gut, sollte aber in Implementation-Step 6 als konkreter Sub-Step landen → Minor #M4
  • Secure-by-Design.

3.8 JIT-Provisioning

  • 3-Stufen-Lookup (ssoSubjectId → email-Fallback → 403)
  • Transaction-safe + Unique-Constraint-Schutz gegen Race-Conditions
  • Test-Cases dazu in Test-Requirements
  • Sauber.

3.9 Fallback-Login via ADMIN_FALLBACK_LOGIN_ENABLED + Email-Allowlist

  • Env-gegated, Allowlist via ADMIN_FALLBACK_LOGIN_EMAILS
  • assertFallbackLoginAllowed-Server-Guard VOR Passwort-Check
  • AuditEvent severity=warn + Sentry-Breadcrumb
  • Disclosure-Toggle nur wenn Flag true, Default false
  • Brute-Force-Schutz separat erwähnt (Security-Notes)
  • Als Emergency-Path ausreichend gehärtet.
  • Empfehlung NTH #N1: Optional Slack/Discord-Alert ist erwähnt — sollte als konkreter Sub-Step im Doku/Operator-Runbook landen statt nur als "optional hook later".

3.10 Logout-Flow mit RP-Initiated-Logout

  • Step 8: Lokale Session-Kill + client.endSessionUrl({id_token_hint, post_logout_redirect_uri})
  • Fallback wenn id_token fehlt (Fallback-Login-Pfad): nur lokale Session, kein Authentik-Redirect — richtig gedacht
  • Logout-Idempotenz in Security-Notes erwähnt
  • Korrekt.

3.11 App-MFA-Layer NACH OIDC für sensible Actions

  • SENSITIVE_ADMIN_ACTIONS = ['impersonation.start', 'tenant.delete', 'permission.grant', 'audit.export', 'data.export']
  • requireAppMfa(request, actionKey) mit 15-Min Server-Side-Cache (lastAppMfaAt in Session-Store, NICHT Cookie)
  • Nutzt konsolidierte otpauth aus #26 (explizit als Acceptance-Criteria geprüft)
  • Defense-in-Depth-Begründung in Approach klar
  • Tests dazu in Unit + E2E
  • Funktioniert konzeptionell, gut isoliert.

4. Test-Requirements

4.1 OIDC-Flow-Tests via Mock-Authentik

  • msw oder Lokal-Container als Mock erwähnt
  • Konkrete negative-Tests: State-Mismatch, Nonce-Mismatch, Expired-Token, Empty-Group-Claim
  • Vorhanden — gut.
  • Empfehlung NTH #N2: openid-client selbst hat keine Test-Doubles als first-class-feature; msw-Setup für OIDC-Endpoints sollte als wiederverwendbares Fixture in apps/web/tests/fixtures/authentik-mock.ts angelegt werden (auch nützlich für #66 später). Sollte als konkreter Sub-Schritt im Test-Block landen.

4.2 Playwright-E2E des Login-Flows

  • 6 Szenarien: Happy-Path-SSO, JIT-Provisioning, Logout, Fallback-Erfolg, Fallback-Reject, Fallback-Toggle-Hidden, App-MFA-Gate
  • Gegen Staging-Authentik — explizit
  • Komplett.

4.3 Fallback-Recovery-Drill

  • Sowohl in Test Requirements als auch in Staging-Deployment-Steps (#12) als manueller Drill spezifiziert
  • "NICHT als completed markieren bevor … MANUELL einmal end-to-end durchgespielt"
  • Pflicht-Drill korrekt verankert.

4.4 Restore-Drill für Authentik-Postgres

  • infra/authentik/scripts/restore-drill.sh als Test-File spezifiziert
  • 24h-Backup-Verifikation + manueller Restore mit Smoke-Login danach
  • Korrekt.

4.5 Coverage-Target

  • ≥85% Lines/Branches im Modul, 100% auf claims.server.ts + state.server.ts (security-kritisch) — angemessen scharf.

5. Security-Notes — Vollständigkeit

Aspekt Abdeckung
State + Nonce + PKCE Pflicht Ja (Security-Notes + Tests negative-Cases)
JWT-Signature gegen JWKS Ja (Auto via openid-client, mit Library-Upgrade-Hinweis)
email_verified=true prüfen Ja (explizit, mit Begründung Email-Hijack)
Audit jeder Admin-Login/Logout in AuditEvent Ja (Step 12 + Audit-Wiring-Tabelle)
Session-Fixation (ID-Rotation nach Callback) Ja (Security-Notes) — siehe Minor #M4
Code-Verifier nicht loggen Ja (Sentry-Breadcrumb-Filter erwähnt)
Group-Claim als Trust-Anchor Ja (mit Hinweis auf Authentik-Hardening)
Fallback-Bypass-Risiko Ja (kurze Allowlist, warn-Severity, Operator-Pflicht)
App-MFA-Cache nicht im Cookie Ja (explizit Session-Store)
Logout-Idempotenz Ja
Redirect-URI-Whitelist + returnTo-Sanitize Ja
Brute-Force-Schutz auf Fallback-Login Ja
Audit-Event-Inhalt: keine Secrets Ja (id_token NIEMALS persistieren)

AUTHENTIK_SECRET_KEY-Loss-Implications (kann nicht rotiert werden ohne Daten-Verlust) ist in #81-Rollback + Security-Notes explizit — sehr wichtig und korrekt dokumentiert.

Ergebnis: Security-Coverage exzellent.


6. Staging-Deployment-Steps

6.1 Authentik-Coolify-Deploy

  • Sehr detailliert: Service-Anlage, Compose-Path, Domain, Env-Vars aus Vault, Initial-Bootstrap, Smoke-Tests, Backup-Verifikation, Restore-Drill, Brute-Force-Smoke
  • openssl rand-Befehle für Secret-Generierung konkret
  • Vollständig.

6.2 Initial-Admin-Bootstrap

  • AUTHENTIK_BOOTSTRAP_PASSWORD + zwingender Wechsel beim ersten Login
  • Recovery-Key generiert + in Coolify-Vault (NICHT in Git)
  • Sauber.

6.3 Restore-Drill

  • Explizit: Dump in leere Postgres restoren, Authentik gegen Test-DB starten, Smoke-Login
  • restore-drill.sh-Script als Helper
  • Konkret.

6.4 Recovery-Drill für Fallback-Login

  • In admin-oidc-login.md Step 12 (Staging) vollständig durchspielt inklusive Authentik-Stack-Stop, Env-Flag-Toggle, Bootstrap-Login, Authentik-Recovery, Flag-wieder-aus
  • Im Doku-File docs/operations/admin-sso.md als Fallback-Recovery-Procedure dokumentiert
  • Pflicht-Drill korrekt.

7. Konsistenz mit User-Wünschen

User-Wunsch Status
"SSO Authentik" — alles Authentik-basiert Ja, kein Mix mit anderen IdPs
"Self-host" — Docker-Compose vollständig Ja (Compose + Override + Backup + Bootstrap + Blueprints)
Customer-SSO-Backlog baut auf Authentik auf Ja — toolctrl-tenant-sso-Provider als deaktivierter Platzhalter, Modul admin-sso/ als Wiederverwendungs-Foundation explizit als Acceptance #82

Erfüllt.


8. Fehlende Aspekte / Lücken

8.1 Authentik-Update-Strategie

  • Doku-Section "Update-Workflow" ist in #81 Step 11 als Mindest-Section gelistet (Stable-Tag bumpen, Pre-Update-Backup, Release-Notes-Pflicht)
  • Lücke Minor #M5: Es fehlt ein konkreter Update-Cadence-Vorschlag (z.B. "monatlich Stable-Bump prüfen, Security-Patches sofort"). Sollte im Operator-Runbook landen statt nur als Doku-Section-Eintrag.

8.2 Authentik-Sentry-Integration

  • AUTHENTIK_SENTRY__DSN= in .env.example Step 3
  • AUTHENTIK_ERROR_REPORTING__ENABLED=false (kein SaaS-Reporting, gut)
  • Lücke Minor #M6: Es fehlt welcher Sentry-Projekt-Name für Authentik vorgesehen ist. Wenn alles im boilerplate-Projekt landet, gehen Authentik-Errors in den App-Error-Stream — vermutlich nicht gewünscht. Sollte als dediziertes Sentry-Projekt authentik-infra in #29 (sentry-selfhost-setup) verzahnt sein. → Doku-Cross-Link nötig.

8.3 Audit-Webhook von Authentik zu AuditEvent

  • Vorbereitet als 80-notifications.yaml Blueprint mit enabled: false, expliziter Verweis auf #67 (Audit-Log-Task)
  • HMAC-Signing erwähnt, Endpoint https://api.<domain>/webhooks/authentik/audit
  • Gut vorbereitet, aktivierung explizit später — korrekte Scope-Trennung.

8.4 Nicht abgedeckt

  • Authentik LDAP-Outpost / SCIM — explizit out of scope (Step 5 nennt "keine Outposts hochfahren"), das ist okay für Phase 09. Im README sollte aber ein "Out-of-Scope"-Vermerk stehen, damit ein Agent das nicht "freiwillig" mitbaut.
  • Mobile-App-OIDC-Flow — Phase 08 Capacitor (Mobile) hat keine direkte Verzahnung. Falls Customer-Tenant-SSO später Mobile-Support braucht, müsste PKCE+Native-AppAuth-Pattern dazu kommen. Erwähnung in #66-Backlog ausreichend.

9. Findings-Liste (priorisiert)

MAJOR (vor Execution adressieren)

#J1 — CLAUDE.md-Routes-Konvention (Filenames + Route-Tree) admin-oidc-login.md legt Routes mit Dot-Notation an: auth.admin.login.tsx, auth.admin.callback.tsx, auth.admin.logout.tsx. Im Projekt-CLAUDE.md (siehe React-Router-v7-Sektion) wird explizit die explizite routes.ts-Konfiguration über Dot-Notation-File-Convention bevorzugt. Beispiele im CLAUDE.md zeigen routes/categories-layout.tsx + route(":slug", "routes/category-details.tsx") als Pattern.

→ Klären: Soll die Phase die im Projekt etablierte File-Routing-Konvention (.-getrennt) nutzen oder via expliziter routes.ts-Einträge mit kebab-case-Filenames (auth-admin-login.tsx, auth-admin-callback.tsx, auth-admin-logout.tsx)? Empfehlung: kebab-case + explizite routes.ts, da klarer und CLAUDE.md-konform. Die Detail-MD sollte angepasst werden.

Auch betroffen: admin/security.mfa-enroll.tsx, admin/security.mfa-challenge.tsx — gleiche Frage.

#J2 — 00-execution-order.md Phase-01-Dependency fehlt 00-execution-order.md §Phase 09 nennt nur Phase 02 als Hard-Dependency. admin-oidc-login.md deklariert aber totp-consolidation.md (#26) aus Phase 01 als hart abhängig (App-MFA-Layer nutzt konsolidierte otpauth).

→ Fix: 00-execution-order.md updaten: "Depends on: Phase 01 (#26 totp-consolidation für App-MFA-Layer), Phase 02 (Sentry für Authentik-Container)".

#J3 — package.json-Touch in #82 Step 1 ist gefährlich (Workspace-Setup) admin-oidc-login.md Step 1 nennt package.json als touched file für pnpm add openid-client jose. Im Monorepo (apps/web/-Sub-Package) sollte das apps/web/package.json sein, nicht das Root-Manifest. Sollte präzisiert werden, sonst landet die Dep im falschen Workspace.

→ Fix: "Files: apps/web/package.json (Dep: openid-client, jose)".

MINOR (Klarheit / Konsistenz)

#M1 — 00-execution-order.md muss Phase 01 als Hard-Dependency für Phase 09 nennen (s. J2). (Doppelt aufgeführt zur Sichtbarkeit.)

#M2 — Hetzner-Server-Mindest-Sizing für Co-Location (App + Sentry + Authentik) fehlt. README oder #81 Approach sollte CX31/CPX31 als Minimum-Empfehlung nennen.

#M3 — Wildcard-Cert-Hinweis (auth.*-Subdomain, DNS-Challenge) nur in Lessons-Learned. Sollte als expliziter Sub-Step in #81 Step 4 (Traefik) auftauchen.

#M4 — Session-Fixation-Schutz (App-Session-ID-Rotation nach OIDC-Callback) ist in Security-Notes erwähnt, aber NICHT als konkreter Sub-Step in #82 Step 6 (Callback-Route). Implementer wird es ggf. übersehen.

#M5 — Authentik-Update-Cadence (monatlich / Security-Patches sofort) als Operator-Runbook-Eintrag fehlt.

#M6 — Sentry-Projekt-Name für Authentik (authentik-infra vs. App-Projekt) ist nicht spezifiziert. Cross-Link mit #29 (sentry-selfhost-setup) nötig.

NICE-TO-HAVE

#N1 — Slack/Discord-Alert für Fallback-Login als konkreter Operator-Hook (statt "optional later").

#N2 — msw-Authentik-Mock-Fixture als wiederverwendbares File (apps/web/tests/fixtures/authentik-mock.ts) für #82-Tests und spätere #66-Wiederverwendung.

#N3 — Out-of-Scope-Section im README ("keine Outposts, kein LDAP-Sync, kein SAML, keine SCIM-Provisioning") damit Implementing-Agent nicht "freiwillig" Scope erweitert.

#N4 — docs/operations/admin-sso.md Mermaid-Flow-Diagramme sind als Anforderung in Step 14 + Subagent-Brief erwähnt; ein Hinweis welcher Mermaid-Renderer / welches Theme genutzt werden soll wäre hilfreich (sonst kommen 3 verschiedene Stile in den Docs zusammen).


10. Phase-Done-Definition (README) vs. Detail-MDs — Konsistenz

15 Items in README Phase-Done-Definition geprüft gegen Acceptance-Criteria in #81+#82:

README-Item In Detail-MD verankert
2 Tasks completed Trivial
Authentik auf Staging erreichbar #81 Acceptance
2 OIDC-Provider in Authentik #81 Acceptance
Groups + MFA-Pflicht #81 Acceptance
Admin-Login durchläuft #82 Acceptance
JIT-Provisioning erstellt AdminUser #82 Acceptance
Logout RP-Initiated #82 Acceptance
Email/Passwort-Fallback Env-Gated #82 Acceptance
App-MFA-Layer verdrahtet #82 Acceptance
4 AuditEvent-Typen geschrieben #82 Step 12 + Acceptance
Lint/typecheck/test grün Standard
docs/operations/authentik-setup.md #81 Step 11 + Acceptance
docs/operations/admin-sso.md #82 Step 14 + Acceptance
.env.example mit allen 7 Keys #82 Step 13 + Acceptance
Code-Review durch gsd-code-reviewer Standard
Backup-Restore-Drill #81 Test-Requirements
Phase-Summary in README Standard

Alle Items in den Detail-MDs verankert. Keine Inkonsistenz.


11. Abschlussbewertung

  • Template-Konformität: 10/10
  • Dependency-Konsistenz: 8/10 (J2/M1 noch zu fixen)
  • Implementation-Detail-Qualität: 10/10 (sehr ausführlich)
  • Test-Coverage-Pläne: 9/10 (kleinere NTHs)
  • Security-Notes: 10/10 (exzellent)
  • Staging-Steps: 10/10
  • User-Wunsch-Konsistenz: 10/10
  • Vollständigkeit (Fehlende Aspekte): 8/10 (M5/M6)

Gesamtbewertung: Phase 09 ist planungstechnisch ready-to-execute nach Adressierung von J1, J2, J3 und idealerweise der Minor-Fixes (M2-M6). Alle Nice-to-haves können während Execution adressiert werden.

Blocker für Execution: Keine — alle Findings sind klärbar/fix-bar ohne Konzept-Änderung. J1 (Routes-Konvention) ist mehr eine Stil-/Klärungs-Frage; falls die Projekt-Konvention die Dot-Notation tatsächlich verwendet (was in der laufenden Codebase verifiziert werden sollte), kann der Plan unverändert bleiben.

Empfehlung: Vor Phase-09-Start einmal kurz die Detail-MDs in einem Follow-up-Commit mit den Major-Fixes patchen, dann freigeben.