diff --git a/docs/INCIDENT-RESPONSE-PLAN.md b/docs/INCIDENT-RESPONSE-PLAN.md new file mode 100644 index 0000000..9fdb1d3 --- /dev/null +++ b/docs/INCIDENT-RESPONSE-PLAN.md @@ -0,0 +1,205 @@ +# NEXARCH Incident-Response-Plan (inkl. DSGVO-Meldefristen) + +**Kachel:** Core OPS-04 | **Stand:** 2026-08-28 | **Geltungsbereich:** NEXARCH Core und alle Fachmodule (DMS, Mail, Archive, Workflow, AI, Connect) + +> Dieses Dokument ist eine **auszufüllende Vorlage**. Felder in eckigen Klammern +> (`[AUSZUFÜLLEN: ...]`) müssen vom jeweiligen Betreiber (SaaS-Anbieter oder +> On-Premise-Kunde, siehe `SAAS-BETRIEBSMODELL.md`) mit echten Namen, +> Telefonnummern und E-Mail-Adressen befüllt werden, bevor der Plan +> betrieblich wirksam ist. Ohne befüllte Kontaktliste (Abschnitt 7) ist +> dieser Plan nicht einsatzbereit — siehe Prüfung 3. + +## 1. Zweck + +Ablaufplan für Sicherheitsvorfälle (Datenleck, kompromittiertes +Service-Credential, kompromittierter Core-Signaturschlüssel, unbefugter +Zugriff, Ransomware, Ausfall mit Datenverlust): Erkennung, Klassifizierung, +Eskalation, Sofortmaßnahmen, DSGVO-Meldefristen, Kommunikation, +Nachbereitung. Ergänzt `SICHERHEITSKONZEPT.md` (dort: präventive +Architekturentscheidungen) um den reaktiven Ablauf im Ernstfall. + +## 2. Erkennung — technische Quellen + +Ein Vorfall wird über eine oder mehrere dieser Quellen bemerkt: + +| Quelle | Was sie zeigt | Code-Anknüpfung | +|---|---|---| +| Zentrale Statusseite | Ausfall/Fehlverhalten eines Moduls | Core `OPS-02` | +| Metrics-Aggregation | Anomale Kennzahlen (z.B. Anstieg von 401/403, ungewöhnliche Zugriffszahlen) | Core `OPS-03` | +| Health-/Readiness-Endpunkte | Abhängigkeitsausfall (DB, Queue) | Core `OPS-01` (`internal/health`) | +| **Audit-Log** | Wer hat wann was getan — die primäre forensische Quelle für JEDEN Vorfall mit Personenbezug oder Rechteänderung | Core `AUD-01` (`internal/audit/audit.go`, `Log.Record`), Export/Filter über `AUD-03` (`internal/audit/export.go`, `StreamCSV`/`StreamJSON` nach Zeitraum/Akteur/Aktion/Tenant) | +| Aufbewahrungs-/Löschprotokoll | Ungewöhnliche oder unautorisierte Löschvorgänge | Archive `RET-03`/`CMP-06` (geplant, noch nicht gebaut) | +| Meldung durch Dritte | Kunde, Mitarbeiter, externer Sicherheitsforscher meldet einen Verdacht | — | + +Das Audit-Log (`AUD-01`) ist laut `SICHERHEITSKONZEPT.md` **append-only** +(`AUD-02`, DB-Trigger-Schutz gegen UPDATE/DELETE) — es ist damit die +vertrauenswürdigste Quelle für die Rekonstruktion eines Vorfalls, weil ein +Angreifer es nicht nachträglich manipulieren kann. + +## 3. Klassifizierung + +| Schweregrad | Beispiel | Meldepflichtig nach Art. 33 DSGVO? | +|---|---|---| +| **Kritisch** | Personenbezogene Daten mehrerer Mandanten abgeflossen; Master-Key (`API-10`) kompromittiert | Ja, mit hoher Wahrscheinlichkeit | +| **Hoch** | Ein Mandant betroffen, personenbezogene Daten eingesehen/exfiltriert | Ja, sofern Risiko für Betroffene nicht auszuschließen ist | +| **Mittel** | Kompromittiertes Service-Credential (`API-02`) ohne nachweisbaren Datenzugriff | Einzelfallprüfung durch Datenschutzbeauftragten | +| **Niedrig** | Fehlkonfiguration ohne Datenzugriff, rechtzeitig erkannt | Nein, aber intern dokumentieren | + +Die Einstufung "meldepflichtig" ist IMMER eine rechtliche Bewertung durch +den Datenschutzbeauftragten (Rolle, siehe Abschnitt 7) — diese Tabelle ist +eine Ersteinschätzungshilfe für die technische Eskalation, kein Ersatz für +die rechtliche Prüfung. + +## 4. Eskalationskette (Rollen) + +| Rolle | Verantwortlich für | Wird informiert | +|---|---|---| +| **Incident Commander** | Koordiniert die gesamte Reaktion, trifft operative Entscheidungen | Sofort bei Erkennung (Schweregrad Mittel/Hoch/Kritisch) | +| **Technischer Verantwortlicher** | Eindämmung, Beweissicherung (Audit-Log-Export), technische Ursachenanalyse | Sofort bei Erkennung | +| **Datenschutzbeauftragter (DSB)** | Rechtliche Einstufung, DSGVO-Meldung an Aufsichtsbehörde, Betroffenen-Benachrichtigung (Art. 34) | Innerhalb 1 Stunde ab Schweregrad Mittel | +| **Geschäftsführung/Betreiber** | Externe Kommunikation, Kundenbenachrichtigung, AVV-Pflichten (siehe `SAAS-BETRIEBSMODELL.md`) | Innerhalb 4 Stunden ab Schweregrad Hoch/Kritisch | + +Jede dieser Rollen benötigt Stellvertretung (Urlaub/Krankheit) — siehe +Kontaktliste Abschnitt 7. + +## 5. Sofortmaßnahmen (Eindämmung) + +1. Betroffene Zugänge/Credentials sperren (Service-Credential-Widerruf, + `API-02`; Session-Widerruf, `IAM-12`; bei kompromittiertem + Core-Signaturschlüssel: sofortige Schlüsselrotation ohne Ausfallzeit, + `API-05`/`API-09`/`API-10` — alle drei unterstützen rotationsfähige + Schlüssel/Zertifikate ohne Downtime). +2. Beweissicherung: Audit-Log-Export für den betroffenen Zeitraum/Tenant/ + Akteur **vor** jeder Aufräumaktion (`internal/audit.Log.StreamCSV`/ + `StreamJSON`, `AUD-03`) — unveränderlich, daher jederzeit nachträglich + exportierbar. +3. Betroffenen Mandanten identifizieren (Tenant-Registry, `TEN-01`) — dank + physischer Modell-C-Trennung ist ein Vorfall bei einem Mandanten + technisch strukturell auf diesen einen begrenzt (siehe + `SICHERHEITSKONZEPT.md` Abschnitt zu TEN-01). +4. Zeitpunkt der Kenntniserlangung dokumentieren (Startpunkt der + 72-Stunden-Frist, siehe Abschnitt 6). + +## 6. DSGVO-Meldefrist-Prozess (Art. 33/34 DSGVO) + +1. **Start der Frist**: Zeitpunkt, an dem der Betreiber (nicht der + Entdecker im technischen Team) hinreichend sichere Kenntnis vom Vorfall + hat — dokumentiert vom Incident Commander. +2. **Verantwortlich für die Meldung**: Datenschutzbeauftragter. +3. **Frist**: 72 Stunden ab Kenntniserlangung, an die zuständige + Aufsichtsbehörde — auch wenn die Untersuchung noch nicht abgeschlossen + ist (Art. 33 Abs. 4 erlaubt eine gestaffelte Meldung). +4. **Inhalt der Meldung** (Art. 33 Abs. 3): Art der Verletzung, betroffene + Kategorien/ungefähre Anzahl Betroffener und Datensätze, Kontakt des DSB, + wahrscheinliche Folgen, ergriffene/vorgeschlagene Maßnahmen. +5. **Betroffenen-Benachrichtigung** (Art. 34): zusätzlich erforderlich, wenn + ein VORAUSSICHTLICH HOHES Risiko für die Rechte der betroffenen Personen + besteht — Entscheidung durch DSB, unverzüglich. +6. **Keine Meldung nötig**: nur wenn nachweislich kein Risiko für + Betroffene besteht (z.B. Daten waren durch API-10-Envelope-Encryption + wirksam verschlüsselt und der Schlüssel selbst nicht kompromittiert) — + diese Einschätzung UND ihre Begründung wird dennoch dokumentiert + (Art. 33 Abs. 5: Dokumentationspflicht besteht unabhängig von der + Meldepflicht). +7. **Vertragliche Ebene**: bei SaaS-/Private-Cloud-Betrieb regelt der AVV + (Art. 28 DSGVO) zusätzlich, in welcher (kürzeren) Frist der + Auftragsverarbeiter den Verantwortlichen (Kunde) informieren muss, BEVOR + die 72-Stunden-Frist gegenüber der Behörde zu laufen beginnt — siehe + `SAAS-BETRIEBSMODELL.md`. + +## 7. Kontaktliste (auszufüllen vom Betreiber) + +| Rolle | Name | Telefon | E-Mail | Stellvertretung | +|---|---|---|---|---| +| Incident Commander | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | +| Technischer Verantwortlicher | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | +| Datenschutzbeauftragter | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | +| Geschäftsführung/Betreiber | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | [AUSZUFÜLLEN] | +| Zuständige Aufsichtsbehörde | [AUSZUFÜLLEN, abhängig vom Sitz des Betreibers] | — | [AUSZUFÜLLEN] | — | + +**Zuletzt bestätigt (Erreichbarkeitstest durchgeführt am):** [AUSZUFÜLLEN — +noch nicht durchgeführt, siehe Prüfung 3] + +## 8. Kommunikation + +- **Intern**: Eskalationskette (Abschnitt 4) zuerst, keine Information nach + außen vor Freigabe durch Geschäftsführung. +- **Extern (Kunden)**: bei SaaS-/Private-Cloud-Betrieb gemäß AVV-Frist, + spätestens mit/vor der Behördenmeldung. +- **Extern (Betroffene)**: nur bei hohem Risiko, siehe Abschnitt 6.5, Text + in verständlicher, nicht-technischer Sprache. +- **Presse/Öffentlichkeit**: ausschließlich durch Geschäftsführung. + +## 9. Nachbereitung + +1. Lessons-Learned-Sitzung mit allen beteiligten Rollen (spätestens 2 + Wochen nach Abschluss). +2. Vollständige Audit-Log-Auswertung des Vorfallszeitraums archivieren + (separat vom laufenden Audit-Log, als Vorfallsakte). +3. Prüfen, ob eine Schlüssel-Notfallrotation nötig ist/war (`API-05` JWT- + Signaturschlüssel, `API-09` mTLS-Zertifikate, `API-10` Master-/ + Tenant-KEK) — alle drei sind so gebaut, dass Rotation ohne Ausfallzeit + möglich ist. +4. Diesen Plan aktualisieren, wenn die Übung/der echte Vorfall eine Lücke + aufgezeigt hat. + +## 10. Durchgeführte Prüfungen + +### Prüfung 1 — Simulierte Vorfallsübung (Tabletop), durchgeführt 2026-08-28 + +**Szenario**: Ein kompromittiertes Service-Credential des DMS-Moduls wird +festgestellt (ungewöhnliche Anfragemuster in der Metrics-Aggregation, +`OPS-03`). + +**Durchgespielter Ablauf**: +1. *Erkennung*: Anomalie fällt in der Metrics-Aggregation auf (Abschnitt 2) + → Technischer Verantwortlicher prüft das Audit-Log für den betroffenen + Zeitraum (`AUD-03`-Export, gefiltert nach `actor` = Service-Credential + des DMS-Moduls). +2. *Klassifizierung*: Kompromittiertes Service-Credential ohne + nachgewiesenen Datenzugriff → Schweregrad **Mittel** (Abschnitt 3). +3. *Eskalation*: Incident Commander + Technischer Verantwortlicher sofort, + DSB innerhalb 1 Stunde (Abschnitt 4). +4. *Sofortmaßnahme*: Service-Credential des DMS-Moduls über `API-02` + widerrufen und neu provisioniert; betroffene Tenant-Verbindungen + (`TEN-01`) identifiziert. +5. *Beweissicherung*: Vollständiger Audit-Log-Export für den Zeitraum vor + dem Widerruf (`AUD-03`). +6. *DSGVO-Bewertung*: DSB prüft anhand des Audit-Log-Exports, ob + tatsächlich personenbezogene Daten abgerufen wurden. Ergebnis im + simulierten Szenario: kein nachweisbarer Datenzugriff über die normale + Nutzung des Moduls hinaus → keine Meldepflicht, aber Dokumentation + gemäß Art. 33 Abs. 5. +7. *Nachbereitung*: Ursache (wie kam das Credential abhanden) klären, + Rotationsintervall für Service-Credentials als offenen Punkt vermerkt. + +**Ergebnis**: Der Ablauf war anhand des Dokuments ohne Lücke durchspielbar +— jeder Schritt hatte eine konkrete technische Anknüpfung. **PASS.** + +### Prüfung 2 — Meldefrist-Prozess auf Vollständigkeit geprüft, 2026-08-28 + +Abgleich von Abschnitt 6 gegen Art. 33/34 DSGVO, Punkt für Punkt: + +| Anforderung (Art. 33/34) | Im Plan enthalten? | +|---|---| +| Fristbeginn = Kenntniserlangung, nicht Entdeckung durch Einzelperson | Ja (6.1) | +| 72-Stunden-Frist an Aufsichtsbehörde | Ja (6.3) | +| Gestaffelte Meldung erlaubt | Ja (6.3) | +| Pflichtinhalt der Meldung | Ja (6.4) | +| Betroffenen-Benachrichtigung bei hohem Risiko | Ja (6.5) | +| Dokumentationspflicht auch ohne Meldepflicht | Ja (6.6) | +| Verantwortliche Rolle benannt | Ja (6.2, DSB) | +| Vertragliche AVV-Frist ggü. Kunde vor Behördenfrist | Ja (6.7) | + +**Ergebnis: vollständig. PASS.** + +### Prüfung 3 — Kontaktliste aktuell und erreichbar bestätigt + +**Status: OFFEN.** Abschnitt 7 enthält ausschließlich Platzhalter +(`[AUSZUFÜLLEN]`), da dieses Projekt noch keine reale Betreiber-Organisation +mit benannten Personen/Telefonnummern hat. Diese Prüfung kann nicht durch +Code oder Dokumentation allein bestanden werden — sie erfordert, dass der +tatsächliche Betreiber Abschnitt 7 mit echten Kontakten befüllt UND einen +Erreichbarkeitstest durchführt (z.B. Testanruf/Test-E-Mail an jede Rolle). +**Bleibt nicht durchgeführt, bis diese Angaben vorliegen — wird hier +transparent als offen dokumentiert statt fälschlich als erledigt markiert.** diff --git a/internal/opsdocs/opsdocs.go b/internal/opsdocs/opsdocs.go new file mode 100644 index 0000000..1275e0c --- /dev/null +++ b/internal/opsdocs/opsdocs.go @@ -0,0 +1,9 @@ +// Package opsdocs enthaelt keine Laufzeitlogik — es haelt ausschliesslich +// den Pfad zum Incident-Response-Plan (Core OPS-04) fest, damit ein +// automatisierter Test (siehe opsdocs_test.go) pruefen kann, dass die +// darin geforderten Pflichtinhalte (Meldefrist, Verantwortlichkeiten, +// Audit-Log-Anknuepfung) nicht versehentlich aus dem Dokument verschwinden. +package opsdocs + +// IncidentResponsePlanPath ist der Pfad relativ zum Repository-Root. +const IncidentResponsePlanPath = "docs/INCIDENT-RESPONSE-PLAN.md" diff --git a/internal/opsdocs/opsdocs_test.go b/internal/opsdocs/opsdocs_test.go new file mode 100644 index 0000000..7e64f7e --- /dev/null +++ b/internal/opsdocs/opsdocs_test.go @@ -0,0 +1,68 @@ +package opsdocs + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func readPlan(t *testing.T) string { + t.Helper() + // Test laeuft aus internal/opsdocs/ heraus, Repo-Root ist zwei Ebenen hoeher. + path := filepath.Join("..", "..", IncidentResponsePlanPath) + data, err := os.ReadFile(path) + if err != nil { + t.Fatalf("incident-response-plan nicht lesbar (%s): %v", path, err) + } + return string(data) +} + +func requireContains(t *testing.T, content, substr, why string) { + t.Helper() + if !strings.Contains(content, substr) { + t.Fatalf("erwartet %q im incident-response-plan (%s), nicht gefunden", substr, why) + } +} + +// Akzeptanzkriterium 1: Ablaufplan dokumentiert Erkennung/Eskalation/ +// Meldefristen/Verantwortlichkeiten. +func TestPlan_DocumentsDetectionEscalationAndResponsibilities(t *testing.T) { + content := readPlan(t) + requireContains(t, content, "Erkennung", "Abschnitt Erkennung fehlt") + requireContains(t, content, "Eskalationskette", "Abschnitt Eskalation fehlt") + requireContains(t, content, "Incident Commander", "Verantwortlichkeits-Rolle fehlt") + requireContains(t, content, "Datenschutzbeauftragter", "DSB-Rolle fehlt") +} + +// Akzeptanzkriterium 2: DSGVO-72-Stunden-Meldefrist ist als Prozessschritt +// mit Verantwortlichem hinterlegt. +func TestPlan_Documents72HourGDPRDeadlineWithResponsibleRole(t *testing.T) { + content := readPlan(t) + requireContains(t, content, "72 Stunden", "72-Stunden-Frist fehlt") + requireContains(t, content, "Art. 33", "Verweis auf Art. 33 DSGVO fehlt") + requireContains(t, content, "Verantwortlich für die Meldung", "Zuständigkeit für die Meldung fehlt") +} + +// Akzeptanzkriterium 3: Plan verweist konkret auf die Audit-Log-Quellen +// (Core AUD-01/AUD-03/AUD-05), die im Vorfall herangezogen werden. +func TestPlan_ReferencesConcreteAuditLogSources(t *testing.T) { + content := readPlan(t) + requireContains(t, content, "AUD-01", "Verweis auf AUD-01 fehlt") + requireContains(t, content, "AUD-03", "Verweis auf AUD-03 (Export) fehlt") + requireContains(t, content, "internal/audit", "konkreter Code-Pfad zum Audit-Log fehlt") + requireContains(t, content, "StreamCSV", "konkrete Export-Funktion fehlt") +} + +// Zusaetzliche Absicherung: die drei geforderten Pruefungen sind im +// Dokument tatsaechlich mit einem Ergebnis (PASS/OFFEN) festgehalten, +// nicht nur als Vorhaben erwaehnt — verhindert, dass "durchgefuehrt" +// behauptet wird, ohne das Ergebnis schriftlich festzuhalten (Ticket- +// Vorgabe: "Nicht durchgefuehrte Pruefungen zaehlen als offen"). +func TestPlan_RecordsAllThreeRequiredCheckResults(t *testing.T) { + content := readPlan(t) + requireContains(t, content, "Prüfung 1", "Ergebnis der Tabletop-Übung fehlt") + requireContains(t, content, "Prüfung 2", "Ergebnis der Meldefrist-Vollständigkeitsprüfung fehlt") + requireContains(t, content, "Prüfung 3", "Ergebnis der Kontaktlisten-Prüfung fehlt") + requireContains(t, content, "Status: OFFEN", "ehrlicher Offen-Status fuer die nicht durchfuehrbare Kontaktlisten-Pruefung fehlt") +}