diff --git a/docs/vs-nfd/20-massnahmenplan.md b/docs/vs-nfd/20-massnahmenplan.md index fec2ab4..2f8134c 100644 --- a/docs/vs-nfd/20-massnahmenplan.md +++ b/docs/vs-nfd/20-massnahmenplan.md @@ -181,9 +181,9 @@ _Meilenstein: `M30 — VS-NfD: compliance documentation`_ Wächst um ca. 25 %, weil jede neue Funktion Handbuch- und Härtungsabschnitte nach sich zieht. -- [ ] **Abgrenzungserklärung §52 VSA** — welche Sicherheitsgrundfunktionen die +- [x] **Abgrenzungserklärung §52 VSA** — welche Sicherheitsgrundfunktionen die Anwendung _nicht_ erbringt und wem sie zufallen. Wichtigstes - Einzeldokument. · 3 AT · #226 + Einzeldokument. · 3 AT · #226 → `40-abgrenzungserklaerung.md` - [ ] **Härtungsleitfaden** mit Referenzkonfiguration „VS-NfD-Betrieb": lokale Auth aus, Public-API aus, MCP aus, Feeds aus, Plugins aus, Backup nur lokal · 3 AT · #227 diff --git a/docs/vs-nfd/40-abgrenzungserklaerung.md b/docs/vs-nfd/40-abgrenzungserklaerung.md new file mode 100644 index 0000000..21fc2bd --- /dev/null +++ b/docs/vs-nfd/40-abgrenzungserklaerung.md @@ -0,0 +1,317 @@ +# Abgrenzungserklärung nach §52 VSA — Dorfteich + +> Liefergegenstand zu Issue #226 (Meilenstein `M30`, compliance +> documentation). Grundlage: ADR 0019 (Entwurfsfassung dieser +> Erklärung); bei inhaltlicher Abweichung wird zuerst das ADR geändert, +> dann diese Erklärung nachgezogen — nie umgekehrt. +> Code-Stand der Belege: `main` = `fd07f71` (Prod v0.12.0); Fundorte in +> der Form `datei:zeile` beziehen sich auf diesen Stand und sind in +> `docs/vs-nfd/10-ist-aufnahme.md` ausführlich hergeleitet. +> Status: Entwurf zur Prüfung. Die juristische Prüfung durch einen +> Rechtsbeistand steht aus und ist nicht Teil dieses Dokuments. + +## 1. Zweck und Adressat + +Dorfteich soll in einer nach der Verschlusssachenanweisung (VSA) +freigegebenen IT-Umgebung einer Behörde betrieben werden können, für +Inhalte bis einschließlich VS-NUR FÜR DEN DIENSTGEBRAUCH (VS-NfD). Eine +BSI-Zulassung von Dorfteich selbst wird **nicht** angestrebt. + +§51 VSA unterwirft IT-Produkte, die eine _Sicherheitsgrundfunktion_ +erbringen, der Zulassungspflicht. §52 VSA benennt diese Grundfunktionen: +**Verschlüsselung, Datenträgerschutz, Netzabschluss und +Authentisierung**. Diese Erklärung legt dar, dass Dorfteich keine dieser +Grundfunktionen selbst erbringt, welche Partei sie stattdessen erbringt, +und wo der heutige Code-Stand dieser Erklärung noch nicht entspricht +(Abschnitt 7). + +Adressat sind Geheimschutzbeauftragte und IT-Sicherheitsbeauftragte +der betreibenden Behörde sowie prüfende Stellen. Die Erklärung ist +zugleich die schriftliche Übergabe der Betreiberpflichten (Abschnitt 6): +was die Anwendung bewusst nicht leistet, muss die Plattform der Behörde +leisten — das ist die Arbeitsteilung, die §52 VSA vorzeichnet, keine +Lücke der Anwendung. + +## 2. Geltungsbereich und Betriebsmodell + +Die Erklärung gilt für die Anwendung Dorfteich in der +Referenz-Zusammensetzung aus `deploy/compose/docker-compose.yml`: die +vier eigenen Dienste web, api, collab und backup sowie die Sidecars +PostgreSQL, pandoc und Gotenberg (Caddy optional als Compose-Profil). +Vorausgesetzt wird das Betriebsmodell aus ADR 0019: + +- **Eine Instanz je Einstufungsniveau.** Die Anwendung trennt + Einstufungsniveaus nicht selbst; die Trennung geschieht außerhalb der + Anwendung durch getrennte Instanzen. Innerhalb einer Instanz + _kennzeichnet_ die Anwendung eingestufte Inhalte lediglich (ADR 0022). +- Die Instanz ist Single-Tenant (33 Prisma-Modelle, kein Mandanten-Modell; + Ist-Aufnahme I-35) — Teiche sind Container innerhalb einer Instanz, + keine Sicherheitsgrenze zwischen Einstufungsniveaus. +- Betrieb in der VS-NfD-Referenzkonfiguration des Härtungsleitfadens + (#227): lokale Anmeldung aus, Public-API aus, MCP aus, Feeds aus, + Plugins aus, Backup nur lokal. + +## 3. Grundsatz + +**Dorfteich erbringt keine Sicherheitsgrundfunktion im Sinne von +§52 VSA. Verschlüsselung, Datenträgerschutz, Netzabschluss und +Authentisierung fallen der Plattform des Betreibers zu** (ADR 0019). + +Das ist Architektur, nicht Unterlassung: Jede dieser Funktionen in der +Anwendung selbst würde Dorfteich zum Träger einer Grundfunktion machen +und in die Zulassungspflicht nach §51 VSA ziehen. Die Anwendung hält sich +deshalb bewusst frei von Inhaltsverschlüsselung, Backup-Verschlüsselung, +eigenem MFA und eigenen Krypto-Primitiven — und jeder künftige +Funktionsvorschlag wird an ADR 0019 gemessen, bevor er gebaut wird. + +Was die Anwendung an Sicherheit selbst beiträgt, ist ein anderer, ihr +zufallender Satz von Eigenschaften (Abschnitt 5): zentrales +default-closed-Berechtigungsmodell, vollständige Abwesenheit ausgehender +Verbindungen, Kennzeichnung eingestufter Inhalte in jedem Ausgabekanal +und ein Audit-Trail. + +## 4. Die Grundfunktionen im Einzelnen + +Je Grundfunktion: was die Anwendung tut, was sie bewusst nicht tut, und +wer die Funktion erbringt. Jede Aussage ist am Code belegt. + +### 4.1 Verschlüsselung + +**Was die Anwendung tut.** Die vollständige Inventur eigener +Krypto-Aufrufe (Ist-Aufnahme, Abschnitt 3.1): + +| Zweck | Verfahren | Fundort | +| ------------------------ | ------------------------------ | --------------------------------------------------- | +| Passwörter | Argon2id (Bibliothek `argon2`) | `apps/api/src/users/password.ts:9–25` | +| Session-Ids | SHA-256 über das Token | `apps/api/src/auth/sessions.service.ts:84` | +| Auth-Tokens (Mail-Flows) | SHA-256 | `apps/api/src/auth/auth-tokens.service.ts:55` | +| PATs | SHA-256 | `apps/api/src/public-api/api-tokens.service.ts:149` | +| Feed-Tokens | SHA-256 | `apps/api/src/public/feed-tokens.service.ts:73` | +| Collab-Tokens (TTL 60 s) | HS256-JWT | `packages/shared/src/token-crypto.ts` | +| Unsubscribe-Tokens | HMAC-SHA-256 | `apps/api/src/notifications/unsubscribe-token.ts` | + +Sämtliche Verfahren dienen der Absicherung von Zugangsdaten und +kurzlebigen Tokens — **nirgends im Code werden Inhalte ver- oder +entschlüsselt**. + +**Was die Anwendung bewusst nicht tut.** Keine Verschlüsselung von +Inhalten in Datenbank oder Dateisystem (Anhänge liegen unverschlüsselt +unter `UPLOADS_DIR//`, +`apps/api/src/files/file-storage.service.ts:21,25`). Keine +Backup-Verschlüsselung (`apps/backup/`, ADR 0015, ADR 0026). Keine +TLS-Implementierung. Keine eigenen kryptographischen Primitive über die +obige Tabelle hinaus; die vorhandene Token-Signatur wird auf eine +geprüfte Bibliothek mit zweckgebundenen Schlüsseln umgestellt (ADR 0020, +#188) — eine Verengung bestehender Krypto, keine neue Grundfunktion. + +**Wer die Funktion erbringt.** Die Plattform des Betreibers: +Vertraulichkeit ruhender Daten durch Volume- bzw. +Festplattenverschlüsselung der Hosts (Datenbank, Upload-Verzeichnis, +Backup-Ablage), Transportverschlüsselung durch die vom Betreiber +betriebene TLS-Terminierung (Abschnitt 4.3). + +### 4.2 Datenträgerschutz + +**Was die Anwendung tut.** Sie hält die Zahl und Lebensdauer der +Datenkopien klein und benennt sie vollständig (Ist-Aufnahme, +Abschnitt 3.2): Inhalte liegen ausschließlich in PostgreSQL (fünf +Repräsentationen je Seite), Anhänge im Dateisystem, Backups in der +konfigurierten Ablage mit konfigurierbarer Retention. Löschung ist +zweistufig (Papierkorb → Purge-Job), der Seiten-Purge erfasst Anhänge, +Content-Cache, Update-Log und abhängige Tabellen (Ist-Aufnahme I-42). +Der PWA-Service-Worker cached **keine** Inhalte, nur Build-Assets +(`apps/web/vite.config.ts:12–20`). Künftig beschränkt die Anwendung, +_wohin_ Backups gehen dürfen (Deploy-Allowlist, leere Liste = nur lokal; +ADR 0026, #192) — mehr nicht. + +**Was die Anwendung bewusst nicht tut.** Keine Verschlüsselung ruhender +Daten (s. 4.1), keine sichere Vernichtung physischer Datenträger, kein +Schutz der Endgeräte. + +**Wer die Funktion erbringt.** Der Betreiber: Festplatten-/ +Volume-Verschlüsselung der Server, Behandlung und Vernichtung von +Datenträgern (einschließlich Backup-Medien) nach den Regeln der Behörde, +und — ausdrücklich — der **Schutz der Endgeräte**: + +> **Inhaltskopie auf dem Endgerät (Betreiberpflicht).** Jede im Editor +> geöffnete Seite wird als Yjs-Dokument in die IndexedDB des Browsers +> gespiegelt (`apps/web/src/editor/use-collab-provider.ts:76`, Datenbank +> `dorfteich-page-`; Ist-Aufnahme I-25). Beim Verlassen der Seite +> wird die Kopie gelöscht, sobald der Server synchronisiert hat; bei +> unsynchronisierten Offline-Änderungen bleibt sie **absichtlich** +> stehen, und bei einem Browser-Abbruch läuft die Aufräum-Routine nicht. +> Die Vertraulichkeit dieser Kopie ist Datenträgerschutz des Endgeräts — +> eine Funktion der Plattform (Endgeräteverschlüsselung, Gerätehärtung +> nach den VS-NfD-Regeln der Behörde), nicht der Anwendung. Die Anwendung +> behauptet ausdrücklich **nicht**, keine Spuren auf Endgeräten zu +> hinterlassen. + +### 4.3 Netzabschluss + +**Was die Anwendung tut.** Nichts — und das belegbar auch in der +Gegenrichtung: **Die Anwendung baut keine Verbindungen nach außen auf.** +Jeder ausgehende Aufruf im Code geht an einen internen Sidecar +(`PANDOC_URL`, `GOTENBERG_URL`), an den konfigurierten SMTP-Server oder +an das konfigurierte Backup-Ziel (Ist-Aufnahme I-31, mit vollständiger +Fundortliste). Keine Telemetrie, keine Update-Checks, kein Analytics, +kein Crash-Reporting, keine Link-Vorschauen, kein oEmbed, keine externen +Schriften, Karten oder Skripte; drawio ist vendored, Mermaid und +Excalidraw sind gebündelte Workspace-Pakete, und die CSP +`default-src 'self'` des Web-Tiers würde Nachlader ohnehin blocken. + +**Was die Anwendung bewusst nicht tut.** Keine TLS-Terminierung, keine +Netzsegmentierung, keine Firewall-Funktion, kein VPN. Die Dienste bieten +unverschlüsseltes HTTP/WebSocket auf ihren Compose-internen Ports an. + +**Wer die Funktion erbringt.** Der Betreiber: Netzabschluss, Zonierung +und Zugangskontrolle seines Netzes; TLS-Terminierung am +Reverse-Proxy der Behörde. Der Netzplan mit allen Ports und +Vertrauensgrenzen ist Gegenstand der Sicherheitsdokumentation (#228); +die Vertrauensstellung zum Reverse-Proxy wird in #215 ausgestaltet. + +### 4.4 Authentisierung + +**Zielbild (das diese Erklärung beschreibt).** Authentisierung ist an +den Identity-Provider des Betreibers delegiert (ADR 0021): Anmeldung per +OIDC Authorization Code mit PKCE gegen den IdP der Behörde (#214), +lokale Anmeldung einschließlich Registrierung, Passwort-Reset, PATs und +Feed-Tokens per hartem Schalter `auth.local.enabled = false` vollständig +abgeschaltet (#216), Gruppen-/Rollen-Mapping aus dem IdP (#217). MFA, +Passwort-Richtlinien und Konto-Lebenszyklus sind damit Sache des IdP. + +**Was die Anwendung heute tut — und der heutige Stand entspricht dem +Zielbild noch nicht** (Ist-Aufnahme I-01/I-02, dort als BLOCKIEREND +bewertet): Es existiert nur die lokale Anmeldung +(Benutzername/Passwort, Argon2id) mit eigener serverseitiger +Session-Verwaltung (Session-Id = SHA-256-Hash des Tokens, +`httpOnly`/`sameSite: lax`/`secure`-Cookie, +`apps/api/src/auth/sessions.service.ts`, `auth.guard.ts:52–58`). Eine +OIDC-Anbindung ist vorbereitet (`UserIdentity.provider`, +`apps/api/prisma/schema.prisma:562–577`), aber nicht implementiert; die +lokale Anmeldung ist nicht abschaltbar. **Bis #214/#216 umgesetzt sind, +ist Dorfteich faktisch Träger der Grundfunktion Authentisierung** — die +Delta-Liste (Abschnitt 7) weist das als die wichtigste offene Position +aus. + +**Was die Anwendung dauerhaft behält.** Die _Autorisierung_ (wer darf +welche Inhalte sehen und ändern) bleibt anwendungsseitig — sie ist keine +Grundfunktion nach §52 VSA, sondern Fachlogik: zentrales +default-closed-Berechtigungsmodell mit deny-wins, durchgesetzt über +Guards und abgesichert durch einen Route-Enumeration-Test +(`apps/api/src/permissions/`; Ist-Aufnahme I-33). Die serverseitige +Session-Haltung bleibt als Sitzungsverwaltung _nach_ erfolgter +Authentisierung ebenfalls bestehen (konfigurierbare Lebensdauer und +Idle-Timeout: #190). + +**Wer die Funktion erbringt.** Der Identity-Provider des Betreibers, +einschließlich MFA und aller Credential-Richtlinien. Für Umgebungen mit +Client-Zertifikaten oder vorgelagerter Proxy-Authentisierung ist #215 +der vorgesehene Pfad. + +### 4.5 Integrität (soweit anwendbar) + +Integrität ist in §52 VSA keine eigene Grundfunktion, wird hier aber der +Vollständigkeit halber abgegrenzt, weil sie zwischen Plattform und +Anwendung geteilt ist: + +**Bei der Anwendung** liegt, was nur sie leisten kann (ADR 0019): + +- **Kennzeichnung eingestufter Inhalte** — nur die Anwendung kennt die + Einstufung einer Seite (ADR 0022; Einführung des Metadatums #204/#205, + Aufdruck in allen Ausgabekanälen #206–#212). +- **Integrität der eigenen Nutzdaten**: SHA-256-Prüfsummen auf Anhängen + (#199, heute nicht vorhanden — Ist-Aufnahme I-18) und Hash-Pinning + für Plugin-Bundles statt Code-Signierung (ADR 0025, #232). + +**Bei der Plattform** liegt die Integrität von Betriebssystem, +Container-Runtime, Netz und Datenträgern. Die Reproduzierbarkeit der +Auslieferung (Image-Digests #203, Node-Pin #236, Offline-Build #219) +ist Zulieferung der Anwendung an die Integritätskette des Betreibers, +keine eigene Grundfunktion. + +## 5. Was die Anwendung selbst beiträgt + +Die Sicherheitsleistung der Anwendung besteht — neben der Abwesenheit +der Grundfunktionen — aus vier Eigenschaften, die sie selbst trägt und +belegt: + +1. **Zentrales Berechtigungsmodell**, default-closed, deny-wins, mit + Route-Enumeration-Test; auch Export, Suche, MCP und die Collab-Ebene + laufen über den zentralen `PermissionService` (Ist-Aufnahme I-33, + I-41; unautorisierte Reads antworten 404, Existenz wird versteckt). +2. **Keine ausgehenden Verbindungen** außer Sidecars, SMTP und + Backup-Ziel (Ist-Aufnahme I-31) — die Grundlage der + Airgap-Tauglichkeit, deren empirischer Nachweis als Testlauf #220 + geführt wird. +3. **Kennzeichnung** eingestufter Inhalte in jedem Ausgabekanal + (ADR 0022, #204–#212 — geplant, s. Delta-Liste). +4. **Audit-Trail** für Authentisierungs- und Administrations-Ereignisse + (`audit_log`, `apps/api/src/audit/audit.service.ts`), künftig mit + konfigurierbarer Retention (#196), stabilem Ereigniskatalog für + SIEM-Anbindung (#201) und einem zuschaltbaren Lesetrail für + eingestufte Inhalte (ADR 0023, #222–#225). Logs gehen als + pino-JSON auf stdout mit Redaction von `authorization`/`cookie` + (`apps/api/src/app.module.ts:84–93`); die Weiterleitung ins SIEM ist + bewusst Sache der Container-Runtime des Betreibers. + +## 6. Betreiberpflichten (Übergabe) + +Aus der Arbeitsteilung folgt, was der Betreiber leisten muss. Diese +Liste ist die schriftliche Übergabe; die Referenzkonfiguration und die +Prüf-Checkliste dazu liefert der Härtungsleitfaden (#227): + +| Nr. | Pflicht | Grundfunktion | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | +| B1 | Volume-/Festplattenverschlüsselung der Hosts für Datenbank, Upload-Verzeichnis und Backup-Ablage | Verschlüsselung | +| B2 | TLS-Terminierung vor der Anwendung; kein unverschlüsselter Zugriff außerhalb der Compose-internen Netze | Verschlüsselung | +| B3 | Netzabschluss, Zonierung und Zugangskontrolle; Egress-Blockade bis auf SMTP und ggf. Backup-Ziel | Netzabschluss | +| B4 | Identity-Provider einschließlich MFA, Passwort-Richtlinien und Konto-Lebenszyklus (sobald #214/#216 umgesetzt; bis dahin s. Delta-Liste) | Authentisierung | +| B5 | Endgeräteschutz einschließlich Geräteverschlüsselung — Seiteninhalte liegen als IndexedDB-Kopie auf jedem Endgerät, das sie geöffnet hat (s. 4.2) | Datenträgerschutz | +| B6 | Behandlung und Vernichtung von Datenträgern und Backup-Medien nach den Regeln der Behörde | Datenträgerschutz | +| B7 | Betrieb **einer Instanz je Einstufungsniveau**; keine Mischinstanz | (Betriebsmodell) | +| B8 | Log-Weiterleitung und -Aufbewahrung (stdout → SIEM/Syslog der Behörde) | (Protokollierung) | +| B9 | Betrieb in der VS-NfD-Referenzkonfiguration (#227) und Nachvollzug von Abweichungen | (Konfiguration) | + +## 7. Delta-Liste — wo der heutige Stand dieser Erklärung noch nicht entspricht + +Diese Erklärung beschreibt das Zielbild. Am Code-Stand `fd07f71` bestehen +folgende Abweichungen; jede ist einem Issue zugeordnet, das sie schließt +(Meilensteine `M24`–`M31`, Herleitung `docs/vs-nfd/10-ist-aufnahme.md`): + +| Abweichung vom Zielbild | Befund | Issue | +| ------------------------------------------------------------------------------------------------------------- | ---------------- | --------------------- | +| Lokale Anmeldung ist der einzige und nicht abschaltbare Auth-Pfad — Grundfunktion liegt noch in der Anwendung | I-01, I-02 | #214, #216 | +| IdP-Gruppen-/Rollen-Mapping fehlt | I-01 | #217 | +| Kein Einstufungsmetadatum, kein Aufdruck in irgendeinem Ausgabekanal | I-03, I-04 | #204–#212 | +| Backup-Ziel frei wählbar (keine Allowlist, kein Deploy-Kill-Switch) | I-11 | #192 | +| Ein Secret signiert zwei Token-Zwecke; JWT handgeschrieben statt Bibliothek | I-06, I-07 | #188 | +| CSRF-Origin-Prüfung fail-open bei fehlenden Headern | I-08 | #189 | +| Session 30 Tage gleitend, hart kodiert, ohne Idle-Timeout | I-09 | #190 | +| Feed-Token im Query-Parameter; Feeds nicht abschaltbar | I-10 | #191 | +| Plugins nicht instanzweit abschaltbar | I-19 | #200 | +| Keine Security-Response-Header, CORS-Haltung nicht als Entscheidung dokumentiert | I-16 | #197 | +| Keine Integritäts-Prüfsummen auf Anhängen | I-18 | #199 | +| Kein Plugin-Hash-Pinning | — | #232 | +| `audit_log` ohne Retention; Ereigniskatalog nicht stabil; kein Lesetrail | I-15, I-20, I-21 | #196, #201, #222–#225 | +| Teich-Papierkorb ohne endgültiges Löschen; Papierkorb-Inhalte im Suchindex | I-12, I-14 | #193, #195 | +| Rohdokument-Bytes und Mail-Outbox unbefristet; Slug-Residuum nach Purge | I-22–I-24 | #233–#235 | +| Container-Images nicht per Digest gepinnt, Node-Version nicht gepinnt, Airgap unverifiziert | I-05, I-26, I-28 | #203, #218–#221, #236 | + +Bewusst offene Punkte, die keine Abweichung, sondern akzeptierte +Restrisiken sind (z. B. Seitentitel in Logs und Digest-Mails, +Slug-Residuum falls in #235 so entschieden), führt die Restrisikoliste +(#231) — nicht diese Erklärung. + +## 8. Pflege dieser Erklärung + +- Maßgeblich ist ADR 0019; Abweichungen werden dort aufgelöst, diese + Erklärung folgt dem ADR. +- Jedes Feature, das die Anwendung zum Träger einer Grundfunktion machen + würde, erfordert zuerst eine Änderung von ADR 0019 — und damit dieser + Erklärung. +- Die Delta-Liste (Abschnitt 7) wird mit jedem geschlossenen Issue + gekürzt; die Erklärung ist erst dann uneingeschränkt gültig, wenn die + Delta-Liste leer ist oder alle Restpositionen in der Restrisikoliste + (#231) vom Betreiber gebilligt sind. +- Querbezüge: Härtungsleitfaden (#227), Sicherheitsdokumentation (#228), + Betriebshandbuch (#229), IT-Grundschutz-Zuarbeit (#230).