New instance switch readTrail.enabled, default OFF: read logging is employee monitoring in a works council's eyes — an ordinary instance must not surveil reads. Off means no event is written ANYWHERE (no row, no stdout line, verified by test); the api announces the switch position once per boot, so an eventless trail is never ambiguous — a gap reads as "was off", never "was lost". The written purpose limitation ships as section 7 of the VS-NfD security documentation (#228): what is recorded (no content, no titles, no IPs, no fingerprinting), why (evidence for reads of marked content only — variant A is the technical anchor of the promise), who may read it (Site Admin, API-only), for how long (readTrail.retentionDays, audited pruning), and what it may NOT be used for (no performance or behaviour monitoring). The hardening guide's reference configuration turns the trail on (reference value true) and points to that text; the existing trail suites now enable the switch explicitly. Refs #225. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AUtYMxwTCMHG9mVHnwbFg8
15 KiB
Härtungsleitfaden — Referenzkonfiguration „VS-NfD-Betrieb" (Issue #227)
Zweck: eine benannte Konfiguration, die ein Betreiber als Ganzes übernehmen kann. Jeder Eintrag nennt den exakten Schalter, den Wert und das Warum — wer abweicht, tut es wissentlich. Der Leitfaden macht zugleich die in M1/M2/M4 gebauten Schalter prüfbar.
Pflegeregel (verbindlich): Jeder PR, der einen neuen Instanz- oder Deploy-Schalter einführt, ergänzt diesen Leitfaden im selben PR um dessen Referenzwert. Ein Schalter ohne Leitfaden-Zeile gilt im Review als unvollständig. (Gleiches Muster wie der Ereigniskatalog-Zaun #201.)
Geltungsbereich: Konfiguration der Anwendung. Die Härtung der Plattform
(Betriebssystem, Netz, Reverse Proxy, Datenträger) ist Betreibersache
(Abgrenzungserklärung 40-abgrenzungserklaerung.md — von dort wird
hierher verwiesen; das IT-Grundschutz-Mapping
80-grundschutz-mapping.md nimmt diese Referenzkonfiguration als
Produkt-Beleg).
1 Referenzkonfiguration
1.1 Instanz-Settings (Site-Admin → Einstellungen; Tabelle instance_settings)
Nach jeder Änderung an Instanz-Settings die api neu starten — der Settings-Cache ist in-process (operations.md).
| Setting | Referenzwert | Default | Warum |
|---|---|---|---|
auth.registrationMode |
closed |
open |
Konten entstehen in einer VS-Umgebung nur kontrolliert; Selbstregistrierung öffnet den Nutzerkreis unkontrolliert. |
api.enabled |
false |
false |
Public REST API ist ein zusätzlicher Egress-Kanal; ohne dokumentierten Bedarf bleibt er zu (404 auf allen /api/public/v1-Routen). |
mcp.enabled |
false |
false |
gleiches Argument für den MCP-Endpoint (/api/mcp); unabhängiger Schalter. |
feeds.enabled |
false |
true |
explizit setzen — Atom-Feeds liefern Inhalte an Reader außerhalb der Kontrolle der Instanz (Feed-Token umgehen die Session); Kopien in Feed-Readern sind nicht einholbar (Kopienliste, Sicherheitsdokumentation §5). Schaltet Routen UND Feed-Token-Verwaltung auf 404. |
plugins.enabled |
false |
true |
explizit setzen — kein Fremdcode in der VS-Zone (#200): alle Plugin-Flächen 404, Dropzone quarantänisiert; bestehende Blöcke degradieren zu ihrem deklarierten Text-Fallback. Hash-Pinning ist verschoben (#232, Restrisikoliste) — der Kill-Switch deckt das Risiko für diesen Betriebsmodus vollständig. |
classification.newPageDefault |
vs_nfd |
unclassified |
in einer VS-NfD-Instanz beginnt nichts unmarkiert (#204); die Vererbung (#205) hält den Baum konsistent. |
classification.uploadPolicy |
block |
warn |
Anhänge können die Kennzeichnung im Inhalt nicht tragen (#212) — die Referenzkonfiguration lehnt Uploads auf eingestufte Seiten serverseitig ab (403 classified_upload_blocked, #213) statt nur zu warnen. |
upload.svgPolicy |
reject |
sanitize |
SVG ist aktiver Inhalt; die Sanitisierung ist gut getestet, aber Ablehnen ist die kleinere Angriffsfläche. Abweichung vertretbar, wenn SVG gebraucht wird. |
upload.allowedExtensions |
nur das dienstlich Nötige (z. B. pdf) |
Standardliste | jede zusätzliche Endung vergrößert die Menge nicht prüfbarer Binärformate im Bestand. Bilder sind davon unabhängig immer erlaubt (Magic-Byte-geprüft). |
backup.nextcloud.enabled |
false |
false |
„Backup nur lokal": kein Anwendungs-Upload von Restore-Sets zu Drittdiensten. Fernspiegel regelt ausschließlich die Deploy-Allowlist (1.2). |
trash.retentionDays, audit.retentionDays, conversion.payloadRetentionDays, mail.outboxRetentionDays |
Defaults (30/365/30/30) | ebd. | Aufbewahrung bewusst begrenzt; Verkürzung nach Betreiber-Löschkonzept zulässig (Betriebshandbuch §5). |
readTrail.enabled |
true |
false |
explizit setzen — der Lesetrail (#222–#225) evidenziert Lesezugriffe auf eingestufte Seiten; Default aus, weil Lesebeobachtung mitbestimmungsrelevant ist. Einschalten NUR zusammen mit der Zweckbindung (Sicherheitsdokumentation §7); die api meldet die Schalterstellung beim Start. |
readTrail.dedupWindowMinutes |
Default (5) | 5 |
Dedup-Fenster des Lesetrails (#223): je (Sitzung, Seite, Kanal) ein Ereignis pro Fenster — begrenzt die Ereignisflut einer Live-Sitzung auf ~12/h. Kleiner = feineres Protokoll und mehr Zeilen; Änderung mit dem Zweckbindungs-Dokument (#225) abstimmen. |
readTrail.retentionDays |
Default (365) | 365 |
eigene Aufbewahrung des Lesetrails (#224), bewusst getrennt von audit.retentionDays; Löschläufe sind selbst auditiert (read_trail.pruned). Dauer mit der Zweckbindung (#225) und dem Betreiber-Löschkonzept abstimmen. |
legal.imprint, legal.privacyPolicy |
befüllt | leer | Betreiberpflicht; leere Seiten zeigen einen Warnbanner. |
1.2 Deploy-Konfiguration (.env / Compose — nur Plattformzugriff, bewusst nicht per Admin-UI)
| Variable | Referenzwert | Warum |
|---|---|---|
BACKUP_ALLOWED_TARGETS |
leer lassen oder exakt der eine freigegebene Spiegel-Host | leere Allowlist schaltet ALLE Fernziele hart ab (ADR 0026, #192) — „Backup nur lokal" ist damit deploy-seitig erzwungen und vom Site-Admin nicht aufweichbar (Rollentrennung, Betriebshandbuch §6). |
SESSION_ABSOLUTE_HOURS |
12 (Default 168) |
eine Sitzung überdauert keinen Arbeitstag; Neuanmeldung am nächsten Tag ist der Preis. |
SESSION_IDLE_HOURS |
2 (Default 72) |
unbeaufsichtigte, noch angemeldete Arbeitsplätze fallen schnell zurück auf die Anmeldemaske. |
SMTP_HOST etc. |
unkonfiguriert lassen (oder internes Relay) | ohne SMTP verlassen keinerlei Inhaltstitel die Instanz per Mail (Digest-Restrisiko I-23 entfällt vollständig). Konsequenz ehrlich benannt: dann gibt es keine Verifikations- und Passwort-Reset-Mails — Kontenpflege läuft über den Site-Admin. Wer Mail braucht, nutzt ein internes Relay und akzeptiert I-23 (Restrisikoliste). |
WEB_PORT/API_PORT/COLLAB_PORT |
Defaults (127.0.0.1-gebunden) | Anwendungscontainer sind nie direkt exponiert; einzige Eintrittsstelle ist der Reverse Proxy (Sicherheitsdokumentation §2). |
LOG_LEVEL |
info |
Audit-Zeilen (audit: -Präfix) müssen den Collector erreichen; debug nur zur Störungssuche. |
1.3 Noch nicht verfügbar (Regel: landet hier im selben PR)
| Schalter | Referenzwert (geplant) | Status |
|---|---|---|
auth.local.enabled |
false — lokale Passwort-Auth aus, Anmeldung nur über die Fremdauthentisierung der Behörde |
⏳ kommt mit #216 (M27); bis dahin bleibt lokale Auth der einzige Anmeldeweg und auth.registrationMode=closed + Session-Verkürzung sind die Kompensation. Zeile wird im #216-PR scharfgestellt. |
2 Verifikations-Checkliste
Auf der laufenden Instanz (ersetze HOST); Erwartung jeweils dahinter.
Die vier 404-Prüfungen laufen unauthentifiziert:
curl -s -o /dev/null -w '%{http_code}\n' https://HOST/api/public/v1/ponds # 404 (api.enabled=false)
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://HOST/api/mcp # 404 (mcp.enabled=false)
curl -s -o /dev/null -w '%{http_code}\n' https://HOST/api/v1/public/IRGENDEIN-TEICH/feed.xml # 404 (feeds.enabled=false)
curl -s -o /dev/null -w '%{http_code}\n' https://HOST/api/v1/admin/plugins # 401/404, nie 200 ohne Session
curl -s https://HOST/api/v1/readyz # status ok
Als Site-Admin (UI → Administration bzw. GET /api/v1/admin/settings):
- Registrierung „geschlossen"; neue Seite entsteht mit Kennzeichnung (Einstufung neuer Seiten = VS-NfD); Upload auf eingestufte Seite wird abgelehnt (403).
- Plugin-Verwaltung antwortet 404 (Kill-Switch aktiv).
- Backup-Panel zeigt keine aktiven Fernziele; auf dem Host ist
BACKUP_ALLOWED_TARGETSleer bzw. exakt der freigegebene Spiegel. - Eine Testsitzung läuft nach
SESSION_IDLE_HOURSInaktivität ab. - Kennzeichnungs-Stichprobe: eingestufte Seite zeigt den Aufdruck in
Web, Druckvorschau und PDF-Export (Konventionen: Kommentare auf
Issue #228 bzw.
60-sicherheitsdokumentation.md§3.5).
3 Querbezüge
Abgrenzungserklärung (40-abgrenzungserklaerung.md, verweist hierher);
IT-Grundschutz-Mapping (80-grundschutz-mapping.md, nutzt dieses
Profil als Produkt-Beleg); Betriebshandbuch (70-betriebshandbuch.md,
Installation §1 wendet dieses Profil an); Restrisikoliste
(90-restrisiken.md — Abweichungen von der Referenzkonfiguration
gehören dorthin, wenn sie dauerhaft sind).