Files
aza/AzA march 2026/security/handovers/STEP_4_3_SECRET_KEY.md

163 lines
4.8 KiB
Markdown
Raw Normal View History

2026-03-25 22:03:39 +01:00
# STEP 4.3 HARDCODED SECRET KEY ENTFERNT (LÜCKE #19)
# Status: ABGESCHLOSSEN
---
## Fundstellen
| Datei | Zeile | Problem |
|-------|-------|---------|
| `workforce_planner/config.py` | 18 | `SECRET_KEY = os.getenv("WP_SECRET_KEY", "dev-secret-change-in-production")` Hardcoded Fallback-Secret |
| `workforce_planner/api/auth.py` | 35, 47 | Konsument: JWT encode/decode mit `SECRET_KEY` |
Keine weiteren hardcoded Secrets gefunden:
- `basis14.py`: OPENAI_API_KEY kommt aus ENV, kein Fallback
- `basis14.py`: MEDWORK_API_TOKEN kommt aus ENV oder Datei, kein hardcoded Wert
- `aza_email_config.json`: Passwörter im Klartext (separates GAP, nicht in diesem Schritt)
---
## Neue ENV-Variablen
| Variable | Pflicht | Beschreibung |
|----------|---------|-------------|
| `AZA_SECRET_KEY` | Ja (ausser DEV) | JWT-Signing-Key, min. 32 Zeichen |
| `AZA_ENV` | Nein | `dev` = erlaubt auto-generierten Key |
Alte Variable `WP_SECRET_KEY` wird **nicht mehr verwendet**.
---
## Implementierung
### workforce_planner/config.py (komplett neu)
**ALT:**
```python
SECRET_KEY = os.getenv("WP_SECRET_KEY", "dev-secret-change-in-production")
```
**NEU:**
```python
def _load_secret_key() -> str:
key = os.getenv("AZA_SECRET_KEY", "").strip()
env_mode = os.getenv("AZA_ENV", "").strip().lower()
# Kein Key: DEV auto-gen oder Fail-Start
if not key:
if env_mode == "dev":
return secrets.token_hex(64) # temporär, nur diese Session
sys.exit(1) # Fehlermeldung + Exit
# Zu kurz (< 32 Zeichen): Fail-Start
if len(key) < 32:
sys.exit(1)
# Triviales Muster: Fail-Start
for pattern in ("dev", "test", "password", "secret", ...):
if key.startswith(pattern) und nicht-alphanumerisches Folgezeichen:
sys.exit(1)
return key
SECRET_KEY = _load_secret_key()
```
### workforce_planner/api/auth.py
Keine Änderung nötig importiert weiterhin `SECRET_KEY` aus `config.py`.
Die Variable hat denselben Namen, der Wert kommt jetzt validiert aus ENV.
---
## Fail-Start Verhalten
| Szenario | Ergebnis |
|----------|----------|
| Kein `AZA_SECRET_KEY`, kein `AZA_ENV=dev` | Exit 1 + Fehlermeldung |
| `AZA_ENV=dev`, kein Key | OK (auto-gen, Warnung auf stderr) |
| Key < 32 Zeichen | Exit 1 + "zu kurz" |
| Key mit trivialem Muster ("dev-...", "test-...", "password...") | Exit 1 + "triviales Muster" |
| Gültiger Key >= 32 Zeichen | OK |
| Nur `WP_SECRET_KEY` gesetzt (alt) | Exit 1 (wird ignoriert) |
---
## Testkommandos + erwartete Outputs
### 1. Fail-Start (kein Key)
```bash
python -c "from workforce_planner.config import SECRET_KEY"
# → Exit 1: FEHLER: AZA_SECRET_KEY ist nicht gesetzt.
```
### 2. DEV-Modus (auto-gen)
```bash
AZA_ENV=dev python -c "from workforce_planner.config import SECRET_KEY; print(len(SECRET_KEY))"
# → 128 (hex-encoded 64 Bytes) + Warnung auf stderr
```
### 3. Zu kurzer Key
```bash
AZA_SECRET_KEY=short123 python -c "from workforce_planner.config import SECRET_KEY"
# → Exit 1: FEHLER: AZA_SECRET_KEY ist zu kurz (8 Zeichen, Minimum: 32)
```
### 4. Triviales Muster
```bash
AZA_SECRET_KEY="test-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" python -c "from workforce_planner.config import SECRET_KEY"
# → Exit 1: FEHLER: AZA_SECRET_KEY enthält triviales Muster ('test')
```
### 5. Gültiger Key
```bash
AZA_SECRET_KEY=$(python -c "import secrets; print(secrets.token_hex(64))") python -c "from workforce_planner.config import SECRET_KEY; print('OK:', len(SECRET_KEY), 'chars')"
# → OK: 128 chars
```
---
## Testergebnis (automatisiert)
```
12/12 PASS, 0/12 FAIL
GESAMTBEWERTUNG: PASS
```
| Test | Ergebnis |
|------|----------|
| Fail-Start ohne Key | PASS |
| Fehlermeldung enthält 'AZA_SECRET_KEY' | PASS |
| DEV auto-gen Key | PASS |
| Key geladen (128 chars) | PASS |
| Warnung ausgegeben | PASS |
| Fail-Start kurzer Key | PASS |
| Fehlermeldung 'zu kurz' | PASS |
| Fail-Start alter Fallback | PASS |
| Fail-Start triviales Pattern (lang) | PASS |
| Start mit gültigem Key | PASS |
| Key geladen (64 chars) | PASS |
| WP_SECRET_KEY allein -> Fail-Start | PASS |
---
## Session/Token-Invalidierung
**Impact:** Bestehende JWT-Tokens (HS256), die mit dem alten Fallback-Key
`"dev-secret-change-in-production"` signiert wurden, werden nach dem
Setzen eines neuen `AZA_SECRET_KEY` **ungültig**.
- Betroffene Nutzer müssen sich **einmalig neu anmelden**.
- Dies betrifft nur den `workforce_planner` (Arbeitsplan-Modul).
- `basis14.py` verwendet keine JWT-Tokens (nur lokales Passwort-Hashing).
- **Keine komplexe Rotation** implementiert (nicht im Scope dieses Schrittes).
- Bei Produktivbetrieb: Key einmalig setzen und dauerhaft beibehalten.
---
## Geänderte Dateien
| Datei | Änderung |
|-------|----------|
| `workforce_planner/config.py` | Hardcoded Fallback entfernt, `_load_secret_key()` mit Validierung + Fail-Start implementiert |