ProofedMesh/docs/architecture/v1.1.md
CTO Agent 2181225022
All checks were successful
validate / Rego (opa fmt + opa test) (push) Successful in 13s
validate / JSON Schema (ajv) (push) Successful in 16s
docs(architecture): add section 7.2a for per-line project allocations (expense.canonical v1.1.0)
2026-10-25 16:20:38 +00:00

47 KiB
Raw Blame History

Technische Zielarchitektur: Vertrauenswürdige Kommunikation zwischen Menschen, KI-Agenten und beliebigen Prozess-Senken

Status: Architekturvorschlag V1.1 (aktive Diskussionsgrundlage) Vorgänger: v1.0.md — ursprünglicher Entwurf (unverändert archiviert) Letzte Änderung: Paralleler Lesepfad eingezogen — Agenten holen Vorab-Informationen aus registrierten Datenquellen über das gleiche Trust-Modell wie bei Senken (Query Attestations, Session Scope Tokens). Erster produktiver Rollout: eigene DB-App als Quelle UND Senke.

Diese Lösung wird als Identity-Aware Agent Messaging Platform konzipiert: eine Plattform, die Benutzerfreigaben, delegierte Berechtigungen und sämtliche Verarbeitungsschritte kryptografisch nachvollziehbar macht — inkl. der Lesezugriffe, die ein Agent vor der eigentlichen Freigabe durchführt, um dem Benutzer sinnvolle Vorschläge zu machen.

Die zentrale Designentscheidung lautet:

Der Benutzer autorisiert den ursprünglichen Geschäftsinhalt. Jeder Agent attestiert anschließend seine eigene Verarbeitung — inkl. jedes Datenzugriffs, der die Vorschlagsgrundlage geformt hat. Die empfangende Senke überprüft die vollständige Kette, bevor sie eine Aktion ausführt.

Dabei werden Identität, Berechtigung, Verarbeitung und Nachrichtentransport strikt getrennt.

0. Änderungen seit V1.0

Diese Revision setzt die Richtungsentscheidungen der bisherigen Review-Runden um:

  • Scope Evidence Store: kein rechtssicherer, kein WORM-/GoBD-Anspruch. Ziel ist der kryptografische Nachweis einer unverfälschten Kommunikation während eines begrenzten Zeitraums (Default: 1 Jahr).
  • PII-Trennung: verbindlich. Attestierungen enthalten nur Hashes und Referenzen; personenbezogene Inhalte liegen in einem separaten, redaktionierbaren PII-Store.
  • IdP: Pocket ID wird einziger IdP — für Menschen und Agenten (client_credentials-Grant). Kein Keycloak.
  • Content Binding: verbindliches UX-/Signatur-Protokoll (WebAuthn über Content-Hash + visuelle Prüfziffer).
  • Workload-Identität: doppelte Prüfung — Pocket-ID-Token plus K8s-ServiceAccount-Token.
  • Schlüsselbund-Scope: Rotation Default 90 Tage × Retention 1 Jahr → max. ~5 aktive Schlüssel pro Agent.
  • Transparency Log: Trillian + PostgreSQL.
  • Replay-Schutz und fachliche Integritätsprüfung: verbindliche Abschnitte.
  • Transport: Matrix nur optional (Phase 6) für Mensch-Chat; Agent↔Agent über HTTPS/mTLS + NATS JetStream.
  • Signing Service: eigenes Deployment ab Tag 1.
  • predicateType-Namespace: https://basicstack.de/attestations/<domain>/<version>.
  • Senken-Generalisierung: SAP ist eine von vielen möglichen Senken. Trust-Core senken-agnostisch. Senken-Adapter sind Plug-ins mit festem Vertrag.
  • 🆕 Datenquellen und paralleler Lesepfad: Agenten holen während der Vorbereitung Informationen aus registrierten Datenquellen (Section 3b, 4.5a) über das gleiche Vertrauens- und Autorisierungsmodell wie bei Senken. Jede Abfrage erzeugt eine Query Attestation; die Benutzerfreigabe bindet an diese Query-Materialien.
  • 🆕 Session Scope Tokens: Session-gebundene, kurzlebige Delegations-Tokens, mit denen Agenten „im Auftrag von Benutzer X in Session S" lesen dürfen. Siehe Abschnitt 3c.
  • 🆕 Erster produktiver Rollout: eigene kleine Go-DB-App (sink:expense-db-app + ds:expense-db-app) als kombinierte Quelle und Senke. SAP folgt später.
  • 🆕 Begriffsklärung PII-Store: Der Begriff bezeichnet eine Rolle im Datenmodell, kein Produkt. Konkrete Technologie-Wahl und Löschsemantik stehen in Abschnitt 8.4.
  • 🆕 Zeilen-Allokationen auf mehrere Projekte: Reisekostenbelege dürfen pro Zeile prozentual oder absolut auf mehrere Projekte aufgeteilt werden (Schema expense.canonical v1.1.0). Policy erzwingt Summenerhalt pro Item. DB-App legt eine zusätzliche Tabelle expense_item_allocations an. Details in Abschnitt 7.2a; Schemas unter schemas/expense/canonical/v1.1.0.json und schemas/sink/db/expense/v1.1.0.json.

1. Zielarchitektur

Logische Komponentenübersicht, keine direkte Netzwerktopologie. Der Prozess hat zwei Pfade, die beide über denselben Trust-Core abgesichert sind:

  • Schreibpfad (Senke): Approval → Agent-Attestierungen → Verification → Senken-Adapter → signierter Übergabenachweis.
  • Lesepfad (Datenquelle): Agent → Session Scope Token → Datenquellen-Adapter → signierte Query Attestation. Query-Materialien gehen als Eingaben in die nachfolgenden Attestierungen und in die Benutzerfreigabe ein.

Der Transport (HTTPS/mTLS + NATS, optional Matrix) überträgt nur Referenzen und Nachrichten — nie die Vertrauensentscheidung.

Senken sind nach außen offene Zielsysteme — ERP, eigene Datenbankanwendungen, HTTP-Webhooks, Message-Queues, Dateiablage u.a. Datenquellen sind nach außen offene Lesesysteme — eigene DBs, HR-Systeme, Projektmanagement-APIs, SAP-OData-Reads u.a. Beide Typen folgen demselben Adapter-Vertrag.

