110 lines
4.4 KiB
Markdown
110 lines
4.4 KiB
Markdown
|
|
# 0012 — DEBUG_AUTH_TOKEN-Bypass für Diagnose-Sessions
|
||
|
|
|
||
|
|
| | |
|
||
|
|
|---|---|
|
||
|
|
| **Status** | accepted |
|
||
|
|
| **Datum** | 2026-05-06 |
|
||
|
|
| **Refs** | commit `f8cfa42` (Bypass), `d853101` (Logging+Rotation), MEMORY/reference_debug_auth_bypass.md |
|
||
|
|
|
||
|
|
## Kontext
|
||
|
|
|
||
|
|
Bei UI-Bugs auf `gwoe-dev.toppyr.de` brauche ich (oder ein Diagnose-
|
||
|
|
Tool) Zugriff auf admin-only HTML-Pages und API-Endpoints. Der reguläre
|
||
|
|
Pfad ist Keycloak-Login mit User-Passwort — funktioniert für den User
|
||
|
|
selbst, aber nicht für headless Tests, die in CI oder im Background
|
||
|
|
laufen.
|
||
|
|
|
||
|
|
Vor Phase 11b war der einzige Weg: Browser-Console-Output vom User
|
||
|
|
abfragen. Das ist langsam (User muss DevTools öffnen, Screenshot
|
||
|
|
schicken, Kontext erklären) und unsicher (User muss erinnern, wo er
|
||
|
|
geklickt hat).
|
||
|
|
|
||
|
|
## Optionen
|
||
|
|
|
||
|
|
### Option A — User-Passwort fest hinterlegen
|
||
|
|
|
||
|
|
Service-Account mit festem Passwort, in `.env` gespeichert. Test-
|
||
|
|
Skripte loggen sich darüber ein.
|
||
|
|
|
||
|
|
- **Pro:** funktioniert mit echtem Keycloak-Flow.
|
||
|
|
- **Kontra:** Service-Account ist ein vollwertiger User in Keycloak,
|
||
|
|
Passwort-Rotation muss synchron mit Keycloak geschehen. Login-Flow
|
||
|
|
ist langsam (3 HTTP-Roundtrips).
|
||
|
|
|
||
|
|
### Option B — JWT mit langer Laufzeit pre-generieren
|
||
|
|
|
||
|
|
Keycloak-Admin-API generiert ein JWT mit z.B. 7 Tagen Laufzeit, in
|
||
|
|
`.env` ablegen. Tests senden es als Bearer-Header.
|
||
|
|
|
||
|
|
- **Pro:** kein Login-Flow nötig.
|
||
|
|
- **Kontra:** 7 Tage langes JWT widerspricht der Token-Lifecycle-
|
||
|
|
Idee. Bei Leak: Keycloak kennt das Token nicht und kann es nicht
|
||
|
|
invalidieren (außer durch Sessions-Revocation des Users).
|
||
|
|
|
||
|
|
### Option C — Eigenes ENV-Secret als Bypass-Token
|
||
|
|
|
||
|
|
Eine zusätzliche Header-/Query-Pruefung im `require_auth`-Pfad: wenn
|
||
|
|
`X-Debug-Token` (oder `?__debug_token=`) dem ENV-Secret entspricht,
|
||
|
|
wird ein Mock-Admin-User zurückgegeben.
|
||
|
|
|
||
|
|
- **Pro:** kein Keycloak-Roundtrip, einfach rotierbar (ENV-Update +
|
||
|
|
Container-Recreate), inactive bei leerem ENV.
|
||
|
|
- **Kontra:** parallele Auth-Pfad neben Keycloak — Risiko bei Audit-
|
||
|
|
Anfragen, ob das System tatsächlich nur über Keycloak authentifiziert.
|
||
|
|
|
||
|
|
## Entscheidung
|
||
|
|
|
||
|
|
**Option C** umgesetzt mit folgender Härtung:
|
||
|
|
|
||
|
|
1. **ENV-binär:** `DEBUG_AUTH_TOKEN=` (leer) → Bypass komplett aus.
|
||
|
|
Default in `docker-compose.dev.yml` ist `${DEBUG_AUTH_TOKEN:-}` →
|
||
|
|
wenn nicht in `.env`, kein Bypass.
|
||
|
|
2. **Nur dev-compose** reicht die ENV durch. Prod-`docker-compose.yml`
|
||
|
|
referenziert sie nicht, der Container sieht sie nicht — selbst wenn
|
||
|
|
jemand sie auf vserver setzt.
|
||
|
|
3. **Mock-User-Rollen:** `["admin", "gwoe-admin"]` — keine echten
|
||
|
|
Keycloak-Rollen, sodass z.B. `audit_log` zwischen Bypass und
|
||
|
|
regulärem Login unterscheiden kann (sub=`debug-user` vs. echte UUID).
|
||
|
|
4. **Audit-Logging:** jeder Use schreibt in `auth_bypass_uses`
|
||
|
|
(`used_at`, `client_ip`, `path`, `user_agent`) plus
|
||
|
|
`logger.warning`. Best-Effort, schlägt unter keinen Umständen den
|
||
|
|
Request fehl.
|
||
|
|
5. **Rotation:** `scripts/rotate-debug-token.sh` läuft wöchentlich
|
||
|
|
(Sonntag 04:00 Cron) und generiert ein neues `secrets.token_urlsafe(32)`
|
||
|
|
in `.env` mit `docker compose up -d --force-recreate`.
|
||
|
|
6. **Manuelle Rotation** ist trivial:
|
||
|
|
```bash
|
||
|
|
NEW=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))")
|
||
|
|
ssh vserver "sed -i 's|^DEBUG_AUTH_TOKEN=.*|DEBUG_AUTH_TOKEN='$NEW'|' /opt/gwoe-antragspruefer-dev/.env"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Konsequenzen
|
||
|
|
|
||
|
|
### Positiv
|
||
|
|
|
||
|
|
- Headless Smoketests (siehe `tests/e2e/test_smoke_browser.py`)
|
||
|
|
laufen ohne Keycloak-Setup. 9 Tests in 52 s gegen Live-System.
|
||
|
|
- Diagnose-Sessions (Playwright + Console-Hook) sind möglich, ohne
|
||
|
|
User-Passwort zu kennen oder zu erfragen.
|
||
|
|
- Bei Audit-Anfragen: `auth_bypass_uses`-Tabelle liefert vollständige
|
||
|
|
Use-Historie mit IP+Path.
|
||
|
|
|
||
|
|
### Negativ
|
||
|
|
|
||
|
|
- Parallele Auth-Pfad. Wenn das ENV-Secret leakt, hat der Angreifer
|
||
|
|
Admin-Zugang zu dev. Mitigation: nur dev, Rotation, Logging.
|
||
|
|
- Bypass-User hat keine echte Identität — manche Endpoints wie
|
||
|
|
Mail-Versand würden mit `email="debug@local"` arbeiten. Keine
|
||
|
|
echten Mails an reale Empfänger möglich (Tabu-Regel), aber
|
||
|
|
defensives Coding nötig.
|
||
|
|
|
||
|
|
### Folgen für andere ADRs
|
||
|
|
|
||
|
|
- **0005 Keycloak SSO mit Dev-Bypass-Fallback:** das war der
|
||
|
|
„kein-Keycloak-konfiguriert"-Bypass. ADR 0012 ergänzt einen
|
||
|
|
zweiten Bypass für **konfiguriertes** Keycloak — beide sind
|
||
|
|
orthogonal und nicht konkurrierend.
|
||
|
|
- **Folge-Issue:** wenn prod-Diagnose nötig wird, könnte ein
|
||
|
|
separater prod-Bypass mit eigener Kontrollebene (z.B.
|
||
|
|
HMAC-signierte Tokens, IP-Whitelist) sinnvoll sein.
|