docs(architecture): generalize sink concept — SAP is one of many sinks, add sink adapter contract

This commit is contained in:
CTO Agent 2026-10-25 14:11:34 +00:00
parent 7de9cbc6ec
commit 9f89f9fb6b

View file

@ -1,47 +1,50 @@
# Technische Zielarchitektur: Vertrauenswürdige Kommunikation zwischen Menschen, KI-Agenten und SAP
# 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)
**Änderungen gegenüber V1.0:** siehe Abschnitt 0 „Änderungen seit V1.0"
**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. Der empfangende Agent überprüft die vollständige Kette, bevor er eine Aktion ausführt.**
> **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 aus der ersten Review-Runde um:
Diese Revision setzt die Richtungsentscheidungen der ersten beiden Review-Runden um:
- **Scope Evidence Store (A.1/A.2):** kein rechtssicherer, kein WORM-/GoBD-Anspruch. Ziel ist der kryptografische Nachweis einer unverfälschten Kommunikation während eines **begrenzten Zeitraums** (Default: 1 Jahr). Danach dürfen Nachweise verworfen werden.
- **PII-Trennung (A.1):** verbindlich eingezogen. Attestierungen enthalten nur Hashes und Referenzen; personenbezogene Inhalte liegen in einem separaten, redaktionierbaren PII-Store.
- **IdP (A.3, A.5):** **Pocket ID** wird einziger IdP — für Menschen *und* Agenten. Begründung und Mechanik in Abschnitt 3a. Keycloak wird nicht eingeführt.
- **Content Binding (A.4):** eigener Abschnitt 4.0 als verbindliches UX-/Signatur-Protokoll.
- **Workload-Identität (A.5):** Agenten authentifizieren sich doppelt — Pocket-ID-`client_credentials`-Token *plus* projiziertes Kubernetes-ServiceAccount-Token. Signing Service verifiziert beide.
- **Schlüsselbund-Scope (A.6):** Historische Schlüssel werden nur für die aktive Nachweis-Retention vorgehalten (Default 1 Jahr). Rotation Default 90 Tage → max. ~5 Schlüssel pro Agent gleichzeitig gültig für die Verifikation.
- **Transparency Log (A.7, B.2):** PostgreSQL + Trillian-Merkle-Log statt Cassandra. Begründung in Abschnitt 8.
- **Replay-Schutz (A.8) und Fachliche Integritätsprüfung (A.9):** jetzt verbindliche Abschnitte 5.1 und 6.1.
- **ABAP-Token (A.10):** manuell im SAP-System hinterlegt (bestätigt). Rotationsprozess siehe Abschnitt 7.
- **Matrix (B.1):** verschoben in optionale Phase 5, nur für Mensch↔Agent-Chat. Agent↔Agent-Transport ist HTTPS/mTLS + NATS JetStream.
- **Signing Service (B.3):** eigenes Deployment von Tag 1.
- **Phase 1 (B.4):** End-to-End-Pfad mit einem Agenten als Abschluss.
- **predicateType-Namespace (B.5):** `https://basicstack.de/attestations/<domain>/<version>`.
- **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/<domain>/<version>`.
- **🆕 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 ERP-Aktionen.
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 |
@ -56,50 +59,51 @@ Logische Komponentenübersicht, keine direkte Netzwerktopologie. Freigabe- und A
| 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) |
| SAP Connector | ABAP REST API / OData | Validierte Buchungsaufträge |
| **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 und Verification bleiben in **einem modularen Go-Dienst** zusammengefasst. Separate APIs und Module bleiben erhalten, aber der Betrieb vieler kleiner Microservices wird vermieden. **Signing Service läuft als eigenes Deployment** mit separater Trust-Boundary.
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: warum Pocket ID reicht
### 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 decken wir beide Welten:
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 normalen Authorization-Code-Flow an.
- **Agenten** werden in Pocket ID als eigene OIDC-Clients registriert (ein Client pro Agent, z.B. `agent-travel`, `agent-sap-mapping`, `agent-sap-posting`). Jeder Client erhält eine `client_id` + ein `client_secret`, das im zugehörigen Kubernetes-Namespace als Secret hinterlegt wird. Der Agent holt sich daraus ein kurzlebiges Access-Token per `client_credentials`.
- **SAP** (bzw. die ABAP-Validierungs-Webservice-Logik aus Abschnitt 7) kann denselben Pocket-ID-JWKS-Endpunkt nutzen, um ein von Agent C präsentiertes Token zu verifizieren — ohne Federation, ohne weiteren IdP.
Keycloak wird **nicht** eingeführt. Das spart einen betriebskritischen Dienst.
- **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 (z.B. Reisekostenabrechnung) 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) liegt im separaten PII-Store.
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
### Vertrauens- und Verarbeitungskette (allgemein, am Beispiel Reisekosten → beliebige Senke)
1. **Benutzerfreigabe** — Approval Service bindet die Signatur an den Hash des Inhalts, den der Benutzer tatsächlich im Browser gesehen und 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 die ursprüngliche Freigabe.
3. **Agent B: SAP-Mapping** — Agent B signiert seine eigene Attestierung und referenziert die Ausgabe von Agent A.
4. **Agent C: SAP-Buchung** — Agent C überprüft die komplette Kette und erzeugt nach erfolgreicher Buchung einen signierten Buchungsnachweis.
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
Das Risiko: der Browser könnte dem Benutzer etwas anderes zeigen als dem Approval Service.
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 dessen SHA-256-Hash `H_content` und speichert `(session_id, H_content, salt)` zusammen mit einem einmaligen `challenge_nonce`.
2. Browser zeigt den Inhalt **und** eine aus `H_content + challenge_nonce` abgeleitete, menschenlesbare **Prüfziffer** (z.B. 6 Zeichen Base32) als visuelles Fingerprinting an.
3. Benutzer bestätigt per Passkey (WebAuthn-Signatur über `challenge_nonce || H_content`). Die WebAuthn-Challenge enthält `H_content` als Teil der Assertion-Daten — der Hardware-Authenticator signiert damit explizit das, was der Server und (per Prüfziffer) der Benutzer gesehen haben.
4. Approval Service verifiziert die WebAuthn-Assertion gegen den registrierten Passkey, prüft, dass die Session-Daten unverändert sind, und erzeugt erst dann die DSSE-signierte Approval-Attestierung.
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 dem Benutzer eine andere Zahl zeigt, am visuellen Prüfziffer-Vergleich *oder* am WebAuthn-Signaturinhalt.
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",
@ -113,10 +117,7 @@ Damit scheitert ein kompromittierter Browser, der dem Benutzer eine andere Zahl
"predicate": {
"workflow_id": "WF-0042",
"approval_id": "APR-0042",
"schema": {
"name": "expense.canonical",
"version": "1.0.0"
},
"schema": { "name": "expense.canonical", "version": "1.0.0" },
"issuer": "approval-service",
"user": {
"iss": "https://auth.basicstack.de",
@ -128,8 +129,9 @@ Damit scheitert ein kompromittierter Browser, der dem Benutzer eine andere Zahl
"verification_code": "F3K-9MQ"
},
"action": "expense.submit",
"audience": "sap-expense-workflow",
"allowed_transformations": ["expense.normalize", "expense.map_to_sap"],
"audience": "sink:sap-s4hana-prod",
"allowed_transformations": ["expense.normalize", "expense.map_to_sink"],
"allowed_sinks": ["sink:sap-s4hana-prod", "sink:expense-db-app"],
"nonce": "<base64 nonce for replay protection>",
"issued_at": "2026-10-25T10:30:00Z",
"expires_at": "2026-11-01T00:00:00Z"
@ -137,7 +139,7 @@ Damit scheitert ein kompromittierter Browser, der dem Benutzer eine andere Zahl
}
```
Der Approval Service darf dieses Dokument nur erzeugen, wenn die WebAuthn-Signatur über dem Content-Hash gültig ist. Ein Agent darf diesen Endpunkt nicht mit einer frei angegebenen Benutzer-ID aufrufen.
Neu: `allowed_sinks` erlaubt in der Freigabe explizit mehrere Zielsenken (z.B. Dual-Write SAP + eigene DB).
### 4.2 Signatur mit DSSE
@ -151,24 +153,25 @@ Der Approval Service darf dieses Dokument nur erzeugen, wenn die WebAuthn-Signat
}
```
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 das in der Agent Registry zum `issued_at` gültige öffentliche Schlüsselmaterial.
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)
### 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/sap-payload",
"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-sap-mapping",
"operation": "expense.map_to_sap",
"actor": "agent-sink-mapping",
"operation": "expense.map_to_sink",
"sink_target": "sink:sap-s4hana-prod",
"materials": [
{ "name": "expense/EXP-2026-0042/normalized", "sha256": "<input hash>" }
],
@ -176,7 +179,7 @@ DSSE's Pre-Authentication Encoding (PAE) signiert Nutzlast und Inhaltstyp gemein
"approval_ref": "APR-0042",
"schema": {
"input": { "name": "expense.canonical", "version": "1.0.0" },
"output": { "name": "sap.expense.payload", "version": "1.2.0" }
"output": { "name": "sink.sap.expense", "version": "1.2.0" }
},
"transform_version": "1.3.0",
"issued_at": "2026-10-25T10:31:15Z"
@ -184,16 +187,14 @@ DSSE's Pre-Authentication Encoding (PAE) signiert Nutzlast und Inhaltstyp gemein
}
```
Agent B signiert diese Attestierung mit seinem eigenen Schlüssel.
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 (unsere Postgres-Tabelle):** die Identität plus Signatur-Schlüsselhistorie.
Schema (vereinfacht):
- **Agent Registry (Postgres):** Identität plus Signatur-Schlüsselhistorie.
```sql
CREATE TABLE agents (
@ -207,14 +208,14 @@ CREATE TABLE agents (
);
CREATE TABLE agent_keys (
key_id TEXT PRIMARY KEY, -- z.B. "agent-travel-2026-q4"
key_id TEXT PRIMARY KEY,
agent_id TEXT NOT NULL REFERENCES agents(agent_id),
public_key_pem TEXT NOT NULL, -- Ed25519
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 -- gesetzt wenn außerhalb Retention
archived_at TIMESTAMPTZ
);
CREATE INDEX idx_agent_keys_lookup
@ -222,13 +223,34 @@ CREATE INDEX idx_agent_keys_lookup
WHERE archived_at IS NULL;
```
**Validierung alter Attestierungen** nutzt den Schlüssel, der zum `issued_at` der Attestierung galt (`valid_from ≤ issued_at < valid_to`, nicht `revoked_at` vor `issued_at`). Das ist das TUF-Pattern.
**Validierung alter Attestierungen** nutzt den Schlüssel, der zur `issued_at` galt (TUF-Pattern).
**Retention und Performance.** Default-Rotation **90 Tage**, Nachweis-Retention **1 Jahr** → pro Agent max. ~5 nicht-archivierte Schlüssel. Beim Überschreiten der Retention wird der Schlüssel auf `archived_at` gesetzt; alte Attestierungen, die noch im Evidence Store liegen, aber über diese Grenze hinaus zu validieren wären, werden explizit abgelehnt (`decision: expired_retention`). Damit bleibt der aktive Keyring klein und die Validierung konstant schnell — auch bei 100+ Agenten.
**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.
## 5. Verifikation beim empfangenden Agenten
### 4.5 Sink Registry
Der SAP-Agent darf sich nicht auf die mitgesendeten IDs verlassen. Er muss die gesamte Nachweiskette prüfen.
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
@ -240,24 +262,28 @@ Content-Type: application/json
{
"workflow_id": "WF-0042",
"artifact_digest": "sha256:<final hash>",
"requested_action": "expense.post_to_sap",
"target": "sap-s4hana-prod"
"requested_action": "expense.post",
"target": "sink:sap-s4hana-prod"
}
```
Prüfungen:
| Prüfung | Fehlerfall |
| -------------------------------------------------------------------- | --------------------- |
| Signatur der Benutzerfreigabe gültig (Schlüssel zum `issued_at` gültig)? | Ablehnen |
| 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 |
| SAP-Nutzlast entspricht freigegebener Geschäftssemantik (OPA)? | Ablehnen |
| `payload_hash` bereits für `target` gebucht? | Keine erneute Buchung |
| Nutzlast entspricht freigegebener Geschäftssemantik (OPA)? | Ablehnen |
| `payload_hash` bereits für `target` übergeben? | Keine erneute Übergabe |
Erfolgsantwort:
@ -266,41 +292,40 @@ Erfolgsantwort:
"valid": true,
"workflow_id": "WF-0042",
"original_user": { "issuer": "https://auth.basicstack.de", "subject": "user-12345" },
"actors": ["agent-travel", "agent-sap-mapping"],
"authorized_action": "expense.post_to_sap",
"actors": ["agent-travel", "agent-sink-mapping"],
"authorized_action": "expense.post",
"artifact_digest": "sha256:<final hash>",
"decision_id": "DEC-2026-0042",
"decision_nonce": "<base64>",
"bound_to_agent": "agent-sap-posting",
"bound_to_target": "sap-s4hana-prod",
"bound_to_agent": "agent-sink-posting",
"bound_to_target": "sink:sap-s4hana-prod",
"expires_at": "2026-10-25T10:36:00Z"
}
```
Diese Decision ist eine kurzlebige, an Agent C + Payload-Hash + Target gebundene Ausführungsberechtigung.
### 5.1 Replay-Schutz (verbindlich)
- `decision_id` enthält einen eigenen `decision_nonce`, Lebensdauer **5 Minuten**.
- `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 Doppelbuchungs-Check.
- SAP-Connector führt eine **eigene** Replay-Tabelle (`sap_decision_log`) mit `UNIQUE (decision_id)`. Beide Prüfungen sind unabhängig voneinander — Defence in Depth.
- Doppelbuchung wird gegen `payload_hash` (nicht nur `workflow_id`) geprüft, damit minimal veränderte Nutzlasten nicht durchrutschen.
- 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:
Beispiel-Regeln (bewusst nicht ERP-spezifisch):
- Agent A darf Belege extrahieren und Reisekosten strukturieren.
- Agent B darf Kontierungsinformationen ergänzen und SAP-Felder zuordnen.
- 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 Reisekostenabrechnungen buchen.
- 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 verändert. Deshalb binden wir die Freigabe an ein **versioniertes kanonisches Schema**:
Ein Hashvergleich allein reicht nicht, weil sich beim Mapping das technische Format ändert. Deshalb binden wir die Freigabe an ein **versioniertes kanonisches Schema**:
```json
{
@ -317,17 +342,34 @@ Ein Hashvergleich allein reicht nicht, weil sich beim Mapping das technische For
Verbindlich:
- Schemas werden als JSON Schema in `schemas/` im Repo versioniert.
- 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.
- 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. SAP S/4HANA Integration
## 7. Senken-Integration (generalisiert)
Für die S/4HANA-2023-Umgebung ist eine ABAP-Integrationsschicht vorgesehen, statt Agent C direkten Zugriff auf Buchungsfunktionen zu geben.
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.
Fluss: `Agent C` → `ABAP REST Endpoint` (Authentifizierung · Freigabenachweis · Idempotenz) → `SAP-Anwendungslogik` (Mitarbeiterzuordnung · fachliche Prüfungen · Buchung).
### 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
@ -346,96 +388,125 @@ Content-Type: application/json
}
```
Zusätzlich stellt ProofedMesh einen **Validierungs-Webservice** bereit, den das ABAP vor der Buchung aufruft:
Vor der Buchung ruft ABAP den Validierungs-Webservice:
```
POST /api/v1/decisions/{decision_id}/replay-check
```
Rückgabe: ob die Decision noch gültig, nicht verbraucht, an Agent C gebunden und für dieses `target` autorisiert ist. Damit braucht SAP keine eigene Krypto-Logik.
Rückgabe: ob Decision noch gültig, nicht verbraucht, an Agent C und Target gebunden.
**Zwei unabhängige Prüfungen** in SAP:
**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.
- **Technische Identität:** Der Aufruf kommt vom autorisierten SAP-Agenten (Bearer-Token-Prüfung).
- **Fachliche Identität:** Der freigebende Benutzer wird über eine serverseitig gepflegte Zuordnung der korrekten SAP-Personalnummer zugeordnet. Eine vom Agenten gelieferte Personalnummer darf diese Zuordnung nicht überschreiben.
**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)`.
**sap-agent-token** wird manuell im SAP-System hinterlegt. Rotationsprozess:
### 7.2 Beispiel: Eigene Datenbankapplikation (Senke `sink:expense-db-app`)
1. Signing Service oder Operator generiert neues Token (JWT, 90-Tage-Gültigkeit) und signiert es mit dem Service-Schlüssel von Agent C.
2. Operator trägt neues Token in SAP ein (Transaktion `SM59` oder äquivalent, abhängig von der konkreten SAP-Konfiguration).
3. Agent C erhält das neue Token über ein K8s-Secret; alte Secrets werden nach einer Übergangszeit entfernt.
4. SAP-Validierung akzeptiert alte und neue Token, solange sie signiert sind — die Agent-Identität wird aus dem Token-`sub` gelesen, nicht aus dem Token-Material selbst.
Minimale Senken-Variante: eine selbst gebaute Postgres-App (eigener Microservice).
**Welche SAP-Buchungsschnittstelle** verwendet wird (SAP Travel Management, Concur, kundeneigener FI-Prozess), bleibt in einem späteren ADR offen — architektonisch ist das austauschbar.
Fluss: `Agent C` → HTTPS/mTLS → `expense-db-adapter` (Go-Service) → `expense-postgres`.
### SAP-Auditdaten
```
POST /api/v1/expense/submit
Authorization: Bearer <agent-c-oidc-token> # Pocket-ID-Access-Token
Content-Type: application/json
```
Zusätzlich zum ERP-Beleg: Tabelle `ZAGENT_AUDIT`.
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/<uuid>`) an Agent C zurück.
| Feld | Inhalt |
| --------------------- | ---------------------------------- |
| WORKFLOW_ID | Eindeutige Prozess-ID |
| APPROVAL_ID | Benutzerfreigabe |
| USER_SUB | Externe Benutzeridentität |
| PERNR | Zugeordnete Personalnummer |
| AGENT_ID | Buchender Agent |
| PAYLOAD_HASH | SHA-256 der Buchungsdaten |
| VERIFICATION_ID | Verifikationsentscheidung |
| DECISION_ID | Replay-Check-Referenz |
| BUKRS / BELNR / GJAHR | FI-Belegreferenz |
| CREATED_AT | Buchungszeitpunkt |
Idempotenz: `UNIQUE (decision_id)` und `UNIQUE (payload_hash)` in `sink_decision_log`. Business-Tabelle hat `UNIQUE (workflow_id)`.
Idempotenz: `UNIQUE (WORKFLOW_ID)` *und* `UNIQUE (DECISION_ID)`. Bei N fehlgeschlagenen Buchungsversuchen landet der Vorgang in einer SAP-Operator-Queue zur manuellen Prüfung — kein stiller Datenverlust.
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 <sink.endpoint_url>
Authorization: Bearer <sink-webhook-secret> # pro Senke in Sink Registry
X-Decision-Id: DEC-2026-0042
X-Payload-Hash: sha256:<final hash>
Idempotency-Key: <decision_id>
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:<url>:<externe-id-aus-response>"`.
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 (`<workflow_id>_<decision_id>.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 auch nachträglich zulassen. **Kein** rechtssicheres GoBD-Archiv.
**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 (`archived_at` + Cron-Job). Konfigurierbar pro Prozess-Typ.
**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**) |
| 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:** Der PII-Store (Belege, Namen, Kostenstellen) ist unabhängig vom Evidence Store löschbar. Löscht ein Benutzer per DSGVO-Antrag seine Daten, verschwinden die Belege; die Hashes und Signaturen in Evidence Store und Transparency Log bleiben erhalten, verifizieren aber dann nur noch „diese Kette existierte", nicht mehr „ihr Inhalt war X".
**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 periodisch signiertem Tree-Root (Signed Tree Head). Entscheidend sind:
- **Strikte Reihenfolge** aller Einträge (eine lineare Sequenznummer).
- **Starke Konsistenz** zwischen Logeintrag und Merkle-Root — der Root muss nach jedem Append reproduzierbar berechnet werden können.
- **Inclusion Proofs** auf Anfrage, idealerweise in ms.
Cassandra ist für diese Zugriffsmuster architektonisch ungeeignet: eventual consistency, ordering nur per Partition, keine serialisierbare globale Sequenz. Es wäre technisch möglich, aber mit erheblichem Over-Engineering (externer Sequencer, Lock-Dienst) — und würde sigstore's Entscheidung widersprechen.
**Empfehlung:** [Google Trillian](https://github.com/google/trillian) als Transparency-Log-Engine (ist die Grundlage von sigstore rekor), gestützt auf PostgreSQL — das ist unsere ohnehin vorhandene Infrastruktur. Für unser erwartetes Volumen (< 1 Mio. Einträge/Jahr, Single-Tenant) läuft das auf einer kleinen Instanz. Der Log-Root wird täglich signiert und ins Backup-System gespiegelt — damit ist eine nachträgliche Manipulation durch den DB-Admin erkennbar.
Falls Trillian als Dependency zu schwer wirkt, Alternative: eine eigene minimale Append-Only-Postgres-Tabelle mit stündlich berechnetem Merkle-Root und Export des Roots als signiertes JSON — deutlich weniger Funktionalität (keine Inclusion Proofs auf Anfrage), aber ausreichend für unseren Scope.
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
Namespaces und Dienste:
```
identity/
pocket-id (bestehend)
pocket-id
agent-trust/
trust-api (Approval + Attestation + Registry + Verification)
trust-api (Approval + Attestation + Agent Registry + Sink Registry + Verification)
signing-service (eigenes Deployment, enge Trust-Boundary)
policy-engine (OPA)
trust-postgres
trillian-log (Transparency Log)
trillian-log
transport/
nats (JetStream für Agent↔Agent)
@ -443,11 +514,19 @@ transport/
paperclip/
paperclip
agent-travel
agent-sap-mapping
agent-sap-posting
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 (Transit Engine für Signaturschlüssel)
openbao
matrix/ (optional, Phase 5)
synapse
@ -455,48 +534,53 @@ matrix/ (optional, Phase 5)
agent-matrix-gateway
```
**Signing Service**: eigenes Deployment, dediziertes Pocket-ID-Client-Secret, eigener ServiceAccount, NetworkPolicy erlaubt eingehend nur die Agent-Namespaces. Agenten rufen den Signing-Endpunkt auf; private Schlüssel verlassen OpenBao nie.
### 9.1 Workload-Identitäts-Prüfung (doppelt)
Der Signing Service verifiziert für jeden eingehenden Request **beide** Credentials:
Der Signing Service verifiziert für jeden Request **beide** Credentials:
1. **Pocket-ID-Access-Token** (Header `Authorization: Bearer <token>`) — gegen Pocket-ID-JWKS validiert; `sub` = `agent-<name>` muss zu einem registrierten Agent in der Agent Registry gehören.
2. **Projected ServiceAccount-Token** (Header `X-Workload-Token: <token>`, Audience `signing-service.agent-trust`) — gegen Kubernetes-TokenReview-API validiert; Namespace + ServiceAccount müssen zum Agent in der Agent Registry passen.
1. **Pocket-ID-Access-Token** (Header `Authorization: Bearer`) — gegen Pocket-ID-JWKS; `sub = agent-<name>` 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 Prüfungen zum selben `agent_id` auflösen, wird signiert. Damit ist weder ein geleaktes Pocket-ID-Secret allein noch ein kompromittierter Pod außerhalb des erwarteten Namespaces ausreichend.
Nur wenn beide auf denselben `agent_id` auflösen, wird signiert.
OpenBao's Transit Engine signiert mit Ed25519. **Caveat:** Transit kennt kein DSSE — der Signing Service berechnet die DSSE-Pre-Authentication-Encoding (PAE) selbst und übergibt nur den Hash an Transit. Backup via Transit-Export-Policy und Snapshot der OpenBao-Instanz.
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 bis 5 Wochen)**
Pocket ID als IdP (Mensch und Agent-Client), 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 die zweistufige Kette (Approval → Agent → Simulierte Senke). Deliverable: ein signierter Durchlauf vom Login bis zur simulierten SAP-Senke.
**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, Materialien-Hash-Kette, OPA-Policies in Rego, Policy-Versionierung.
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-Tabelle, Retention-Cron-Job, PII-Store-Trennung.
Trillian-Deployment, Decision-Nonce-Mechanik, Decision-Replay-Tabellen, Retention-Cron-Jobs, PII-Store-Trennung.
**Phase 4 — SAP-Integration**
ABAP-Endpunkt, serverseitige Mitarbeiterzuordnung, SAP-seitige Replay-Prüfung über Validierungs-Webservice, Operator-Queue.
**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 — Matrix für Mensch-Chat (optional)**
Nur Mensch↔Agent-Chat, E2EE. Agent↔Agent läuft weiterhin über NATS/HTTPS.
**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
- Matrix ist **nicht** Standard-Transport — nur optionale Mensch-Chat-Schicht in Phase 5. Intern NATS JetStream + HTTPS/mTLS.
- Transparency Log ist eine eigene Komponente, nicht nur „Postgres-Tabelle".
- 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, dann Löschung.
- Pocket ID ist alleiniger IdP — Keycloak entfällt.
- Keine Unveränderbarkeits-/GoBD-Garantien — Retention 1 Jahr.
- Pocket ID ist alleiniger IdP.
## 12. Empfohlener Kernstack (Zielbild)
| Identität | **Pocket ID** (Menschen + Agent-Clients) |
| Identität | Pocket ID (Menschen + Agent-Clients) |
| ------------- | ------------------------------------------------------------------- |
| Workload-ID | K8s projected ServiceAccount Token + TokenReview |
| Signaturen | Ed25519 / DSSE, OpenBao Transit |
@ -505,8 +589,8 @@ Nur Mensch↔Agent-Chat, E2EE. Agent↔Agent läuft weiterhin über NATS/HTTPS.
| Transparency | Trillian + PostgreSQL |
| Transport | HTTPS/mTLS + NATS JetStream (Agent↔Agent); Matrix optional (Mensch) |
| Agenten | Paperclip |
| ERP | SAP S/4HANA / ABAP REST + Validierungs-Webservice |
| **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 Testprozess von der Benutzerfreigabe bis zur simulierten SAP-Senke, mit genau einem Agenten. Matrix und ADRs für Schema/OPA-Deep-Dive folgen danach.
**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.