2. Die sechs Architekturprinzipien

  1. Unveränderliche Benutzerfreigabe — ein vertrauenswürdiger Dienst bestätigt den konkret autorisierten Geschäftsinhalt.
  2. Eigene Identität jedes Agenten — jeder Agent besitzt eine separate kryptografische Identität und signiert seine eigenen Verarbeitungsschritte.
  3. Verkettete Attestierungen — jeder Verarbeitungsschritt referenziert exakte Eingabe- und Ausgabe-Hashes; Lesezugriffe werden ebenfalls attestiert und als Materialien verkettet.
  4. Unabhängige Autorisierung — eine Signatur allein erteilt keine Berechtigung; eine Policy Engine kontrolliert erlaubte Transformationen, Lesezugriffe und Senken-Aktionen.
  5. Transportneutralität — Nachweise funktionieren über HTTP, NATS, Queue oder Matrix.
  6. Quellen- und Senken-Neutralität — Trust-Core und Verifikationspfad kennen keine konkrete Quellen- oder Senken-Semantik; beide sind Plug-ins mit festem Vertrag.

3. Konkrete technische Komponenten

Dienst Technologie Verantwortung
Identity Provider Pocket ID Benutzeranmeldung (Passkey) und Agent-Clients (OIDC)
Approval Service Go, REST API Inhaltsgebundene Benutzerfreigabe
Session Scope Token Svc Go (Teil des trust-api) Short-lived Delegations-Tokens „Agent X im Auftrag von User Y in Session S für Scope Z"
Agent Registry PostgreSQL Agentenidentitäten, Schlüsselhistorie, Berechtigungen
Signing Service Go + OpenBao (Transit) DSSE-Signaturen, verifiziert Agenten-Identität doppelt
Attestation Service Go + in-toto Verarbeitungsschritte und Lesezugriffe dokumentieren
Policy Decision Point Open Policy Agent (OPA) Berechtigungen für Transformationen, Lesezugriffe, Senken
Verification Service Go Gesamte Vertrauenskette überprüfen
Transparency Log Trillian + PostgreSQL Append-only Merkle-Log mit Inclusion Proofs
Message Transport HTTPS/mTLS + NATS JetStream Agent↔Agent-Kommunikation
Chat Transport (opt.) Matrix/Synapse Mensch↔Agent-Chat (nur Phase 6)
Sink Registry PostgreSQL Registrierte Senken, Adapter-Metadaten, Audience-Keys
Data Source Registry PostgreSQL Registrierte Datenquellen, erlaubte Query-Patterns, PII-Klassifikation
Senken-Adapter pro Senke; siehe Abschnitt 7 Übersetzt verifizierte Decision in Senken-Aktion
Datenquellen-Adapter pro Quelle; siehe Abschnitt 7a Prüft Scope-Token + Policy, führt Query aus, erzeugt Query Attestation
Evidence Store PostgreSQL (Metadaten) + S3 DSSE-Envelopes und Attestate (Retention: 1 Jahr)
PII-Store (Rolle) Verschlüsselter S3-Bucket + Mediator-Service Belege, Geschäftsdaten UND Query-Ergebnisse mit PII — redaktionierbar. Rolle, kein Produkt — Details Abschnitt 8.4

Approval, Session Scope Token Service, Attestation, Registry (Agent + Sink + Data Source) und Verification laufen in einem modularen Go-Dienst (trust-api). Signing Service läuft als eigenes Deployment. Senken- und Datenquellen-Adapter laufen pro Typ (oft als derselbe Prozess, wenn eine Komponente beides anbietet — siehe 7.2).

3a. Identity Provider: Pocket ID allein genügt

Pocket ID unterstützt neben dem Authorization-Code-Flow auch den OIDC client_credentials-Grant (POST /api/oidc/token) und bietet Standard-OIDC-Discovery inkl. JWKS unter https://auth.basicstack.de/.well-known/openid-configuration.

  • Menschen melden sich per Passkey an.
  • Agenten sind in Pocket ID als OIDC-Clients registriert; holen sich kurzlebige Access-Tokens per client_credentials.
  • Senken und Datenquellen verifizieren per Pocket-ID-JWKS.

Keine Federation nötig.

3b. Data Source Registry

Datenquellen sind registrierte Entitäten mit stabiler ID, erlaubten Query-Patterns und PII-Klassifikation.

CREATE TABLE data_sources (
  data_source_id      TEXT PRIMARY KEY,              -- z.B. "ds:expense-db-app"
  display_name        TEXT NOT NULL,
  adapter_kind        TEXT NOT NULL,                 -- "db_app" | "http_api" | "sap_odata" | "custom"
  endpoint_url        TEXT,
  owner_team          TEXT NOT NULL,
  pii_class           TEXT NOT NULL,                 -- "none" | "indirect" | "direct"
  created_at          TIMESTAMPTZ NOT NULL,
  retired_at          TIMESTAMPTZ
);

CREATE TABLE data_source_resources (
  data_source_id      TEXT NOT NULL REFERENCES data_sources(data_source_id),
  resource            TEXT NOT NULL,                 -- z.B. "project_assignments", "cost_centers"
  allowed_filters     TEXT[] NOT NULL,               -- z.B. ["employee_id", "project_code"]
  returns_pii         BOOLEAN NOT NULL,
  schema_name         TEXT NOT NULL,
  schema_version      TEXT NOT NULL,
  PRIMARY KEY (data_source_id, resource)
);

Pro Agent-Datenquellen-Kombination gibt es OPA-Regeln (siehe Abschnitt 6).

3c. Session Scope Tokens — Delegation „Agent im Auftrag von Benutzer"

Problem: Der Lese-Agent muss der Datenquelle beweisen, dass er für Benutzer Y in Session S liest — nicht nur, dass er irgendein Agent ist.

Lösung: Der Session Scope Token Service (Teil von trust-api) stellt kurzlebige, signierte Delegations-Tokens aus. Technisch ein JWT mit act-Claim nach RFC 8693 (OAuth 2.0 Token Exchange — die Semantik, nicht der volle Flow).

