# Technische Zielarchitektur: Vertrauenswürdige Kommunikation zwischen Menschen, KI-Agenten und beliebigen Prozess-Senken **Status:** Architekturvorschlag V1.1 (aktive Diskussionsgrundlage) **Vorgänger:** [`v1.0.md`](v1.0.md) — ursprünglicher Entwurf (unverändert archiviert) **Letzte Änderung:** Senken-Konzept generalisiert — SAP ist nur eine mögliche Senke neben eigenen DB-Applikationen, HTTP-Webhooks, Message-Queues u.a. Diese Lösung wird als **Identity-Aware Agent Messaging Platform** konzipiert: eine Plattform, die Benutzerfreigaben, delegierte Berechtigungen und sämtliche Verarbeitungsschritte kryptografisch nachvollziehbar macht. Die zentrale Designentscheidung lautet: > **Der Benutzer autorisiert den ursprünglichen Geschäftsinhalt. Jeder Agent attestiert anschließend seine eigene Verarbeitung. 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 ersten beiden 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 (per `client_credentials`-Grant). Kein Keycloak. - **Content Binding:** eigener Abschnitt 4.0 als 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 (nicht Cassandra — Begründung in 8.3). - **Replay-Schutz und fachliche Integritätsprüfung:** verbindliche Abschnitte (5.1 und 6.1). - **Transport:** Matrix nur optional in Phase 5 für Mensch-Chat; Agent↔Agent läuft über HTTPS/mTLS + NATS JetStream. - **Signing Service:** eigenes Deployment ab Tag 1. - **predicateType-Namespace:** `https://basicstack.de/attestations//`. - **🆕 Senken-Generalisierung:** SAP ist eine von vielen möglichen Prozess-Senken. Der Trust-Core ist senken-agnostisch. Senken-Adapter sind eine austauschbare Schicht mit festem Vertrag (Abschnitt 7). ## 1. Zielarchitektur Logische Komponentenübersicht, keine direkte Netzwerktopologie. Freigabe- und Attestierungsnachweise werden über eigene APIs erstellt und geprüft; der Transport (HTTPS/mTLS + NATS, optional Matrix) überträgt nur Referenzen und Nachrichten — nie die Vertrauensentscheidung. Der Prozess endet an einer **Senke** (Sink). Senken sind nach außen offene Zielsysteme — ERP (SAP S/4HANA, SAP Concur), eigene Datenbankanwendungen, HTTP-Webhooks externer Dienste, Message-Queues (Kafka/NATS), Dateiablage (SFTP, S3), Legacy-Systeme (Mail/EDI) oder beliebige kundeneigene APIs. Der Trust-Core ist senken-agnostisch; pro Senken-Typ gibt es einen **Senken-Adapter**, der denselben Vertrag erfüllt (Abschnitt 7). ## 2. Die fünf 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. 4. **Unabhängige Autorisierung** — eine Signatur allein erteilt keine Berechtigung; eine Policy Engine kontrolliert erlaubte Transformationen und Senken-Aktionen. 5. **Transportneutralität** — Nachweise funktionieren über HTTP, NATS, Queue oder Matrix, ohne dass die kryptografische Vertrauenskette verloren geht. Zusatzprinzip: **Senken-Neutralität.** Weder der Trust-Core noch der Verifikationspfad kennen die Semantik einer konkreten Senke. Senken-Adapter übersetzen zwischen dem senken-agnostischen „Decision"-Objekt und dem jeweiligen Zielsystem. ## 3. Konkrete technische Komponenten | Dienst | Technologie | Verantwortung | | --------------------- | ---------------------------------- | --------------------------------------------------- | | Identity Provider | **Pocket ID** | Benutzeranmeldung (Passkey) und Agent-Clients (OIDC) | | Approval Service | Go, REST API | Inhaltsgebundene Benutzerfreigabe | | 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 dokumentieren | | Policy Decision Point | Open Policy Agent (OPA) | Berechtigungen und Transformationsregeln | | 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 5) | | **Sink Registry** | PostgreSQL | **Registrierte Senken, Adapter-Metadaten, Audience-Keys** | | **Senken-Adapter** | **pro Senke; siehe Abschnitt 7** | **Übersetzt verifizierte Decision in Senken-Aktion** | | Evidence Store | PostgreSQL (Metadaten) + S3 | DSSE-Envelopes und Attestate (Retention: 1 Jahr) | | PII-Store | Verschlüsselt in S3 | Belege und Geschäftsdaten, redaktionierbar | Approval, Attestation, Registry (Agent + Sink) und Verification bleiben in **einem modularen Go-Dienst** zusammengefasst. **Signing Service läuft als eigenes Deployment**. **Senken-Adapter** laufen pro Senken-Typ als eigenes Deployment oder — bei trivialen Senken — als Thin-Client im Buchungs-Agenten. ### 3a. Identity Provider: Pocket ID allein genügt Pocket ID unterstützt neben dem Authorization-Code-Flow auch den OIDC **`client_credentials`-Grant** (Endpunkt `POST /api/oidc/token`) und bietet eine Standard-OIDC-Discovery inkl. JWKS unter `https://auth.basicstack.de/.well-known/openid-configuration`. Damit: - **Menschen** melden sich per Passkey (WebAuthn) über den Authorization-Code-Flow an. - **Agenten** werden in Pocket ID als eigene OIDC-Clients registriert (ein Client pro Agent). Jeder Client erhält `client_id` + `client_secret`, hinterlegt als K8s-Secret im Agent-Namespace. Agenten holen sich daraus kurzlebige Access-Tokens. - **Senken** (insb. externe wie SAP) verifizieren per Pocket-ID-JWKS. Keine Federation nötig. ## 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. Der *Hash* liegt im Evidence Store; der *Inhalt* (PII) im separaten PII-Store. ### Vertrauens- und Verarbeitungskette (allgemein, am Beispiel Reisekosten → beliebige Senke) 1. **Benutzerfreigabe** — Approval Service bindet die Signatur an den Hash des Inhalts, den der Benutzer per Content Binding bestätigt hat (siehe 4.0), und an die OIDC-Identität des Mitarbeiters. 2. **Agent A: Vorbereitung** — Agent A signiert eine Attestierung über Eingabe-Hash, Ausgabe-Hash, Transformationsart und ursprüngliche Freigabe. 3. **Agent B: Mapping auf Senken-Datenmodell** — Agent B signiert seine eigene Attestierung mit Referenz auf die Ausgabe von Agent A. 4. **Agent C: Senken-Übergabe** — Agent C überprüft die komplette Kette, führt die Aktion über den passenden **Senken-Adapter** aus und erzeugt nach erfolgreicher Übergabe einen signierten Übergabenachweis mit Senken-Belegreferenz. Attestierungen sind keine Chatnachrichten, sondern eigenständige, überprüfbare Datensätze. ### 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)` mit einmaligem `challenge_nonce`. 2. Browser zeigt den Inhalt *und* eine aus `H_content + challenge_nonce` abgeleitete, menschenlesbare **Prüfziffer** (z.B. 6 Zeichen Base32). 3. Benutzer bestätigt per Passkey (WebAuthn-Assertion über `challenge_nonce || H_content`). 4. Approval Service verifiziert die WebAuthn-Assertion, prüft Session-Integrität, erzeugt erst dann die DSSE-signierte Approval-Attestierung. Damit scheitert ein kompromittierter Browser, der etwas anderes anzeigt, am visuellen Prüfziffer-Vergleich *oder* am WebAuthn-Signaturinhalt. ### 4.1 Benutzerfreigabe (DSSE-Statement) Beachte: `audience` zeigt auf eine **registrierte Senke** aus der Sink Registry (3b), nicht hart auf „SAP". ```json { "_type": "https://in-toto.io/Statement/v1", "subject": [ { "name": "expense/EXP-2026-0042/v1", "digest": { "sha256": "<64 hex characters>" } } ], "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:", "verification_code": "F3K-9MQ" }, "action": "expense.submit", "audience": "sink:sap-s4hana-prod", "allowed_transformations": ["expense.normalize", "expense.map_to_sink"], "allowed_sinks": ["sink:sap-s4hana-prod", "sink:expense-db-app"], "nonce": "", "issued_at": "2026-10-25T10:30:00Z", "expires_at": "2026-11-01T00:00:00Z" } } ``` Neu: `allowed_sinks` erlaubt in der Freigabe explizit mehrere Zielsenken (z.B. Dual-Write SAP + eigene DB). ### 4.2 Signatur mit DSSE ```json { "payloadType": "application/vnd.in-toto+json", "payload": "", "signatures": [ { "keyid": "approval-service-key-2026-q4", "sig": "" } ] } ``` DSSE's Pre-Authentication Encoding (PAE) signiert Nutzlast und Inhaltstyp gemeinsam. `keyid` ist nur Hinweis — die Identität ergibt sich aus der verifizierten Signatur gegen den zur `issued_at` gültigen Schlüssel in der Agent Registry. ### 4.3 Transformations-Attestierung (Beispiel Agent B — Mapping auf eine konkrete Senke) ```json { "_type": "https://in-toto.io/Statement/v1", "subject": [ { "name": "expense/EXP-2026-0042/sink-payload", "digest": { "sha256": "" } } ], "predicateType": "https://basicstack.de/attestations/transform/v1", "predicate": { "workflow_id": "WF-0042", "actor": "agent-sink-mapping", "operation": "expense.map_to_sink", "sink_target": "sink:sap-s4hana-prod", "materials": [ { "name": "expense/EXP-2026-0042/normalized", "sha256": "" } ], "parent_attestation": "sha256:", "approval_ref": "APR-0042", "schema": { "input": { "name": "expense.canonical", "version": "1.0.0" }, "output": { "name": "sink.sap.expense", "version": "1.2.0" } }, "transform_version": "1.3.0", "issued_at": "2026-10-25T10:31:15Z" } } ``` Agent B signiert diese Attestierung mit seinem eigenen Schlüssel. Wird dieselbe Freigabe auf eine zweite Senke abgebildet (z.B. „sink:expense-db-app"), erzeugt Agent B eine **zweite** Attestierung mit anderem `sink_target` und `output`-Schema. ### 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. ```sql 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). **Retention und Performance.** Rotation Default 90 Tage, Nachweis-Retention 1 Jahr → max. ~5 nicht-archivierte Schlüssel/Agent. Nach Retention: `archived_at` wird gesetzt; Attestierungen jenseits der Retention werden explizit mit `expired_retention` abgelehnt. ### 4.5 Sink Registry Senken sind **registrierte Entitäten** mit eigener Identität, Audit-Vertrag und — falls sinnvoll — eigenem Krypto-Schlüsselmaterial für Übergabenachweise: ```sql CREATE TABLE sinks ( sink_id TEXT PRIMARY KEY, -- z.B. "sink:sap-s4hana-prod" display_name TEXT NOT NULL, adapter_kind TEXT NOT NULL, -- "sap_abap" | "db_app" | "http_webhook" | "message_queue" | "file_drop" | "custom" endpoint_url TEXT, -- primary endpoint (sofern HTTP) idempotency_scope TEXT NOT NULL, -- "payload_hash" | "workflow_id" | "sink_defined" callback_pubkey_pem TEXT, -- optional: Senke signiert eigene Buchungsnachweise allowed_actions TEXT[] NOT NULL, owner_team TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL, retired_at TIMESTAMPTZ ); ``` Der Verification Service verifiziert bei jedem Aufruf: `requested_action ∈ sink.allowed_actions` und `sink.retired_at IS NULL`. ## 5. Verifikation beim empfangenden Senken-Adapter Der Senken-Adapter (oder — bei Thin-Client-Senken — Agent C) darf sich nicht auf die mitgesendeten IDs verlassen. Er muss die gesamte Nachweiskette prüfen. ``` POST /api/v1/attestations/verify Authorization: Bearer Content-Type: application/json ``` ```json { "workflow_id": "WF-0042", "artifact_digest": "sha256:", "requested_action": "expense.post", "target": "sink:sap-s4hana-prod" } ``` Prüfungen: | Prüfung | Fehlerfall | | -------------------------------------------------------------------- | --------------------- | | Signatur der Benutzerfreigabe gültig (Schlüssel zur `issued_at` gültig)? | 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 | | `target` in Sink Registry registriert 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 | | Transformationen laut Freigabe zulässig? | Ablehnen | | Schema-Version der kanonischen Daten mit Approval kompatibel? | Ablehnen | | Nutzlast entspricht freigegebener Geschäftssemantik (OPA)? | Ablehnen | | `payload_hash` bereits für `target` übergeben? | Keine erneute Übergabe | Erfolgsantwort: ```json { "valid": true, "workflow_id": "WF-0042", "original_user": { "issuer": "https://auth.basicstack.de", "subject": "user-12345" }, "actors": ["agent-travel", "agent-sink-mapping"], "authorized_action": "expense.post", "artifact_digest": "sha256:", "decision_id": "DEC-2026-0042", "decision_nonce": "", "bound_to_agent": "agent-sink-posting", "bound_to_target": "sink:sap-s4hana-prod", "expires_at": "2026-10-25T10:36:00Z" } ``` ### 5.1 Replay-Schutz (verbindlich) - `decision_id` enthält einen `decision_nonce`, Lebensdauer 5 Minuten. - Decision ist gebunden an `(agent_id, payload_hash, target)` — Zieländerung oder Agent-Wechsel invalidiert sie. - Verification Service hält eine Postgres-Tabelle `decisions` mit `UNIQUE (payload_hash, target)` für den Doppelübergabe-Check. - Jeder Senken-Adapter führt eine **eigene** Replay-Tabelle (`sink_decision_log`) mit `UNIQUE (decision_id)` und `UNIQUE (payload_hash)`. Defence in Depth, denn der Trust-Core kennt die Idempotenz-Eigenschaften der Senke nicht. - Doppelübergabe wird gegen `payload_hash` (nicht nur `workflow_id`) geprüft. ## 6. Berechtigungssteuerung mit Open Policy Agent Beispiel-Regeln (bewusst nicht ERP-spezifisch): - Agent A darf Belege extrahieren und Geschäftsdaten strukturieren. - Agent B darf Kontierungs- oder Zieldaten ergänzen und Felder auf das Senken-Schema zuordnen. - Agent B darf keine Beträge oder Währungen ohne zusätzliche Freigabe ändern. - Agent C darf ausschließlich vollständig validierte Vorgänge an Senken übergeben, und zwar nur an Senken aus `allowed_sinks` der Freigabe. - Pro Senken-Typ können zusätzliche Policies greifen (z.B. „Senke `db-app` erlaubt Updates, Senke `sap-s4hana-prod` nur Inserts"). Rego-Policies werden zentral verwaltet und versioniert; die zum Entscheidungszeitpunkt verwendete Policy-Version wird im Evidence Store mit abgelegt. ### 6.1 Fachliche Integritätsprüfung — Schema-Versionierung (verbindlich) Ein Hashvergleich allein reicht nicht, weil sich beim Mapping das technische Format ändert. Deshalb binden wir die Freigabe an ein **versioniertes kanonisches Schema**: ```json { "schema": { "name": "expense.canonical", "version": "1.0.0" }, "employee_id": "EMP-12345", "currency": "EUR", "total_amount": "428.50", "expense_items": [ { "type": "HOTEL", "amount": "328.50" }, { "type": "MEALS", "amount": "100.00" } ] } ``` Verbindlich: - Kanonische Schemas und Senken-spezifische Zielschemas liegen versioniert in `schemas/` im Repo. - Jede Approval-Attestierung signiert `schema.name` und `schema.version` mit. - Jede Transform-Attestierung signiert Input- *und* Output-Schema plus `sink_target`. - OPA-Policies arbeiten gegen das kanonische Schema; sie prüfen z.B. „Agent B darf `total_amount` nicht verändern" oder „Agent B darf `expense_items[].amount` höchstens kaufmännisch runden". - Schema-Änderungen sind Breaking Changes und erfordern eine neue Hauptversion. ## 7. Senken-Integration (generalisiert) Der Trust-Core ist senken-agnostisch. Jede Senke wird über einen **Senken-Adapter** angebunden, der denselben Vertrag erfüllt. SAP S/4HANA ist eine Senken-Implementierung; weitere Beispiele siehe 7.1–7.5. ### 7.0 Vertrag jedes Senken-Adapters Jeder Adapter MUSS: 1. **Verifizieren** — ruft `POST /api/v1/attestations/verify` auf (oder bettet die Verifikationslogik mit eingezogenen Schlüsseln ein) und bricht bei `valid=false` oder abgelaufener Decision ab. 2. **Idempotent sein** — führt eine eigene Tabelle `sink_decision_log` mit `UNIQUE (decision_id)` und `UNIQUE (payload_hash)`. 3. **Audit-Mindestdaten speichern** — pro erfolgreicher Übergabe: `workflow_id`, `approval_id`, `decision_id`, `payload_hash`, `agent_id`, `original_user_sub`, `sink_record_ref` (z.B. Belegnummer / DB-ID / Message-ID / Dateipfad), `created_at`. 4. **Übergabenachweis zurückgeben** — signierte Antwort (ideal: Senke besitzt eigenen Schlüssel in `sinks.callback_pubkey_pem`; Fallback: Agent C signiert die unsignierte Senken-Antwort inkl. `sink_record_ref` selbst). 5. **Fehlerpfad definieren** — nach N fehlgeschlagenen Versuchen fließt der Vorgang in eine senken-eigene Operator-Queue oder meldet strukturierten Fehler an den Trust-Core (`sink_delivery_failed`-Attestierung). 6. **Mapping zu Business-IDs** darf nur serverseitig passieren — eine vom Agenten gelieferte Personalnummer / Benutzer-ID / Kostenstelle darf eine im Senken-System hinterlegte Zuordnung nicht überschreiben. Die Verification Service-Antwort ist senken-agnostisch (`decision_id`, `bound_to_target`, `bound_to_agent`, `authorized_action`). Was die Senke damit tut, ist adapter-spezifisch. ### 7.1 Beispiel: SAP S/4HANA (Senke `sink:sap-s4hana-prod`) ABAP-Integrationsschicht statt direktem Agentenzugriff auf Buchungsfunktionen. Fluss: `Agent C` → `ABAP REST Endpoint` → `SAP-Anwendungslogik`. ``` POST /sap/bc/zexpense/v1/submit Authorization: Bearer Idempotency-Key: WF-0042 Content-Type: application/json ``` ```json { "workflow_id": "WF-0042", "approval_id": "APR-0042", "verification_ref": "DEC-2026-0042", "expense_ref": "EXP-2026-0042", "payload_hash": "sha256:" } ``` Vor der Buchung ruft ABAP den Validierungs-Webservice: ``` POST /api/v1/decisions/{decision_id}/replay-check ``` Rückgabe: ob Decision noch gültig, nicht verbraucht, an Agent C und Target gebunden. **sap-agent-token** wird manuell im SAP-System hinterlegt. Rotation: neuer JWT (90 Tage) wird vom Signing Service erzeugt, Operator trägt in SM59 ein, alte und neue Token sind während Rollover parallel gültig. **SAP-Audit** liegt in Tabelle `ZAGENT_AUDIT` (`WORKFLOW_ID`, `APPROVAL_ID`, `USER_SUB`, `PERNR`, `AGENT_ID`, `PAYLOAD_HASH`, `VERIFICATION_ID`, `DECISION_ID`, `BUKRS/BELNR/GJAHR`, `CREATED_AT`), mit `UNIQUE (WORKFLOW_ID)` und `UNIQUE (DECISION_ID)`. ### 7.2 Beispiel: Eigene Datenbankapplikation (Senke `sink:expense-db-app`) Minimale Senken-Variante: eine selbst gebaute Postgres-App (eigener Microservice). Fluss: `Agent C` → HTTPS/mTLS → `expense-db-adapter` (Go-Service) → `expense-postgres`. ``` POST /api/v1/expense/submit Authorization: Bearer # Pocket-ID-Access-Token Content-Type: application/json ``` Der Adapter: - verifiziert das Pocket-ID-Token gegen JWKS, - ruft Verification Service (`POST /api/v1/attestations/verify`), - schreibt in `sink_decision_log` (Idempotenz), - führt die Business-Insert/Update-Transaktion aus, - gibt `sink_record_ref` (z.B. `db:expense_app/expenses/`) an Agent C zurück. Idempotenz: `UNIQUE (decision_id)` und `UNIQUE (payload_hash)` in `sink_decision_log`. Business-Tabelle hat `UNIQUE (workflow_id)`. Vorteil gegenüber SAP: keine externe Krypto-Vertrauensbasis nötig; Adapter kann unmittelbar auf Agent Registry und JWKS zugreifen. ### 7.3 Beispiel: Generischer HTTP-Webhook (Senke `sink:custom-webhook-*`) Für externe Dienste, die nur „einen HTTP-POST entgegennehmen" können. ``` POST Authorization: Bearer # pro Senke in Sink Registry X-Decision-Id: DEC-2026-0042 X-Payload-Hash: sha256: Idempotency-Key: Content-Type: application/json ``` Der Senken-Adapter läuft **auf unserer Seite** (nicht im externen System), weil wir die Verifikation vor dem Push durchführen müssen. Er verwaltet pro Senke: - Secret für `Authorization`-Header (im K8s-Secret), - Retry-Backoff (3 Versuche, exponentiell), - Rückmeldung an Agent C mit `sink_record_ref: "http::"`. Falls die Senke keine Response-ID liefert, generiert der Adapter eine aus `H(decision_id || endpoint_url)`. ### 7.4 Beispiel: Message-Queue (Senke `sink:nats-kafka-*`) Für asynchrone Übergaben an interne Downstream-Systeme (Analytics, Replikation). Der Senken-Adapter publiziert nach erfolgreicher Verifikation einen Event auf einem Topic. Payload enthält `workflow_id`, `decision_id`, `payload_hash` und (sofern erlaubt) den fachlichen Nutzinhalt. Idempotenz: Queue-Message-Deduplication-Key = `decision_id`. Senken-Belegnummer = Queue-Message-ID. ### 7.5 Beispiel: Dateiablage (Senke `sink:sftp-*`, `sink:s3-*`) Für Export in Partnerumgebungen (SFTP) oder Cold-Storage. Der Adapter legt eine Datei mit kanonischem Namen (`_.json`) ab, signiert sie als DSSE und schreibt eine Index-Zeile in `sink_decision_log`. Dateipfad = `sink_record_ref`. ### 7.6 Welchen Adapter wo deployen? | Senke | Adapter läuft bei uns | Adapter läuft im Zielsystem | | -------------------- | --------------------- | --------------------------- | | SAP S/4HANA | nein (dünner Agent C) | ja (ABAP-Endpoint + Validierungs-Webservice-Call) | | Eigene DB-App | ja (`expense-db-adapter`) | — | | HTTP-Webhook extern | ja (`webhook-adapter`) | — | | Message-Queue | ja (`queue-adapter`) | — | | Dateiablage | ja (`file-adapter`) | — | | Legacy (Mail/EDI) | ja (adapter spezifisch) | — | Daumenregel: Wenn das Zielsystem eigene Autorisierungs-/Audit-Funktionen hat (SAP), bringen wir dort einen dünnen Verifier unter. Wenn nicht, läuft der komplette Adapter in unserem Cluster. ## 8. Nachweisablage und Transparency Log ### 8.1 Scope und Retention **Ziel:** kryptografisch belegen, dass die Agent-Kommunikation unverfälscht gelaufen ist, und diese Prüfung nachträglich zulassen. **Kein** rechtssicheres GoBD-Archiv. **Retention Default: 1 Jahr.** Nach Ablauf werden Attestierungen, Decisions und zugehörige Schlüsselhistorie automatisiert gelöscht. Konfigurierbar pro Prozess-Typ *und pro Senken-Typ* (z.B. Webhook-Senken kürzer). ### 8.2 Datenklassen | Daten | Speicherung | | --------------------------------------- | ---------------------------------------- | | Prozessstatus, Identitäten, Referenzen | PostgreSQL (`trust-postgres`) | | Senken-Registrierung | PostgreSQL (`trust-postgres`) | | Signierte Attestierungen (DSSE) | S3 Object Storage | | Transparency-Log-Einträge + Proofs | Trillian + PostgreSQL | | Reisekostenbelege und Geschäftsdaten | Verschlüsselt in S3 (separater Bucket, PII-Store) | | Signatur- und Schlüsselhistorie | Agent Registry (Postgres), max 1 Jahr | | Policy-Versionen | Git-versioniert, Hash im Evidence Store | | Senken-Übergabenachweise | S3 + Index in `sink_decision_log` der jeweiligen Senke | **Strikte Trennung PII vs. Nachweis.** ### 8.3 Warum Trillian + PostgreSQL (nicht Cassandra) Ein Transparency Log ist ein append-only Merkle-Tree mit Inclusion Proofs und signierten Tree-Heads. Entscheidend: strikte Reihenfolge, starke Konsistenz, Inclusion Proofs in ms. Cassandra ist dafür ungeeignet (eventual consistency, Ordering nur per Partition). Trillian + PostgreSQL ist bewährt (Basis von sigstore rekor), passt in unsere bestehende Postgres-Infrastruktur und reicht für < 1 Mio Einträge/Jahr auf einer kleinen Instanz. Täglicher signierter Log-Root wird ins Backup-System gespiegelt. ## 9. Deployment in Kubernetes ``` identity/ pocket-id agent-trust/ trust-api (Approval + Attestation + Agent Registry + Sink Registry + Verification) signing-service (eigenes Deployment, enge Trust-Boundary) policy-engine (OPA) trust-postgres trillian-log transport/ nats (JetStream für Agent↔Agent) paperclip/ paperclip agent-travel agent-sink-mapping agent-sink-posting sinks/ expense-db-adapter (für sink:expense-db-app) expense-db-postgres webhook-adapter (für sink:custom-webhook-*) queue-adapter (für sink:nats-kafka-*) file-adapter (für sink:sftp-*, sink:s3-*) # SAP-Adapter läuft als ABAP im SAP-System (nicht in K8s) openbao/ openbao matrix/ (optional, Phase 5) synapse element-web agent-matrix-gateway ``` ### 9.1 Workload-Identitäts-Prüfung (doppelt) Der Signing Service verifiziert für jeden Request **beide** Credentials: 1. **Pocket-ID-Access-Token** (Header `Authorization: Bearer`) — gegen Pocket-ID-JWKS; `sub = agent-` muss zu einem registrierten Agent passen. 2. **Projected ServiceAccount-Token** (Header `X-Workload-Token`, Audience `signing-service.agent-trust`) — gegen K8s TokenReview; Namespace + ServiceAccount müssen zum Agent in der Registry passen. Nur wenn beide auf denselben `agent_id` auflösen, wird signiert. OpenBao Transit signiert Ed25519. Caveat: Transit kennt kein DSSE — der Signing Service berechnet die DSSE-PAE selbst und übergibt nur den Hash an Transit. ## 10. Implementierungsreihenfolge **Phase 1 — End-to-End-Skelett (3–5 Wochen)** Pocket ID als IdP, Approval Service mit Content Binding, ein Testagent mit Ed25519-Schlüssel in der Agent Registry, Signing Service mit doppelter Identitätsprüfung, Verification Service für zweistufige Kette, **eine triviale Senke** (`sink:dummy-sink` als Mock-Adapter in Go) für den vollständigen Durchlauf. **Phase 2 — Agent Attestations in Breite** Weitere Agenten, Schlüsselrotation, in-toto-Transformationsnachweise, OPA-Policies, Policy-Versionierung. **Phase 3 — Replay-Schutz, Transparency Log, Retention** Trillian-Deployment, Decision-Nonce-Mechanik, Decision-Replay-Tabellen, Retention-Cron-Jobs, PII-Store-Trennung. **Phase 4 — Erste produktive Senke(n)** Ein echter Senken-Adapter — Reihenfolge nach Business-Priorität: - Variante A: **SAP S/4HANA** (ABAP-Endpunkt, serverseitige Mitarbeiterzuordnung, SM59-Rotationsprozess, Validierungs-Webservice). - Variante B: **Eigene DB-Applikation** (Go-Adapter mit Postgres, einfacher zu bauen, geeignet als Pilot). Beide Varianten nutzen denselben Senken-Vertrag aus 7.0. Welche zuerst gebaut wird, entscheidet die Produkt-Priorität. **Phase 5 — Weitere Senken-Typen** HTTP-Webhook-Adapter, Message-Queue-Adapter, File-Adapter — Baumuster steht nach Phase 4, inkrementell. **Phase 6 — Matrix für Mensch-Chat (optional)** Nur Mensch↔Agent-Chat, E2EE. Agent↔Agent läuft weiter über NATS/HTTPS. ## 11. Was bewusst anders ist als in V1.0 - SAP ist **eine** Senke, nicht das Ziel. Trust-Core ist senken-agnostisch, Senken sind Plug-ins mit festem Vertrag. - Matrix ist **nicht** Standard-Transport — nur optionale Mensch-Chat-Schicht. - Transparency Log ist eigene Komponente (Trillian), nicht nur Postgres-Tabelle. - Signing Service ist eigenes Deployment ab Tag 1. - PII-Store ist strikt getrennt vom Evidence Store. - Keine Unveränderbarkeits-/GoBD-Garantien — Retention 1 Jahr. - Pocket ID ist alleiniger IdP. ## 12. Empfohlener Kernstack (Zielbild) | Identität | Pocket ID (Menschen + Agent-Clients) | | ------------- | ------------------------------------------------------------------- | | Workload-ID | K8s projected ServiceAccount Token + TokenReview | | Signaturen | Ed25519 / DSSE, OpenBao Transit | | Provenienz | in-toto v1, predicate-Namespace `basicstack.de/attestations/*/*` | | Autorisierung | OPA (Rego) + Approval Service | | Transparency | Trillian + PostgreSQL | | Transport | HTTPS/mTLS + NATS JetStream (Agent↔Agent); Matrix optional (Mensch) | | Agenten | Paperclip | | **Senken** | **Plug-in-Architektur** — SAP S/4HANA (ABAP), eigene DB-Apps (Go-Adapter), HTTP-Webhooks, Message-Queues, Dateiablage | | Evidence | PostgreSQL + S3 (Retention 1 Jahr) | | PII | Separater verschlüsselter S3-Bucket, redaktionierbar | **Wichtigste Empfehlung bleibt:** Zuerst in Phase 1 ein vollständiger signierter Testdurchlauf mit einer trivialen Mock-Senke. Erst in Phase 4 wird die erste echte Senke angebunden — ob SAP oder eine eigene DB-App entscheidet die Produkt-Priorität.