- docker-compose.coolify(.prebuilt).yml: Service craftvia-worker (Target worker, Chromium, shm_size 1gb, gleiche Härtung), Craftvia-Variablen für app und worker. - Dockerfile: worker-Stage mit HOME=/home/app (Chromium-Profil für non-root); lokaler docker build der Targets runner und worker erfolgreich, PDF-Erzeugung im Image geprüft. - .env.example/.env.prod.example/.env.coolify.example: alle Craftvia-Variablen inkl. RLS, KI-Provider, PDF_CHROMIUM_PATH, OFFLINE_MAX_DAYS, API_RATE_LIMIT_*, AI_GENERATION_RETENTION_DAYS, AI_MONTHLY_TOKEN_LIMIT. - CI (.github, .gitea): Job gate mit Postgres (pgvector) und Redis als Service: migrate deploy, seed, Passwort für craftvia_app, tsc, lint, build, npm run test. - docs/craftvia/DEPLOY.md (aus den Certvia-Deploy-Docs abgeleitet): Architektur, Domains, Secrets, Worker, Migrationen, RLS-Aktivierung, Backup/Restore, KI, Rate Limits, Aufbewahrung, Smoke, Update/Rollback. build-and-push-images.sh baut craftvia-worker. - Certvia-/ISMS-Dokumente aus docs/ nach docs/_certvia-archiv/ (mit README); Verweise in README.md und Skript-Kommentaren angepasst. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
79 lines
8.3 KiB
Markdown
79 lines
8.3 KiB
Markdown
# Umsetzungspaket — Sicherheit & Administration (1 Entwickler)
|
||
|
||
> Claude-Code-Prompt. Basis-Branch **`dev`**; je Story ein Feature-Branch `dev/sec<n>-…` (PR-Ziel `dev`). Grundlage: `Sicherheit-und-Administration-Konzept.md` + Ist-Stand `STAND-dev-branch.md`.
|
||
> **Entscheidungen (fix):** Mail via **SMTP** · **1 Entwickler** (sequenziell) · **2FA bleibt optional**, aber **pro Tenant im Adminportal als Pflicht** einstellbar · **Passkeys** dabei · **DSGVO-Funktionen** dabei.
|
||
|
||
## Vorhandenes wiederverwenden (nicht neu bauen)
|
||
- **MFA-Kern** (TOTP + Recovery-Codes) für Plattform- und Mandanten-Nutzer: `src/server/mfa.ts`; Policy-Flag `securityPolicy.mfaRequired` existiert.
|
||
- **Passwort**: `src/lib/password-policy.ts` (Validierung) + `src/server/password.ts` (Argon2id + Generator); **Force-Change**-Gate im `(app)`-Layout.
|
||
- **Auth**: zwei NextAuth-Instanzen — Mandant `src/server/auth.ts` (`/login`), Plattform `src/server/platform-auth.ts` (`/platform/login`). **`PlatformAdmin`**-Store getrennt.
|
||
- **Queue**: BullMQ + Redis im Stack. **Audit-Log** mit `tenantId` nullable (`scope=platform`). **Task/TaskComment** für Ticket-/Freigabe-Ereignisse.
|
||
- **Modul-Guard**: neue Server-Actions in `scripts/check-module-guards.ts` eintragen; tenant-Modelle in `TENANT_MODELS`+RLS.
|
||
|
||
## Betriebs-/DNS-Voraussetzungen (kein Code, aber Vorbedingung)
|
||
Dedizierte Absenderdomain (`no-reply@certvia.de`) mit **SPF, DKIM, DMARC**; TLS/HSTS; SMTP-Zugangsdaten + alle Secrets aus **Env/Secret-Store** (nicht im Repo).
|
||
|
||
---
|
||
|
||
## Reihenfolge (sequenziell, 1 Entwickler)
|
||
SEC1 → SEC2 → SEC3 → SEC4 → SEC5 → SEC6. Einzelne P0-Härtungen (Rate-Limit an Login/Reset/MFA, Token-Hashing) landen **inline** in SEC2/SEC3; die globalen Härtungen bündelt SEC5.
|
||
|
||
---
|
||
|
||
## SEC1 — SMTP-Mail-Fundament (`dev/sec1-mail-smtp`) [L]
|
||
**Ziel:** zuverlässiger, gebrandeter, asynchroner Mail-Versand als Fundament für Reset/Einladung/Benachrichtigung.
|
||
- **Mail-Service** `src/server/mail/**` mit **SMTP-Transport** (nodemailer, TLS) hinter einem Interface `sendMail(template, to, vars, locale)` — Provider später austauschbar.
|
||
- **Queue/Worker** über BullMQ/Redis: asynchron, **Retry mit Backoff**, Dead-Letter, Rate-Limit; Fehler/Bounce ins Log.
|
||
- **Templates** (Certvia-gebrandet, **de/en**, HTML + Text-Alternative): Einladung, Passwort-Reset, „Passwort geändert", E-Mail-Änderung bestätigen, „MFA geändert", **Ticket-/Freigabe-/Fristen-Benachrichtigung**.
|
||
- **Benachrichtigungsregeln**: je Nutzer/Ereignis opt-in/opt-out + Sprache; strikt mandantengetrennt. Trigger aus Task-Ereignissen (Zuweisung, Freigabe-Anfrage, Entscheidung, Fälligkeit).
|
||
- **Admin-Testversand** (eine Aktion „Test-Mail senden") zur Zustellprüfung.
|
||
- **AK:** Mail wird asynchron mit Retry versendet; Templates gebrandet + zweisprachig; Bounces/Fehler geloggt; Ticket-Benachrichtigung wird bei Task-Zuweisung/Freigabe ausgelöst; keine Secrets im Repo.
|
||
|
||
## SEC2 — Passwort-Self-Service & Sessions (`dev/sec2-auth-selfservice`) [M–L] · Abh. SEC1
|
||
- **Passwort-Reset**: „Passwort vergessen" → **Single-Use-Token**, kurzlebig (30–60 Min), **serverseitig gehasht** gespeichert, an E-Mail gebunden. **Enumeration-Schutz** (immer gleiche Antwort), **Rate-Limit** je IP/Konto. Nach Reset: **alle Sessions invalidieren** + Bestätigungs-Mail + Audit; deaktivierte/gesperrte Konten erhalten keinen Reset.
|
||
- **Passwort selbst ändern**: Profilseite mit **Alt-Passwort-Bestätigung**, Policy-Prüfung, danach **andere Sessions abmelden** (aktuelle behalten), Bestätigungs-Mail + Audit.
|
||
- **E-Mail-Änderung**: **Double-Opt-in** an neue Adresse + Benachrichtigung an alte; Audit.
|
||
- **Session-Invalidierung** als wiederverwendbarer Baustein (bei Reset/Änderung/Deaktivierung/MFA-Änderung).
|
||
- **AK:** Reset-Token single-use/gehasht/rate-limited/enumeration-safe; Self-Change funktioniert; E-Mail-Änderung verifiziert; Sessions werden korrekt invalidiert; alle Ereignisse im Audit.
|
||
|
||
## SEC3 — MFA pro Tenant erzwingen + Passkeys (`dev/sec3-mfa-passkeys`) [L] · Abh. SEC1
|
||
- **Optional bleibt Default.** Im **Adminportal** kann pro Mandant `securityPolicy.mfaRequired` gesetzt werden (Superadmin) → **Enrollment-Gate**: Nutzer dieses Mandanten werden beim nächsten Login zur MFA-Einrichtung gezwungen (analog Force-Change-Gate im `(app)`-Layout). Ebenso erzwingbar für **alle Plattform-Admins**.
|
||
- **Passkeys/WebAuthn** als zusätzlicher 2. Faktor (`@simplewebauthn/server` + Browser-API): Registrierung + Login; Nutzer kann **TOTP oder Passkey** verwenden; Credentials verwaltbar (anlegen/entfernen).
|
||
- **Step-up-Re-Auth** für sensible Aktionen: MFA deaktivieren, Plattform-Admin anlegen, Datenexport, Mandant löschen.
|
||
- **TOTP-Secret at rest verschlüsselt** (falls noch Klartext) + **Rate-Limit** auf Code-Eingabe; Recovery-Codes-Flow (Anzeige/Regenerierung, Verbrauch protokolliert) abrunden.
|
||
- **AK:** Admin setzt `mfaRequired` je Tenant → betroffene Nutzer müssen beim Login enrollen; Passkey-Registrierung + -Login funktionieren; Step-up greift bei sensiblen Aktionen; TOTP-Secret verschlüsselt; MFA global weiterhin optional, wenn Policy es nicht verlangt.
|
||
|
||
## SEC4 — Plattform-Admin-Verwaltung (`dev/sec4-platform-admins`) [M] · Abh. SEC1, SEC3
|
||
- **Verwaltungs-UI** im Adminportal (`src/app/(platform)/admin/**`, Actions `platform*.ts`): weitere **`PlatformAdmin`** anlegen (Einladung via SEC1 oder Initial-Passwort), **Rollen** (z. B. „Voll-Admin" vs. „Support/Read-only"), **sperren/reaktivieren**, Passwort-Reset, **MFA-Pflicht** für Plattform-Admins.
|
||
- **Selbst-Aussperr-Schutz** auf Plattform-Ebene (letzter Voll-Admin nicht entfernbar/deaktivierbar); kritische Aktionen mit **Step-up** (SEC3).
|
||
- **Vollständiges Plattform-Audit** (`scope=platform`) jeder Aktion.
|
||
- **AK:** ein zweiter Voll-Admin ist anlegbar und kann verwalten; Rollen greifen (Read-only kann nichts ändern); Last-Admin-Schutz aktiv; jede Aktion protokolliert.
|
||
|
||
## SEC5 — Härtung P0 (quer) (`dev/sec5-hardening`) [M]
|
||
- **HTTP-Security-Header** (zentrale Middleware): CSP, HSTS, `X-Frame-Options`/`frame-ancestors`, `X-Content-Type-Options`, `Referrer-Policy`, `Permissions-Policy`.
|
||
- **Rate-Limiting/Brute-Force** global an Login/Reset/MFA/Admin-Aktionen (IP **und** kontobezogen), ergänzt den bestehenden Konto-Lockout.
|
||
- **Security-Audit erweitern**: Logins (Erfolg/Fehlschlag), Rechte-/Rollenänderungen, MFA-Änderungen, Exporte, Admin-Aktionen; **append-only**/manipulationssicher; Aufbewahrung definiert.
|
||
- **Passwort-Breach-Check** (HaveIBeenPwned k-Anonymity) beim Setzen/Ändern zusätzlich zur Policy.
|
||
- **Token-/Secret-Hygiene**: alle Tokens single-use + gehasht (Konsistenz zu SEC2/SEC3); **Secret-Scanning** in CI.
|
||
- **AK:** Header messbar gesetzt (z. B. securityheaders-Check); Rate-Limits greifen; Audit-Ereignisse vorhanden; bekannte kompromittierte Passwörter werden abgelehnt.
|
||
|
||
## SEC6 — DSGVO-Funktionen (`dev/sec6-dsgvo`) [L] · Abh. SEC1, SEC3 (Step-up)
|
||
- **Mandanten-Datenexport** (vollständig, maschinenlesbar, z. B. JSON/ZIP), Admin-getriggert, **asynchron** via Queue, Download-Link mit Ablauf.
|
||
- **Löschung/Retention**: Mandanten-Löschung (Soft→Hard mit Karenz), **Aufbewahrungsfristen**/Löschkonzept, RLS-bewusste Kaskaden; Audit; Step-up-Bestätigung.
|
||
- **Betroffenenrechte**: Export/Löschung nutzerbezogener Daten, soweit anwendbar.
|
||
- **Doku-Bausteine** (Inhalt, kein Code): AVV/DPA + TOMs — als offener fachlicher Punkt markieren.
|
||
- **AK:** vollständiger Tenant-Export erzeugbar; Löschung respektiert Retention + Audit + Step-up; DSGVO-Aktionen protokolliert.
|
||
|
||
---
|
||
|
||
## Definition of Done (jede Story)
|
||
`npx tsc --noEmit` → `npm run lint` → `npm run build` (Guard-Check) grün · neue Actions in `check-module-guards.ts` · neue tenant-Modelle in `TENANT_MODELS`+RLS+Migration (RLS-DO-Block) · Security-Verifikation (Header/Rate-Limit/Token) · Browser-Test der Flows · Demo-Umgebung lauffähig · **Secrets nur aus Env**.
|
||
|
||
## Hot Files (koordiniert, da 1 Entwickler → nur Reihenfolge beachten)
|
||
`prisma/schema.prisma` + Migrationsreihenfolge · zentrale **Middleware** (Header/Rate-Limit) · `(app)`- und `(platform)`-Layouts (Enrollment-/Force-Gates) · `src/server/auth.ts` / `platform-auth.ts` / `mfa.ts` · `scripts/check-module-guards.ts`.
|
||
|
||
## Offene fachliche Punkte
|
||
- DNS: SPF/DKIM/DMARC vor Produktivversand aktiv.
|
||
- AVV/DPA-Texte + TOMs (Datenschutz/ISB).
|
||
- Aufbewahrungsfristen je Datenart festlegen (Grundlage für SEC6-Retention).
|