Ablauf:

  1. Benutzer meldet sich per Pocket ID an und startet eine Session im Approval Service (POST /api/v1/sessions). Approval Service hält session_id, user_sub, active_until.

  2. Agent A will für diese Session eine Datenquelle lesen. Er ruft:

    POST /api/v1/session-scope-tokens
    Authorization: Bearer <agent-pocket-id-token>
    X-Workload-Token: <k8s-sa-token>
    Content-Type: application/json
    
    {
      "session_id": "SES-2026-10-25-abc",
      "requested_scope": {
        "data_source": "ds:expense-db-app",
        "resource": "project_assignments",
        "filters": { "employee_id": "<EMP from session>" },
        "operation": "read"
      },
      "ttl_seconds": 300
    }
    
  3. Der Service prüft:

    • beide Agent-Credentials (Pocket-ID + K8s SA) → agent_id;
    • OPA: darf agent_id die angeforderte Operation auf dieser Datenquelle im Namen dieses konkreten Benutzers ausführen? (z.B. „nur eigene Projekte, nicht fremde");
    • Session aktiv und valide?
  4. Rückgabe: Scope-Token (JWT), signiert vom trust-api-Schlüssel:

    {
      "iss": "https://trust.basicstack.de",
      "sub": "agent-travel",
      "act": {
        "iss": "https://auth.basicstack.de",
        "sub": "user-12345",
        "session_id": "SES-2026-10-25-abc"
      },
      "scope": {
        "data_source": "ds:expense-db-app",
        "resource": "project_assignments",
        "filters": { "employee_id": "EMP-12345" },
        "operation": "read"
      },
      "jti": "<unique>",
      "iat": 1735120000,
      "exp": 1735120300
    }
    
  5. Agent A ruft die Datenquelle: GET https://expense-db-adapter/api/v1/project_assignments?employee_id=EMP-12345 mit Header Authorization: Bearer <scope-token>.

  6. Datenquellen-Adapter prüft Scope-Token (Signatur gegen trust-api-JWKS, exp, scope deckt den Request), führt die Abfrage aus und schreibt eine Query Attestation (siehe 4.5a).

Vorteile:

  • Datenquellen müssen weder Session-State noch Benutzer-Authentifizierung selbst halten — nur Token verifizieren.
  • OPA entscheidet zentral, welche Agent-Benutzer-Kombinationen welche Lesescopes bekommen.
  • Kompromittierte Agent-Credentials erlauben nur die Scopes, die vom Session Scope Token Service herausgegeben wurden — nicht die Weltlese-Erlaubnis.

4. Datenmodell der Vertrauenskette

Jeder Vorgang erhält eine unveränderliche workflow_id. Jede Fassung der Daten wird als eigenes Artefakt mit SHA-256-Hash gespeichert. PII bleibt im separaten PII-Store; Attestierungen enthalten nur Hashes und Referenzen.

Vertrauens- und Verarbeitungskette (am Beispiel Reisekosten → eigene DB-App als erster Rollout)

  1. Session-Start. Benutzer meldet sich per Passkey an, Agent-Travel beginnt den Chat.
  2. Vorab-Lesezugriffe (parallel-Pfad). Agent-Travel holt sich pro Lesezugriff ein Session Scope Token und ruft die Datenquelle (z.B. ds:expense-db-app, Resource project_assignments). Jeder Zugriff erzeugt eine Query Attestation (siehe 4.5a). Der User sieht die zurückgelieferten Vorschläge und wählt (z.B. ein Projekt).
  3. Benutzerfreigabe. Approval Service bindet die Signatur an den Hash des Inhalts, den der Benutzer per Content Binding bestätigt hat, UND an die Materialien-Hashes der oben erzeugten Query Attestations (siehe 4.1).
  4. Agent A: Vorbereitung. Agent-Travel signiert eine Transform-Attestierung über Eingabe-Hash, Ausgabe-Hash, Transformationsart, Freigabe-Referenz und die genutzten Query-Materialien.
  5. Agent B: Mapping. Agent-Sink-Mapping führt eigene Lesezugriffe durch (z.B. Kontierungsvorschläge → neue Query Attestations), transformiert, signiert.
  6. Agent C: Übergabe. Agent-Sink-Posting verifiziert die komplette Kette, übergibt an den Senken-Adapter, erzeugt den signierten Übergabenachweis.

4.0 Content Binding bei der Benutzerfreigabe

Risiko: der Browser könnte dem Benutzer etwas anderes zeigen als dem Approval Service. Verbindlicher Ablauf:

  1. Approval Service rendert den Freigabe-Inhalt serverseitig, berechnet SHA-256 H_content und speichert (session_id, H_content, salt, challenge_nonce).
  2. Browser zeigt den Inhalt und eine aus H_content + challenge_nonce abgeleitete menschenlesbare Prüfziffer.
  3. Benutzer bestätigt per Passkey (WebAuthn-Assertion über challenge_nonce || H_content).
  4. Approval Service verifiziert die WebAuthn-Assertion und erzeugt die DSSE-signierte Approval-Attestierung.

4.1 Benutzerfreigabe (DSSE-Statement, inkl. Query-Materialien)

Neu: materials referenziert die Query Attestations, deren Ergebnisse die Vorschlagsgrundlage für den Benutzer waren.

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": "expense/EXP-2026-0042/v1",
      "digest": { "sha256": "<content hash>" }
    }
  ],
  "predicateType": "https://basicstack.de/attestations/approval/v1",
  "predicate": {
    "workflow_id": "WF-0042",
    "approval_id": "APR-0042",
    "schema": { "name": "expense.canonical", "version": "1.0.0" },
    "issuer": "approval-service",
    "user": {
      "iss": "https://auth.basicstack.de",
      "sub": "user-12345"
    },
    "content_binding": {
      "method": "webauthn-content-hash-v1",
      "assertion_hash": "sha256:<webauthn assertion hash>",
      "verification_code": "F3K-9MQ"
    },
    "materials": [
      {
        "name": "query/project_assignments/employee=EMP-12345",
        "sha256": "<result_hash>",
        "attestation_ref": "sha256:<query attestation hash>"
      },
      {
        "name": "query/cost_centers/active-for-EMP-12345",
        "sha256": "<result_hash>",
        "attestation_ref": "sha256:<query attestation hash>"
      }
    ],
    "action": "expense.submit",
    "audience": "sink:expense-db-app",
    "allowed_transformations": ["expense.normalize", "expense.map_to_sink"],
    "allowed_sinks": ["sink:expense-db-app"],
    "nonce": "<base64 nonce>",
    "issued_at": "2026-10-25T10:30:00Z",
    "expires_at": "2026-11-01T00:00:00Z"
  }
}

