BACKUP_ALLOWED_TARGETS (comma-separated destination hosts) constrains where backups may go, enforced twice: the api rejects settings writes and connection tests towards non-allowlisted hosts with admin-visible error codes and resolves a non-allowlisted configured target to null, and the sidecar enforces the same policy at the point of egress for the WebDAV upload and the rsync mirror alike (shared policy helpers in packages/shared/src/backup-target-policy.ts). BREAKING: the empty default disables every remote target - backups stay local only, the VS-NfD reference configuration (ADR 0026). Existing deployments with a remote target must list its host or uploads and mirror stop. The admin UI distinguishes unavailable-by-policy from unconfigured (i18n de+en) and shows the permitted hosts. Refs #192 (ADR 0026) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0168Ph5uBmHm8X28CSVpbpnJ
13 KiB
Maßnahmenplan VS-NfD — Dorfteich (Rev. 2, volle Tiefe)
Ziel: einsetzbar in einer nach VSA freigegebenen Umgebung, keine eigene BSI-Zulassung. Diese Revision zieht die vormals als Roadmap geführten Punkte in die Planung und weist die Terminwirkung aus.
Aufwand in Arbeitstagen (AT) für eine Person mit Claude Code. Erfahrungswert: Implementierung ist der kleinere Teil, Test und Dokumentation der größere. Die Schätzungen enthalten beides.
Stand 2026-07-30: In Meilensteine M24–M31 und Issues #188–#236
überführt (Volltexte und Anlage-Protokoll: 31-issue-entwurf.md,
Befundgrundlage: 10-ist-aufnahme.md). Issue-Nummern stehen an den
Checkboxen, Meilensteine an den Phasen.
Phase 0 — Nicht bauen (Leitplanken)
Diese Dinge machen die Situation schlechter, weil sie die Anwendung zur Trägerin einer Sicherheitsgrundfunktion nach §52 VSA machen würden:
- ❌ Keine eigene Backup-Verschlüsselung — Datenträgerschutz ist Plattformsache
- ❌ Keine Verschlüsselung von Inhalten in DB oder Filesystem
- ❌ Kein eigenes MFA/TOTP, keine eigene Passwort-Policy-Engine
- ❌ Keine neuen Krypto-Primitive
- ❌ Keine anwendungsseitige Trennung von Einstufungsniveaus
Stattdessen: delegieren und dokumentieren.
Phase 1 — Blocker · Summe 30–38 AT
P1-1 Fremdauthentisierung + lokale Auth abschaltbar · 10–12 AT
Meilenstein: M27 — VS-NfD: external authentication
- OIDC Authorization Code + PKCE gegen
UserIdentity.provider(ADR 0007 ausbauen), Keycloak als Referenz-IdP · 5–6 AT · #214 - Alternativpfad vertrauenswürdiger Reverse-Proxy-Header bzw. mTLS- Client-Zertifikat · 2 AT · #215
- Harter Schalter
auth.local.enabled = falseinkl. Reset- und Registrierungs-Flows, PATs und Feed-Tokens · 2 AT · #216 - Gruppen-/Rollen-Mapping aus IdP-Claims auf das Permission-Modell · 2–3 AT · #217
P1-2 Einstufung als First-Class-Metadatum · 14–18 AT
Meilenstein: M26 — VS-NfD: classification metadata
- Enum-Feld
classificationanPage, Migration, Default aus Instance-Setting · 2 AT · #204 - Vererbung im Seitenbaum, Herabstufung nur mit eigenem Recht + Audit · 3 AT · #205
- Durchreichen in alle Ausgabekanäle · 8–12 AT · #206–#212
- Web-Ansicht (Kopf/Fuß) · 1 AT · #206
- Print-CSS (
@media print, Kopf/Fuß je Seite) — fehlt komplett · 1 AT · #207 - PDF via gotenberg (
pdf-html.tsHeader/Footer-Template) · 1 AT · #208 - DOCX/ODT via pandoc (Reference-Doc mit Kopf-/Fußzeile) · 2–3 AT · #209
- Markdown-ZIP (Frontmatter + Aufdruck) · 1 AT · #210
- Atom-Feeds, Public-API, Suchergebnisse, No-JS-Shell · 2–3 AT · #211
- Attachment-Download (Dateiname-Präfix + Begleitdatei) · 1–2 AT · #212
- Warnung/Sperre beim Anhängen an eingestufte Seiten · 1 AT · #213
P1-3 Verifizierter Offline-/Airgap-Pfad · 8–10 AT ⟵ neu aus Roadmap
Meilenstein: M28 — VS-NfD: offline/airgap deployment — das
Digest-Pinning (#203) läuft vorgezogen in M25
Hochgezogen, weil das eine Frage im ersten Behördengespräch ist. „Sollte gehen" ist dort eine schlechtere Antwort als „getestet, hier ist die Anleitung".
- Alle Images auf Digest pinnen (schließt den
gotenberg:8-Punkt ein) · 1 AT · #203 - Mirror-Verfahren in interne Registry dokumentieren · 1 AT · #218
- Build ohne Netz reproduzierbar (pnpm Offline-Store / reine Prebuilt-Images) · 2–3 AT · #219
- Testlauf in netzisolierter Umgebung, Protokoll als Beleg · 2 AT · #220
- Offline-Update-Pfad inkl. Migrationen · 2–3 AT · #221
Phase 2 — Billig, hohe Prüfer-Signalwirkung · Summe 22–28 AT
Meilensteine: M24 — VS-NfD: security quick wins; die nachgezogenen
Punkte (#199, #200, #201, #202) in M25 — VS-NfD: hardening & supply chain
- Schlüsseltrennung
COLLAB_TOKEN_SECRETper HKDF (zweckgebundene Subkeys) — echter Fund, vor allen Features · 1–2 AT · #188 - Eigenbau-HMAC-JWT durch
joseersetzen · +2–3 AT · #188 ⟵ neu aus Roadmap Gebündelt mit der Zeile darüber, weil dieselbe Datei (packages/shared/src/token-crypto.ts). Einzeln wären es 5–6 AT. Achtung: Unsubscribe-Tokens leben lang in versandten Mails → Dual-Verify-Fenster einplanen. - CSRF fail-closed — fehlendes Origin und Referer wird derzeit durchgelassen · 1 AT · #189
- Session-Timeout konfigurierbar, Default deutlich unter 30 Tagen, separates Idle-Timeout · 1–2 AT · #190
- Feed-Token raus aus dem Query-Parameter, alternativ Feeds hart abschaltbar · 2 AT · #191
- Backup-Ziele einschränkbar — Allowlist, WebDAV/rsync per Deploy vollständig deaktivierbar · 2 AT · #192
- Pond-Purge implementieren — getrashte Ponds bleiben ewig liegen · 3 AT · #193
- Orphan-File-Sweep implementieren,
Attachment.deletedAtnutzen oder entfernen · 2 AT · #194 - Papierkorb aus dem Suchindex entfernen statt query-seitig filtern · 2 AT · #195
- Retention-Job für
audit_log· 1 AT · #196 - Security-Header (helmet), CORS explizit restriktiv · 1 AT · #197
- SBOM in CI (CycloneDX/syft) + Lizenzreport als Artefakt · 1–2 AT · #202
deploy/compose/.envprüfen, Beispieldatei statt Realdatei · 0,5 AT · #198- Attachment-Integritätshashes · +2–3 AT · #199 ⟵ neu aus Roadmap SHA-256-Spalte, Berechnung beim Upload, Prüfung beim Download, Backfill-Migration. Nebennutzen: Orphan-Sweep, Dedup, Backup-Verifikation.
- Plugins hart abschaltbar (
plugins.enabled = false) · +2 AT · #200 ⟵ neu Deckt das Risiko „Codeausführung in der VS-Zone" für den Angebotsstand vollständig ab. Hash-Pinning siehe Phase 4. - Syslog/SIEM: Ereigniskatalog · +3–4 AT · #201 ⟵ neu aus Roadmap Der Code-Anteil ist klein (stdout-JSON reicht meist). Wert liegt im stabilen Ereigniskatalog: feste Event-IDs, dokumentierte Semantik und Felder, damit die Behörde SIEM-Regeln schreiben kann.
Phase 3 — Beweissicherung / Lesezugriffe · 8–20 AT ⟵ neu aus Roadmap
Meilenstein: M29 — VS-NfD: read-access audit trail (Variante A)
Der aufwändigste der nachgezogenen Punkte, und der mit dem größten Gestaltungsspielraum. Zwei Varianten:
Variante A (empfohlen): nur eingestufte Inhalte · 8–10 AT
Protokolliert werden Lesezugriffe ausschließlich auf Seiten mit
classification = VS_NFD. Setzt P1-2 voraus.
- Instrumentierung der Lesepfade: Seitenansicht, Public-API-GET, Attachment-Download, Export, No-JS-Shell, Collab-WS-Join · 4 AT · #222
- Dedup-Fenster (eine Sitzung + eine Seite innerhalb N Minuten = ein Ereignis), sonst erzeugt Yjs-Sync eine Ereignisflut · 2 AT · #223
- Getrennte Tabelle mit eigener Retention und Partitionierung · 2 AT · #224
- Abschaltbar, Zweckbindung dokumentiert · 1–2 AT · #225
Vorteil über den Aufwand hinaus: Die Zweckbindung ist sauber begründbar („nur eingestufte Inhalte"), was die Personalrats-Diskussion beim Kunden erheblich entschärft.
Variante B: alle Lesezugriffe · 18–20 AT
Zusätzlich Volumen-, Latenz- und Aufbewahrungsprobleme: gepufferte Schreibung ohne Ereignisverlust (ein verlorenes Ereignis ist eine Lücke in der Beweissicherung), Suchtreffer als eigene Ereignisklasse, Partitionierung zwingend.
Einordnung: Für „einsetzbar in zugelassener Umgebung" ist das kein zwingendes Produktmerkmal — Beweissicherung kann die Plattform erbringen. In der Praxis kann Plattform-Logging aber nicht beantworten, welche eingestufte Seite gelesen wurde (Proxy-Logs kennen URLs, nicht Einstufungen). In Leistungsbeschreibungen taucht das als Muss-Kriterium auf. Deshalb rein — aber in Variante A.
Phase 4 — Verbleibende Roadmap
Meilenstein: M31 — VS-NfD: backlog
Nur noch ein Punkt bleibt draußen:
- Plugin-Allowlist mit Hash-Pinning · 8–10 AT · #232
Manifest mit SHA-256, Allowlist in
instance_settings, Prüfung beim Laden, Admin-UI. Bleibt zurückgestellt, weil Phase 2 mit der harten Abschaltung das Risiko bereits schließt — und weil echte Code-Signierung ohne juristische Person ohnehin nicht verfügbar ist. Hash-Pinning ist die richtige Antwort, aber nicht die dringendste.
Phase 5 — Dokumentation · 15–20 AT (vorher 12–15)
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
Anwendung nicht erbringt und wem sie zufallen. Wichtigstes
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
- Sicherheitsdokumentation: Architektur, Datenflüsse, Netzplan, Ports/Dienste, Vertrauensgrenzen · 4 AT · #228
- Betriebshandbuch: Installation (inkl. Airgap), Update, Backup/Restore, Löschung und Vernichtung, Rollentrennung · 4–5 AT · #229
- Zuarbeit IT-Grundschutz APP.3.1 und CON.11.1, je Anforderung „Produkt / Betreiber / nicht anwendbar" · 3–4 AT · #230
- Restrisikoliste mit bewusst offenen Punkten · 1 AT · #231
Terminwirkung
| Block | vorher | Rev. 2 |
|---|---|---|
| Phase 1 Blocker | 22–28 AT | 30–38 AT |
| Phase 2 Billigblock | 15–18 AT | 22–28 AT |
| Phase 3 Beweissicherung | — | 8–10 AT (Var. A) |
| Phase 5 Dokumentation | 12–15 AT | 15–20 AT |
| Summe | 49–61 AT | 75–96 AT |
Bei 4 produktiven Tagen pro Woche:
- vorher: ca. 3–3,5 Monate
- Rev. 2 mit Variante A: ca. 4,5–5,5 Monate
- Rev. 2 mit Variante B: ca. 5,5–6,5 Monate
- Plus Phase 4 (Hash-Pinning): weitere ~0,5 Monate
Der Zuwachs von ~26–35 AT verteilt sich zu etwa zwei Dritteln auf Beweissicherung und Airgap-Verifikation. Beides sind Punkte, nach denen gefragt wird — nicht Punkte, die man erklären muss.
Empfehlung zur Reihenfolge: Termin für den Angebotsstand nicht verschieben. Phase 5 und der Billigblock sind nach ca. 3 Monaten fertig — das genügt, um Gespräche zu führen. Phase 1-3 laufen dahinter weiter. Ein Angebot mit belegter Dokumentation und laufender Umsetzung ist besser als ein fertiges Produkt ohne Gesprächspartner.
Zu klärende Punkte aus der Ist-Aufnahme
- drawio-Plugin: geklärt — vendored unter
packages/plugins/drawio/vendor/, lädt keine externe Editor-URL; kein Ausschlusskriterium (Ist-Aufnahme I-40) - Fließen Labels heute in Exporte? Nein —
export.service.tslädtlabelIdsnur für die Permission-Filterung (Ist-Aufnahme I-03a) - Was bricht ohne Internetzugang? → wird durch den Testlauf #220 beantwortet (Ist-Aufnahme I-28)
- MCP-Gate-Duplikat: divergiert nicht — nutzt den zentralen
PermissionService, eigenständig sind nur die Schalter (Ist-Aufnahme I-33) - Collab-WebSocket: WS-Ebene prüft nur das Token, aber Tokens leben
60 s und Grant-Entzug schließt Verbindungen per
pg_notify; Randbedingung für #222 (Ist-Aufnahme I-41)
Ergänzungen aus der Ist-Aufnahme (2026-07-30)
Befunde der nachgezogenen 10-ist-aufnahme.md, die in diesem Plan
fehlten — als Issues angelegt:
- Conversion-Job-Payloads prunen — Rohbytes jedes Im-/Exports liegen
unbefristet in
conversion_jobs· 2 AT · #233 (M24, I-22) - Retention für
mail_outbox— Digest-Mails tragen Seitentitel · 1 AT · #234 (M24, I-23) page_links.target_slug-Residuum nach Purge entscheiden · 0,5 AT · #235 (M24, I-24)- Node-Version pinnen — Voraussetzung für #219 · 0,5 AT · #236 (M25, I-26)
Ohne eigenes Issue: IndexedDB-Kopie auf Endgeräten (I-25) — als Akzeptanzkriterium in #226 (Abgrenzungserklärung) und #231 (Restrisikoliste) verankert.
Vorhandene Stärken (im Angebot nach vorne stellen)
Nicht ausbauen, sondern belegen:
- Keine Telemetrie, keine Update-Checks, keine CDNs, kein Runtime-Nachladen,
Fonts self-hosted, CSP
default-src 'self'— hier scheitern die meisten Konkurrenzprodukte - Zentrales, default-closed Berechtigungsmodell mit deny-wins und Route-Enumeration-Test — ein prüfbares Artefakt
- Volltextsuche in Postgres statt externer Suchmaschine
- Single-Tenant — passt zur empfohlenen Betriebsform „eine Instanz pro Einstufungsniveau"
- Public-API und MCP zur Laufzeit hart abschaltbar, Default aus
- Open Source unter MIT — Quelloffenheit ist im Prüfprozess ein Vorteil
- Keine Verschlüsselung im Code = korrekte Architektur, nicht fehlende Funktion. So argumentieren.