ProofedMesh/docs/adr/0003-pii-retention-policy.md

6.2 KiB
Raw Blame History

ADR-0003: PII-Retention-Richtlinie

  • Status: accepted
  • Datum: 2026-10-25
  • Entscheider: CEO (A. Leinen), CTO
  • Betroffene Dokumente: docs/architecture/v1.1.md Abschnitte 8.1, 8.2, 8.4

Kontext und Problemstellung

Der PII-Store (siehe docs/architecture/v1.1.md 8.4) hält personenbezogene Daten (Belege, kanonische Reisekostendaten, Query-Ergebnisse mit Namen und Zuordnungen) getrennt vom Evidence Store. Dieser muss zwei Anforderungen gleichzeitig erfüllen:

  1. DSGVO Art. 17 „Recht auf Löschung" — Betroffene müssen ihre personenbezogenen Daten löschen lassen können.
  2. Kryptografischer Nachweis einer unverfälschten Kommunikation während eines sinnvollen Zeitraums — Attestierungen müssen Nachkontrollen gegen den Originalinhalt erlauben, solange ein berechtigtes Interesse besteht.

Festzulegen: wie lange halten wir PII-Daten auf, wann wird gelöscht, wie wird eine vorzeitige Löschung ausgeführt, und wie wird die Löschung ihrerseits nachweisbar?

Entscheidungsoptionen

  • Option A — Default-Retention 1 Jahr, mit konfigurierbarer Verkürzung pro Prozess-Typ. Nach Ablauf automatische Cryptographic Erasure. Betroffene können jederzeit vorzeitige Löschung beantragen.
  • Option B — Default-Retention 90 Tage — kürzer, aber möglicherweise zu kurz für realistische Nachprüfungen (Jahresabschluss, interne Audits).
  • Option C — Default-Retention 3 Jahre — richtet sich an GoBD-Fristen aus; widerspricht aber der grundsätzlichen Entscheidung „kein rechtssicheres Archiv" (ADR-0001 bzw. docs/architecture/v1.1.md 8.1).

Entscheidung

Option A.

Konkrete Regeln:

Default-Retention

  • 1 Jahr ab letzter Workflow-Aktivität (letzte Attestierung, Decision oder Deletion-Anfrage, je nachdem was später ist).
  • Konfigurierbar pro Prozess-Typ (workflow_type.retention_days) und pro Senke/Datenquelle (sinks.retention_days, data_sources.retention_days), jeweils als Default-Override.
  • Minimum: 30 Tage (unter diesem Wert ist kein Review mehr sinnvoll). Maximum: 2 Jahre (darüber kippt die „kein rechtssicheres Archiv"-Positionierung).

Automatische Löschung

  • Cron-Job pii-retention-sweeper läuft täglich 03:30 UTC.
  • Für jeden Workflow mit last_activity_at + retention_days < NOW():
    1. Alle PII-Objekte des Workflows aus dem S3-Bucket entfernen.
    2. Alle Envelope-Keys im OpenBao Transit vergessen (Cryptographic Erasure).
    3. Eine signierte PII-Deletion-Attestierung in den Transparency Log schreiben (predicateType=https://basicstack.de/attestations/pii_deletion/v1).
    4. Workflow-Status auf pii_purged setzen; der Evidence-Store-Eintrag bleibt bestehen.

Vorzeitige Löschung auf Antrag

  • Endpunkt DELETE /pii/<workflow_id> am PII-Mediator mit Admin-Auth.
  • Zusätzlich: Endpunkt DELETE /pii/by-subject/<user_sub> löscht alle Workflows, in denen der angegebene Benutzer original_user.sub ist. Für DSGVO-Antragsabwicklung.
  • Ablauf identisch zur automatischen Löschung (Schritte 1–4 oben).

Löschung-vs-Signaturkette

  • Signaturkette im Evidence Store wird nicht angerührt.
  • Hashes in Attestierungen bleiben prüfbar; Nachkontrolle gegen den Inhalt ist nach Löschung nicht mehr möglich — das ist der bewusste Trade-off.
  • Verification Service markiert Verifikationsantworten, deren materials-Hashes nicht mehr im PII-Store auflösbar sind, mit content_check: "pii_purged" (statt pii_matched).

PII-Deletion-Attestierung (neue predicate)

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    { "name": "pii/<workflow_id>", "digest": { "sha256": "<hash of deleted objects manifest>" } }
  ],
  "predicateType": "https://basicstack.de/attestations/pii_deletion/v1",
  "predicate": {
    "workflow_id": "WF-...",
    "deletion_reason": "retention_policy_expired" | "subject_erasure_request" | "operator_action",
    "deleted_objects": [ { "pii_store_ref": "pii://...", "content_hash_before_delete": "sha256:..." } ],
    "requested_by": { "iss": "...", "sub": "..." },
    "deleted_at": "YYYY-MM-DDTHH:MM:SSZ",
    "retention_policy_version": "pii-retention-v1"
  }
}

Signiert vom PII-Mediator-Adapter (agent_id = "pii-mediator"), landet im Transparency Log.

Begründung

  • 1 Jahr trifft den Sweet Spot. Länger als ein interner Audit-Zyklus (meist quartalsweise); kurz genug, dass wir nicht in GoBD-Territorium rutschen; akzeptabel für Betroffene (vgl. gängige SaaS-Retention bei Log-Daten).
  • Pro-Typ-Konfigurierbarkeit erlaubt es, z.B. Debugging-Workflows auf 30 Tage und besonders sensible Workflows auf das Minimum zu drücken.
  • Deletion-Attestierung schließt die Nachweislücke „zu diesem Workflow waren PII-Daten vorhanden und wurden am X auf Antrag Y gelöscht". Ohne diese Attestierung wäre Löschen und Nichthaben nachträglich nicht unterscheidbar.
  • Automatische Löschung über Cron, nicht erst auf Zugriff — damit garantieren wir, dass PII tatsächlich verschwindet und nicht erst durch Zufall irgendwann einmal.

Konsequenzen

Positive

  • DSGVO-Anfragen können technisch binnen Minuten abgearbeitet werden (vorzeitiger DELETE).
  • Datenwachstum im PII-Store ist bounded.
  • Deletion-Nachweis selbst ist kryptografisch (nicht nur Audit-Log).

Negative / Trade-offs

  • Fehlbedienung oder Scheduler-Bug kann Daten einen Tag zu früh löschen — Verification-Antworten dieser Workflows werden dann content_check: "pii_purged". Mitigation: Dry-Run-Modus im Sweeper mit Warnung an Operator, bevor der echte Lauf greift.
  • OpenBao-Transit-Key-Vergessen ist unwiderruflich — Backup-Strategie muss sicherstellen, dass vergessene Keys nicht aus einem alten Backup zurückkehren. Siehe Folgearbeit.

Folgearbeiten / Open Points

  • Policy für Backup-Rotation: OpenBao-Snapshots dürfen nicht länger als retention_days + 7 aufgehoben werden, damit vergessene Keys nicht wiederauftauchen.
  • Datenschutz-Dokument (für Benutzer-Information und AV-Vertrag) muss die 1-Jahres-Retention explizit benennen.
  • Monitoring: tägliche Metrik für Anzahl gelöschter Workflows + Alert, wenn Sweeper nicht läuft.
  • docs/architecture/v1.1.md Abschnitte 8.1, 8.2, 8.4
  • DSGVO Art. 17
  • OpenBao Transit docs (Key Rotation + Delete)