Verifikation (Abschnitt 5) prüft, dass genau die hier referenzierten Query Attestations existieren, gültig signiert sind und ihre Ergebnisse den im Freigabeinhalt verwendeten Werten entsprechen (z.B. „das ausgewählte Projekt ist tatsächlich in der Ergebnisliste").

4.2 Signatur mit DSSE

{
  "payloadType": "application/vnd.in-toto+json",
  "payload": "<base64-encoded statement>",
  "signatures": [
    { "keyid": "approval-service-key-2026-q4", "sig": "<base64-encoded signature>" }
  ]
}

4.3 Transformations-Attestierung (Agent B, Mapping)

Neue Felder: read_materials referenziert Query Attestations, die diese Transformation genutzt hat.

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    { "name": "expense/EXP-2026-0042/sink-payload", "digest": { "sha256": "<output hash>" } }
  ],
  "predicateType": "https://basicstack.de/attestations/transform/v1",
  "predicate": {
    "workflow_id": "WF-0042",
    "actor": "agent-sink-mapping",
    "operation": "expense.map_to_sink",
    "sink_target": "sink:expense-db-app",
    "materials": [
      { "name": "expense/EXP-2026-0042/normalized", "sha256": "<input hash>" }
    ],
    "read_materials": [
      { "name": "query/account_assignments/project=P-42",
        "sha256": "<result_hash>",
        "attestation_ref": "sha256:<query attestation hash>" }
    ],
    "parent_attestation": "sha256:<previous proof hash>",
    "approval_ref": "APR-0042",
    "schema": {
      "input":  { "name": "expense.canonical",   "version": "1.0.0" },
      "output": { "name": "sink.db.expense",     "version": "1.0.0" }
    },
    "transform_version": "1.3.0",
    "issued_at": "2026-10-25T10:31:15Z"
  }
}

4.4 Agentenregistrierung und Schlüsselhistorie

Jeder Agent ist in zwei Systemen eingetragen:

  • Pocket ID: als OIDC-Client (client_id, client_secret im K8s-Secret).
  • Agent Registry (Postgres): Identität plus Signatur-Schlüsselhistorie.
CREATE TABLE agents (
  agent_id            TEXT PRIMARY KEY,
  pocket_id_client    TEXT UNIQUE NOT NULL,
  k8s_namespace       TEXT NOT NULL,
  k8s_service_account TEXT NOT NULL,
  display_name        TEXT NOT NULL,
  allowed_actions     TEXT[] NOT NULL,
  created_at          TIMESTAMPTZ NOT NULL
);

CREATE TABLE agent_keys (
  key_id            TEXT PRIMARY KEY,
  agent_id          TEXT NOT NULL REFERENCES agents(agent_id),
  public_key_pem    TEXT NOT NULL,
  valid_from        TIMESTAMPTZ NOT NULL,
  valid_to          TIMESTAMPTZ NOT NULL,
  revoked_at        TIMESTAMPTZ,
  revocation_reason TEXT,
  archived_at       TIMESTAMPTZ
);

CREATE INDEX idx_agent_keys_lookup
  ON agent_keys (agent_id, archived_at)
  WHERE archived_at IS NULL;

Validierung alter Attestierungen nutzt den Schlüssel, der zur issued_at galt (TUF-Pattern). Rotation Default 90 Tage × Retention 1 Jahr → max. ~5 nicht-archivierte Schlüssel/Agent.

4.5 Sink Registry

CREATE TABLE sinks (
  sink_id             TEXT PRIMARY KEY,              -- z.B. "sink:expense-db-app"
  display_name        TEXT NOT NULL,
  adapter_kind        TEXT NOT NULL,                 -- "sap_abap" | "db_app" | "http_webhook" | "message_queue" | "file_drop" | "custom"
  endpoint_url        TEXT,
  idempotency_scope   TEXT NOT NULL,
  callback_pubkey_pem TEXT,
  allowed_actions     TEXT[] NOT NULL,
  owner_team          TEXT NOT NULL,
  created_at          TIMESTAMPTZ NOT NULL,
  retired_at          TIMESTAMPTZ
);

4.5a Query Attestation (Lesezugriffs-Nachweis)

Jeder Lesezugriff eines Agenten auf eine Datenquelle erzeugt eine signierte Query Attestation. Die Attestierung enthält Query-Parameter und einen deterministischen Hash der Rückgabe — nicht die Rückgabe selbst (PII bleibt im PII-Store).

{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": "query/project_assignments/employee=EMP-12345",
      "digest": { "sha256": "<hash of (query_params || result_hash)>" }
    }
  ],
  "predicateType": "https://basicstack.de/attestations/query/v1",
  "predicate": {
    "workflow_id": "WF-0042",
    "session_id": "SES-2026-10-25-abc",
    "actor": "agent-travel",
    "data_source": "ds:expense-db-app",
    "operation": "data_source.read",
    "query": {
      "resource": "project_assignments",
      "filters": { "employee_id": "EMP-12345" },
      "query_hash": "sha256:<canonicalized query>"
    },
    "result": {
      "row_count": 3,
      "result_hash": "sha256:<canonicalized result rows>",
      "pii_class": "indirect",
      "pii_store_ref": "s3://pii-store/queries/WF-0042/SES-abc/<uuid>.json"
    },
    "on_behalf_of": {
      "iss": "https://auth.basicstack.de",
      "sub": "user-12345"
    },
    "session_scope_token_jti": "<jti of the scope token used>",
    "schema": { "name": "ds.expense.project_assignment", "version": "1.0.0" },
    "issued_at": "2026-10-25T10:28:12Z"
  }
}

Wesentlich: Die Query Attestation wird vom Datenquellen-Adapter erzeugt und signiert (nicht vom Agenten), damit der Agent nicht die Rückgabe fälschen kann. Der Adapter benutzt seinen eigenen Schlüssel (ds-adapter-<name>-key-<rev>), der in der Agent Registry mit agent_id = "ds-adapter:<name>" registriert ist.

Der PII-Anteil der Rückgabe landet im PII-Store unter pii_store_ref; dort gelten die normalen Retention- und Löschregeln. Verifikation nach Löschung: die Signaturkette bleibt gültig, aber result_hash kann dann nicht mehr gegen den Inhalt geprüft werden — das ist der bewusste Trade-off aus der DSGVO-Löschbarkeit.

4.6 Agentenregistrierung — zusätzliche Datenquellen-Berechtigungen

CREATE TABLE agent_data_source_scopes (
  agent_id            TEXT NOT NULL REFERENCES agents(agent_id),
  data_source_id      TEXT NOT NULL REFERENCES data_sources(data_source_id),
  resource            TEXT NOT NULL,
  allowed_filters     TEXT[] NOT NULL,
  operation           TEXT NOT NULL CHECK (operation IN ('read')),
  requires_user_context BOOLEAN NOT NULL DEFAULT TRUE,
  PRIMARY KEY (agent_id, data_source_id, resource, operation)
);

Der Session Scope Token Service konsultiert diese Tabelle UND OPA (für feinere Regeln). requires_user_context = TRUE erzwingt, dass der Scope-Token nur mit aktiver Benutzer-Session ausgestellt wird (verhindert hintergründige Lesezugriffe ohne Benutzer).

