# Service-Key-Rotation — Cards Stand: 2026-05-12. `CARDS_DSGVO_SERVICE_KEY` ist heute ein **statischer** Service-Key, gegen den `apps/api/src/middleware/service-key.ts` constant-time- vergleicht. mana-admin verwendet ihn für DSGVO-Fan-Out (`POST /api/v1/dsgvo/{export,delete}`). Bis Phase F-1 die Verifikation gegen `mana-auth.apps.app_service_keys` ersetzt, bleibt Rotation manuell. Dieses Playbook hält den Ablauf festgenagelt. --- ## Wann rotieren - **Sofort** bei Verdacht auf Leak (Logs, env-Datei, Container-Image, alte Backups, geleakte Screenshots). - **Routinemäßig** alle 6 Monate. - **Nach Personalwechsel** in der Plattform-Crew. - **Nach jeder Notfall-`docker compose exec`-Session**, in der der Key sichtbar war. ## Rotation in 5 Schritten ### 1. Neuen Key generieren ```bash openssl rand -hex 32 # Beispiel: msk_2cfa7… (Prefix nach Konvention msk_ für „Mana Service Key") ``` ### 2. Neuen Key auf der Prod-Box eintragen ```bash ssh mana-server cd ~/projects/cards nano infrastructure/.env.production # CARDS_DSGVO_SERVICE_KEY=msk_ ← ersetzen ``` `.env.production` ist git-ignored und liegt ausschließlich auf der Box. Nicht ins Repo committen. ### 3. cards-api neustarten ```bash docker compose -f infrastructure/docker-compose.production.yml \ --env-file infrastructure/.env.production \ up -d cards-api ``` Kein Rebuild nötig — env-only-Change. ### 4. Neuen Key bei den Callern eintragen Aktueller Single-Caller: **mana-admin**. ```bash # mana-Plattform: env-Datei für mana-admin updaten + Service neustarten ssh mana-server cd ~/projects/mana nano .env.production # CARDS_DSGVO_SERVICE_KEY_FOR_FANOUT=msk_ ← oder wie auch immer # die mana-admin-env-Variable benannt ist docker compose -f infrastructure/docker-compose.production.yml \ up -d mana-admin ``` Wenn weitere S2S-Caller dazukommen (z.B. mana-research): hier ergänzen. ### 5. Verifizieren + alten Key invalidiert ```bash # Alter Key MUSS jetzt 401 geben: curl -i -H "X-Service-Key: " \ https://cardecky-api.mana.how/api/v1/dsgvo/export?user_id=... # Erwartet: 401 service_key_invalid # Neuer Key MUSS funktionieren: curl -i -H "X-Service-Key: " \ https://cardecky-api.mana.how/api/v1/dsgvo/export?user_id=... # Erwartet: 200 mit JSON-Bundle ``` Audit-Log-Zeile prüfen: ```bash docker logs cards-api --since 5m | grep '"event":"dsgvo.export"' | tail ``` Sollte den letzten erfolgreichen Aufruf mit `auth_mode: "service-key"` zeigen. --- ## Was nach Phase F-1 anders wird Phase F-1 ersetzt die `serviceKeyAuth()`-Middleware durch Verifikation gegen `mana-auth.apps.app_service_keys`. Damit: - Keys leben in der DB, nicht in env. - Rotation = `UPDATE apps.app_service_keys SET key_hash = … WHERE app_id = 'cards'`. - Multiple Keys parallel möglich (overlap-Rotation ohne Downtime). - Revocation via Soft-Delete-Flag. Bis dahin: dieses Playbook. --- ## Tabu - **Nie** den Service-Key in Commit-Messages, PR-Beschreibungen oder Chat-Threads klartext hinschreiben. - **Nie** im selben Step neuen Key generieren *und* alten Caller weiterlaufen lassen — kurz Downtime ist OK, blindes Doppel- Akzeptieren ist es nicht. (Die Middleware hat heute nur einen Slot.) - **Nie** `CARDS_DSGVO_SERVICE_KEY` im Compose-File hart vorgeben — bleibt env-var-Reference (`${CARDS_DSGVO_SERVICE_KEY:?missing}`), damit der Compose-Default „fail-loud" ist.