5. Verifikation

POST /api/v1/attestations/verify
Authorization: Bearer <service-token>
Content-Type: application/json

{
  "workflow_id": "WF-0042",
  "artifact_digest": "sha256:<final hash>",
  "requested_action": "expense.post",
  "target": "sink:expense-db-app"
}

Prüfungen (vollständig):

Prüfung Fehlerfall
Signatur der Benutzerfreigabe gültig (Schlüssel zur issued_at)? Ablehnen
Content-Binding-Assertion in der Approval-Attestierung vorhanden? Ablehnen
Benutzeridentität im Pocket-ID-JWKS auflösbar? Ablehnen
Freigabe gültig, nicht widerrufen, nicht abgelaufen? Ablehnen
Alle in Approval referenzierten Query Attestations existieren und sind gültig signiert? Ablehnen
Datenquellen zur Query-Zeit registriert und Agent berechtigt? Ablehnen
Query-Materialien konsistent mit den im Freigabeinhalt verwendeten Werten? Ablehnen
target in Sink Registry und allowed_actions erlaubt die Aktion? Ablehnen
target in approval.allowed_sinks enthalten? Ablehnen
Alle Agentensignaturen gültig gegen agent_keys zur issued_at? Ablehnen
Agenten zum Signaturzeitpunkt registriert und berechtigt? Ablehnen
Input-/Output-Hashes der Materialien-Kette konsistent? Ablehnen
Alle in Transform-Attestierungen referenzierten read_materials existieren? Ablehnen
Transformationen laut Freigabe zulässig? Ablehnen
Schema-Versionen kompatibel? Ablehnen
Nutzlast entspricht freigegebener Geschäftssemantik (OPA)? Ablehnen
payload_hash bereits für target übergeben? Keine erneute Übergabe

5.1 Replay-Schutz (verbindlich, unverändert)

  • decision_id enthält decision_nonce, Lebensdauer 5 Minuten.
  • Bindung an (agent_id, payload_hash, target).
  • Verification Service: UNIQUE (payload_hash, target) in decisions.
  • Jeder Senken-Adapter führt eigene Replay-Tabelle sink_decision_log.
  • Scope-Tokens (für Reads) haben eigene jti und exp; Replay-Schutz pro Datenquelle: UNIQUE (data_source_id, jti) in einer kleinen scope_token_log-Tabelle beim Adapter (optional — die kurze TTL deckt den Normalfall).

6. Berechtigungssteuerung mit Open Policy Agent

OPA deckt drei Policy-Klassen ab:

  1. Transformation-Policies — welche Agenten dürfen welche Transformationen auf welchen Schemas durchführen? (unverändert aus V1.0)
  2. Senken-Policies — welche Agenten dürfen welche Senken für welche Aktionen nutzen? (aus V1.1 Erstfassung)
  3. 🆕 Datenquellen-/Scope-Policies — welche Agenten dürfen welche Lesezugriffe im Namen welcher Benutzer durchführen?

Beispiel-Regeln für Datenquellen:

  • Agent-Travel darf ds:expense-db-app → project_assignments lesen, aber nur gefiltert nach employee_id des aktuellen Benutzers (keine fremden Zuweisungen).
  • Agent-Sink-Mapping darf ds:expense-db-app → account_assignments lesen, aber nur für Projekte, die aus einer vorherigen Query Attestation desselben Workflows stammen.
  • Agent-Travel darf ds:hr-system → employee_profile NUR mit requires_user_context=TRUE und nur die Felder name, cost_center, nicht salary.
  • Agenten dürfen keine Datenquellen abfragen, deren retired_at IS NOT NULL.

Rego-Policies werden zentral versioniert; die zum Entscheidungszeitpunkt verwendete Policy-Version wird in der Query Attestation bzw. Decision mit abgelegt.

6.1 Fachliche Integritätsprüfung — Schema-Versionierung (verbindlich)

Kanonische und Senken-/Quellen-spezifische Zielschemas liegen versioniert in schemas/ im Repo. Approval signiert schema.name und schema.version mit. Transform- und Query-Attestierungen tragen ebenfalls schema-Felder. Schema-Änderungen sind Breaking Changes und erfordern eine neue Hauptversion.

7. Senken-Integration

(unverändert gegenüber V1.1 Erstfassung — Vertrag in 7.0, Beispiele 7.1–7.5)

7.0 Vertrag jedes Senken-Adapters

Jeder Adapter MUSS: verifizieren (/api/v1/attestations/verify), idempotent sein (sink_decision_log mit UNIQUE (decision_id) und UNIQUE (payload_hash)), Audit-Mindestdaten speichern, Übergabenachweis zurückgeben, Fehlerpfad definieren, serverseitige Business-ID-Mapping-Hoheit wahren.

7.1 SAP S/4HANA (später)

Siehe V1.1 Erstfassung. Phase-6-Senke, nicht Phase 4.

7.2 Eigene DB-App (Phase 4 — ERSTER produktiver Rollout, kombinierter Lese- und Schreibpfad)

Die eigene DB-App ist gleichzeitig Datenquelle (ds:expense-db-app) und Senke (sink:expense-db-app). Ein gemeinsamer Go-Service deployed als expense-db-adapter mit Backing-Store expense-db-postgres.

Endpunkte (Beispiel):

# Datenquellen-Seite (Reads)
GET /api/v1/project_assignments?employee_id=<EMP>
GET /api/v1/account_assignments?project_code=<P>
GET /api/v1/cost_centers?active=true

# Senken-Seite (Writes)
POST /api/v1/expense/submit     # Erst-Buchung
POST /api/v1/expense/update     # Nachbuchung (optional, pro OPA-Policy)

Alle Reads erwarten Authorization: Bearer <session-scope-token>. Alle Writes erwarten Authorization: Bearer <agent-pocket-id-token> und rufen Verification Service.

Datenmodell (vereinfacht):

CREATE TABLE project_assignments (
  id             BIGSERIAL PRIMARY KEY,
  employee_id    TEXT NOT NULL,
  project_code   TEXT NOT NULL,
  valid_from     DATE NOT NULL,
  valid_to       DATE,
  UNIQUE (employee_id, project_code, valid_from)
);

CREATE TABLE account_assignments (
  id             BIGSERIAL PRIMARY KEY,
  project_code   TEXT NOT NULL,
  cost_center    TEXT NOT NULL,
  gl_account     TEXT NOT NULL,
  valid_from     DATE NOT NULL,
  valid_to       DATE
);

CREATE TABLE cost_centers (
  cost_center    TEXT PRIMARY KEY,
  display_name   TEXT NOT NULL,
  active         BOOLEAN NOT NULL DEFAULT TRUE
);

CREATE TABLE expenses (
  workflow_id    TEXT PRIMARY KEY,
  employee_id    TEXT NOT NULL,
  project_code   TEXT NOT NULL,
  cost_center    TEXT NOT NULL,
  currency       TEXT NOT NULL,
  total_amount   NUMERIC(12,2) NOT NULL,
  payload_hash   TEXT NOT NULL,
  decision_id    TEXT UNIQUE NOT NULL,
  approval_id    TEXT NOT NULL,
  original_user_sub TEXT NOT NULL,
  posted_by_agent TEXT NOT NULL,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE sink_decision_log (
  decision_id    TEXT PRIMARY KEY,
  payload_hash   TEXT UNIQUE NOT NULL,
  sink_record_ref TEXT NOT NULL,
  posted_by_agent TEXT NOT NULL,
  created_at     TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

Der Adapter prüft bei jeder Lese-Anfrage: Scope-Token signiert durch trust-api, Resource und Filter aus Scope-Token decken Request-Resource und -Filter, exp nicht abgelaufen. Danach führt er die Abfrage aus und erzeugt die Query Attestation.

7.2a Zeilen-Allokationen auf mehrere Projekte (v1.1.0)

Für Reisekosten, die anteilig auf mehrere Projekte gebucht werden sollen, nutzen wir ab expense.canonical v1.1.0 bzw. sink.db.expense v1.1.0 ein Allocation-Modell:

  • Jedes Item in expense_items[] trägt ein optionales allocations[]. Ohne Allocation gilt das top-level project_assignment als Default für dieses Item.
  • Allocation-Entry hat project_code, cost_center, source_attestation_ref und einen Modus:
    • mode: "percentage" + percentage (0.00..100.00) — alle Entries desselben Items mit mode=percentage, Summe exakt 100.00.
    • mode: "absolute" + amount — alle Entries desselben Items mit mode=absolute, Summe exakt gleich item.amount.
  • Mischen von Modi innerhalb eines Items ist unzulässig (OPA-Regel).
  • source_attestation_ref ist Pflicht — bindet die gewählten Projekte/Kostenstellen an eine Query Attestation von ds:expense-db-app.

Agent-sink-mapping löst percentage-Allokationen in absolute Beträge auf (letzte Allocation absorbiert den Rundungsresiduum, damit die Summe exakt bleibt) und schreibt in die Senke immer absolute Beträge. Die OPA-Policy proofedmesh.transformations.expense prüft pro Item sum(allocations.amount) == item.amount in Cents (siehe policies/transformations/expense.rego).

DB-Schema-Erweiterung in der eigenen DB-App:

-- Neu bzw. ergänzend zu 7.2:

CREATE TABLE expense_items (
  id             BIGSERIAL PRIMARY KEY,
  workflow_id    TEXT NOT NULL REFERENCES expenses(workflow_id) ON DELETE CASCADE,
  item_index     INT NOT NULL,
  item_type      TEXT NOT NULL,
  amount         NUMERIC(12,2) NOT NULL,
  incurred_on    DATE NOT NULL,
  description    TEXT,
  receipt_ref    TEXT,                 -- "pii://..." Referenz in den PII-Store
  UNIQUE (workflow_id, item_index)
);

CREATE TABLE expense_item_allocations (
  id              BIGSERIAL PRIMARY KEY,
  expense_item_id BIGINT NOT NULL REFERENCES expense_items(id) ON DELETE CASCADE,
  project_code    TEXT NOT NULL,
  cost_center     TEXT NOT NULL,
  gl_account      TEXT NOT NULL,
  amount          NUMERIC(12,2) NOT NULL,         -- immer absolut
  percentage      NUMERIC(5,2),                   -- optional, nur informativ aus canonical mode=percentage
  source_attestation_ref TEXT NOT NULL,
  UNIQUE (expense_item_id, project_code, cost_center)
);

Die ursprüngliche Tabelle expenses behält project_code und cost_center als Kompatibilitätsfelder für v1.0.0-Vorgänge (dort gibt es nur ein Projekt pro Vorgang). Für v1.1.0-Vorgänge sind beide Felder in expenses NULL und die Zuordnung ergibt sich aus expense_item_allocations.

Beispiel-Payloads: schemas/expense/canonical/examples/v1.1.0/*.json und schemas/sink/db/expense/examples/v1.1.0/split-resolved.json.

7.3–7.5 Weitere Senken-Typen (HTTP-Webhook, Message-Queue, Dateiablage) — unverändert aus V1.1 Erstfassung.

7.6 Welchen Adapter wo deployen? — unverändert.

7a. Datenquellen-Integration

7a.0 Vertrag jedes Datenquellen-Adapters

Jeder Datenquellen-Adapter MUSS:

  1. Scope-Token verifizieren — Signatur gegen trust-api-JWKS, exp nicht abgelaufen, Scope deckt den Request (data_source, resource, filters, operation), jti noch nicht verbraucht (sofern Replay-Schutz aktiv).
  2. Query ausführen mit genau den im Scope-Token enthaltenen Filtern — keine Erweiterung erlaubt.
  3. Query Attestation signieren mit eigenem Adapter-Schlüssel.
  4. PII-Anteil der Rückgabe in den PII-Store schreiben, Ergebnis-Hash in die Attestation stellen.
  5. An Agent zurückliefern — Rückgabe-Payload (für die unmittelbare Nutzung) PLUS die Query Attestation (für die spätere Verwendung in Approvals/Transforms).
  6. Audit-Zeile schreiben — (workflow_id, session_id, agent_id, user_sub, data_source_id, resource, filters, result_hash, created_at).

7a.1 Beispiel: Eigene DB-App als Datenquelle

Siehe 7.2 (kombiniert mit Senken-Seite).

7a.2 Beispiel: HR-System via HTTP-API

Externer HR-Dienst (OData/REST). Datenquellen-Adapter läuft in unserem Cluster, kapselt das Backend-Secret, mappt zwischen externem Schema und data_source_resources-Schema. OPA-Policy kann einzelne Felder (z.B. salary) ausschließen.

7a.3 Beispiel: SAP OData-Read

Später, parallel zur SAP-Senken-Anbindung. Dann ist SAP sowohl ds:sap-s4hana-prod als auch sink:sap-s4hana-prod.

8. Nachweisablage und Transparency Log

8.1 Scope und Retention

Default-Retention: 1 Jahr. Attestierungen, Decisions, Query Attestations und zugehörige Schlüsselhistorie werden danach automatisiert gelöscht. Konfigurierbar pro Prozess-Typ, Senke und Datenquelle.

8.2 Datenklassen

Daten Speicherung
Prozessstatus, Identitäten, Referenzen PostgreSQL (trust-postgres)
Senken- und Datenquellen-Registry PostgreSQL (trust-postgres)
Signierte Attestierungen (DSSE) S3 Object Storage
Transparency-Log-Einträge + Proofs Trillian + PostgreSQL
Geschäftsdaten + Query-Ergebnisse mit PII PII-Store (separater S3-Bucket, redaktionierbar)
Signatur- und Schlüsselhistorie Agent Registry (Postgres), max 1 Jahr
Policy-Versionen Git-versioniert, Hash in Attestations
Senken-Übergabenachweise S3 + sink_decision_log je Senke

Query-Ergebnisse mit PII landen immer im PII-Store. Löschung dort invalidiert nicht die Signaturkette, nur die Nachkontrolle der Ergebnisse.

8.3 Trillian + PostgreSQL (unverändert)

Append-only Merkle-Log mit Inclusion Proofs. Cassandra ist dafür ungeeignet (siehe V1.1 Erstfassung).

8.4 Was ist der PII-Store konkret?

Begriffsklärung. „PII" steht für Personally Identifiable Information (deutsch: personenbezogene Daten im Sinne der DSGVO Art. 4 Nr. 1). „PII-Store" ist kein Produktname und keine Technologie, sondern eine architektonische Rolle in unserem Datenmodell. Das Muster — personenbezogene Daten in einem dedizierten, löschbaren Speicher getrennt vom unveränderlichen Nachweismaterial zu halten — ist in Privacy-Engineering-Literatur unter Namen wie „PII vault", „tokenization vault" oder „data minimization layer" bekannt (siehe NIST SP 800-188 „De-Identifying Government Datasets" oder ENISA „Pseudonymisation techniques and best practices").

Warum wir die Rolle brauchen. Wir müssen zwei scheinbar widersprüchliche Anforderungen gleichzeitig erfüllen:

  • Nachweiskette darf nicht geändert werden — eine Signaturkette, deren Inhalte nachträglich veränderbar sind, ist nutzlos.
  • DSGVO Art. 17 „Recht auf Löschung" — personenbezogene Daten müssen auf Antrag entfernt werden können.

Lösung: wir trennen Nachweis und Nutzinhalt physisch:

  • Der Evidence Store hält DSSE-Envelopes, Attestierungen, Transparency-Log-Einträge und Hashes. Dieser Speicher ist für die Dauer der Retention unveränderlich.
  • Der PII-Store hält die eigentlichen Nutzinhalte (Reisekostenbelege, Dateien, Query-Ergebnisse mit Personen- oder Projektdaten). Dieser Speicher ist pro Vorgang und pro Betroffenem löschbar.

Löscht man im PII-Store, bleibt die Signaturkette intakt — nur die Nachkontrolle gegen den Inhalt ist dann nicht mehr möglich. Das ist der bewusste Trade-off: Löschbarkeit gewinnt gegenüber Nachkontrolle, der Beweis der Kommunikation an sich bleibt bestehen.

Konkrete Technologie-Wahl für ProofedMesh (Default). Der PII-Store wird aus zwei Bausteinen gebaut, die wir bereits im Cluster haben:

  1. Verschlüsselter Hetzner Object Storage (S3-kompatibel), eigener Bucket. Jeder Workflow bekommt ein eigenes Prefix (pii/<workflow_id>/…). Der Bucket hat keine öffentlichen ACLs; Zugriff nur per Service-Account aus unserem Cluster.
  2. PII-Mediator-Service (kleine Go-Komponente). Alle anderen Dienste (Approval, Datenquellen-Adapter, Senken-Adapter, Verifikations-UI) sprechen nur mit dem Mediator, nie direkt mit S3. Der Mediator:
    • vergibt pro Objekt einen Datenschlüssel (envelope-encrypted über OpenBao Transit — der eigentliche Objektschlüssel liegt nicht im Mediator),
    • prüft bei jedem Zugriff: Token, Scope, OPA-Policy,
    • führt ein Zugriffs-Audit (workflow_id, agent_id/user_sub, operation, created_at),
    • exekutiert Löschungen (Objekt löschen + Transit-Schlüssel vergessen → Cryptographic Erasure).

Dadurch ergibt sich automatisch ein doppeltes Löschen: Objekt entfernt UND Entschlüsselungsschlüssel vergessen. Beides muss gelingen, aber jedes einzelne davon reicht bereits, um die Daten unlesbar zu machen.

Was im PII-Store liegt (vs. was NICHT dort liegt):

Datenart PII-Store? Alternativer Ort
Reisekostenbelege (PDF, Scan) ja —
Kanonische Reisekostendaten (expense.canonical) ja —
Query-Ergebnisse mit Namen/Kostenstellen/Projektzuordnungen ja —
DSSE-Envelopes (nur Hashes) nein Evidence Store (S3, Retention 1 Jahr)
Transparency-Log-Einträge nein Trillian + Postgres
Agent-/Session-Schlüsselmaterial nein OpenBao Transit, Agent Registry
Workflow-Status, Decision-IDs, Referenzen nein trust-postgres

Retention und Löschsemantik.

  • Default-Retention: 1 Jahr nach letzter Workflow-Aktivität (identisch zu Evidence Store), danach automatisches Löschen durch Cron-Job.
  • Vorzeitige Löschung auf Antrag eines Betroffenen (DSGVO Art. 17): PII-Mediator ruft DELETE /pii/<workflow_id> → S3-Objekte entfernen + Transit-Keys vergessen + Audit-Zeile schreiben. Die Signaturkette im Evidence Store wird NICHT angerührt.
  • Löschprotokoll: der Mediator schreibt eine signierte Deletion-Attestierung in den Transparency Log (predicateType=https://basicstack.de/attestations/pii_deletion/v1), damit später nachweisbar ist „zu diesem Workflow waren PII-Daten vorhanden und wurden am Datum X auf Antrag Y gelöscht".

Alternativen, die wir bewusst nicht wählen (Begründung).

Alternative Warum nicht (für den Start)
Keine Trennung, PII in den DSSE-Payloads Macht DSGVO Art. 17 unlösbar — die Signaturkette müsste bei jeder Löschung invalidiert werden.
Kommerzielle PII-Vaults (Skyflow, Piiano, VGS) Externer Dienst, Vendor-Lock-in, Kosten; keine Zusatzgarantien, die wir für den geplanten Scope brauchen.
Dedizierte Postgres-Instanz mit TDE Löschbarkeit braucht Zusatzlogik; kein nennenswerter Vorteil gegenüber verschlüsseltem Object Storage für Blob-PII.
OpenBao Transform Engine (Format-Preserving Encryption) Lohnt sich bei strukturierten Feldern (z.B. Kreditkarten) in einer bestehenden App — Overhead für unsere Use Cases.
Confidential Computing (TEE/SGX) Overkill und derzeit auf Hetzner nicht in der Variante verfügbar, die wir brauchen würden.

Begrifflichkeit im weiteren Doc. Wo bisher „PII-Store" steht, ist jeweils diese Rolle gemeint — konkret implementiert als „verschlüsselter S3-Bucket + PII-Mediator-Service". Wenn wir später z.B. Confluence-Export oder Teams-Daten anbinden, bleibt der Begriff gleich; nur der Mediator bekommt zusätzliche Backend-Adapter.

9. Deployment in Kubernetes

identity/
  pocket-id

agent-trust/
  trust-api             (Approval + Session Scope Tokens + Attestation + Agent Registry + Sink Registry + Data Source Registry + Verification)
  signing-service       (eigenes Deployment, enge Trust-Boundary)
  policy-engine         (OPA)
  trust-postgres
  trillian-log

transport/
  nats                  (JetStream)

paperclip/
  paperclip
  agent-travel
  agent-sink-mapping
  agent-sink-posting

sinks-and-sources/
  expense-db-adapter    (für ds:expense-db-app UND sink:expense-db-app)
  expense-db-postgres
  # später: webhook-adapter, queue-adapter, file-adapter
  # später: hr-api-adapter (nur Datenquelle)
  # SAP-Adapter läuft als ABAP im SAP-System

openbao/
  openbao

matrix/                 (optional, Phase 6)

9.1 Workload-Identitäts-Prüfung (doppelt, unverändert)

Signing Service und Session Scope Token Service verifizieren beide: Pocket-ID-Access-Token UND projected K8s ServiceAccount-Token. Nur bei übereinstimmendem agent_id wird signiert bzw. ein Scope-Token ausgestellt.

10. Implementierungsreihenfolge

Phase 1 — End-to-End-Skelett (3–5 Wochen). Pocket ID als IdP, Approval Service mit Content Binding, ein Testagent, Signing Service mit doppelter Identitätsprüfung, Verification Service für zweistufige Kette, triviale Mock-Senke (sink:dummy-sink). Noch ohne Lesepfad.

Phase 2 — Agent Attestations + Lesepfad (Minimum). Weitere Agenten, Schlüsselrotation, in-toto-Transformationsnachweise, Session Scope Token Service, Data Source Registry, erste triviale Datenquelle (ds:dummy-ds), Query Attestations, OPA-Policies in Rego (Transformation + Datenquelle), Policy-Versionierung.

Phase 3 — Replay-Schutz, Transparency Log, Retention. Trillian-Deployment, Decision-Nonce-Mechanik, Retention-Cron-Jobs, PII-Store-Trennung inkl. Query-Result-PII.

Phase 4 — Eigene DB-App als kombinierte Quelle und Senke (erster produktiver Rollout). expense-db-adapter + expense-db-postgres, mit ds:expense-db-app (Reads auf project_assignments, account_assignments, cost_centers) und sink:expense-db-app (Writes auf expenses). Vollständiger produktiver Reisekostenprozess: Chat-Agent liest Projektzuweisungen, Benutzer wählt und bestätigt per Passkey, Mapping-Agent liest Kontierungsvorschläge, Posting-Agent schreibt — alles kryptografisch verkettet, prüfbar, mit 1-Jahres-Retention.

Phase 5 — Weitere Senken-/Datenquellen-Typen. HTTP-Webhook-Adapter, Message-Queue-Adapter, File-Adapter, erste externe Datenquelle (z.B. HR-API).

Phase 6 — SAP-Integration. SAP S/4HANA als Senke (ABAP-Endpoint, Validierungs-Webservice, SM59-Rotation) und ggf. als Datenquelle (OData-Reads via Adapter).

Phase 7 — Matrix für Mensch-Chat (optional). E2EE-Chat.

11. Was bewusst anders ist als in V1.0

  • Zwei Pfade (Schreib- und Lesepfad), beide über denselben Trust-Core.
  • Datenquellen und Senken sind symmetrische Konzepte mit festem Adapter-Vertrag.
  • Session Scope Tokens machen Delegation „Agent im Auftrag von Benutzer" explizit und auditierbar.
  • SAP ist eine mögliche Senke/Quelle, nicht das Ziel. Erster produktiver Rollout ist eigene DB-App.
  • Matrix ist optional, Phase 7.
  • Transparency Log ist eigene Komponente (Trillian).
  • Signing Service ist eigenes Deployment ab Tag 1.
  • PII-Store strikt getrennt vom Evidence Store, inkl. Query-Result-PII.
  • Keine Unveränderbarkeits-/GoBD-Garantien.
  • Pocket ID ist alleiniger IdP.

12. Empfohlener Kernstack (Zielbild)

Identität Pocket ID (Menschen + Agent-Clients)
Workload-ID K8s projected ServiceAccount Token + TokenReview
Delegation Session Scope Tokens (JWT mit act-Claim, 5-Min-TTL)
Signaturen Ed25519 / DSSE, OpenBao Transit
Provenienz in-toto v1, predicate-Namespace basicstack.de/attestations/*/*
Autorisierung OPA (Rego) + Approval Service — drei Policy-Klassen (Transform/Senke/Datenquelle)
Transparency Trillian + PostgreSQL
Transport HTTPS/mTLS + NATS JetStream (Agent↔Agent); Matrix optional (Mensch)
Agenten Paperclip
Senken Plug-in-Architektur — erster Rollout: eigene DB-App. Später SAP, Webhook, Queue, Dateiablage
Datenquellen Plug-in-Architektur — erster Rollout: eigene DB-App (gleicher Adapter wie Senke). Später HR-API, SAP OData u.a.
Evidence PostgreSQL + S3 (Retention 1 Jahr)
PII Separater verschlüsselter S3-Bucket, redaktionierbar (inkl. Query-Result-PII)

Wichtigste Empfehlung: Phase 1–3 bauen den Trust-Core samt Lesepfad mit Mock-Komponenten. Phase 4 ist der erste produktive Durchlauf mit eigener DB-App als kombinierter Quelle und Senke. SAP und externe Datenquellen folgen in Phase 6.