512 lines
29 KiB
Markdown
512 lines
29 KiB
Markdown
# Technische Zielarchitektur: Vertrauenswürdige Kommunikation zwischen Menschen, KI-Agenten und SAP
|
|
|
|
**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"
|
|
|
|
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.**
|
|
|
|
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:
|
|
|
|
- **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>`.
|
|
|
|
## 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.
|
|
|
|
## 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.
|
|
5. **Transportneutralität** — Nachweise funktionieren über HTTP, NATS, Queue oder Matrix, ohne dass die kryptografische Vertrauenskette verloren geht.
|
|
|
|
## 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) |
|
|
| SAP Connector | ABAP REST API / OData | Validierte Buchungsaufträge |
|
|
| 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.
|
|
|
|
### 3a. Identity Provider: warum Pocket ID reicht
|
|
|
|
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:
|
|
|
|
- **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.
|
|
|
|
## 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.
|
|
|
|
### Vertrauens- und Verarbeitungskette
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
Damit scheitert ein kompromittierter Browser, der dem Benutzer eine andere Zahl zeigt, am visuellen Prüfziffer-Vergleich *oder* am WebAuthn-Signaturinhalt.
|
|
|
|
### 4.1 Benutzerfreigabe (DSSE-Statement)
|
|
|
|
```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:<webauthn assertion hash>",
|
|
"verification_code": "F3K-9MQ"
|
|
},
|
|
"action": "expense.submit",
|
|
"audience": "sap-expense-workflow",
|
|
"allowed_transformations": ["expense.normalize", "expense.map_to_sap"],
|
|
"nonce": "<base64 nonce for replay protection>",
|
|
"issued_at": "2026-10-25T10:30:00Z",
|
|
"expires_at": "2026-11-01T00:00:00Z"
|
|
}
|
|
}
|
|
```
|
|
|
|
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.
|
|
|
|
### 4.2 Signatur mit DSSE
|
|
|
|
```json
|
|
{
|
|
"payloadType": "application/vnd.in-toto+json",
|
|
"payload": "<base64-encoded statement>",
|
|
"signatures": [
|
|
{ "keyid": "approval-service-key-2026-q4", "sig": "<base64-encoded signature>" }
|
|
]
|
|
}
|
|
```
|
|
|
|
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.
|
|
|
|
### 4.3 Transformations-Attestierung (Beispiel Agent B)
|
|
|
|
```json
|
|
{
|
|
"_type": "https://in-toto.io/Statement/v1",
|
|
"subject": [
|
|
{
|
|
"name": "expense/EXP-2026-0042/sap-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",
|
|
"materials": [
|
|
{ "name": "expense/EXP-2026-0042/normalized", "sha256": "<input hash>" }
|
|
],
|
|
"parent_attestation": "sha256:<previous proof hash>",
|
|
"approval_ref": "APR-0042",
|
|
"schema": {
|
|
"input": { "name": "expense.canonical", "version": "1.0.0" },
|
|
"output": { "name": "sap.expense.payload", "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.
|
|
|
|
### 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):
|
|
|
|
```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, -- z.B. "agent-travel-2026-q4"
|
|
agent_id TEXT NOT NULL REFERENCES agents(agent_id),
|
|
public_key_pem TEXT NOT NULL, -- Ed25519
|
|
valid_from TIMESTAMPTZ NOT NULL,
|
|
valid_to TIMESTAMPTZ NOT NULL,
|
|
revoked_at TIMESTAMPTZ,
|
|
revocation_reason TEXT,
|
|
archived_at TIMESTAMPTZ -- gesetzt wenn außerhalb Retention
|
|
);
|
|
|
|
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 zum `issued_at` der Attestierung galt (`valid_from ≤ issued_at < valid_to`, nicht `revoked_at` vor `issued_at`). Das ist das 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.
|
|
|
|
## 5. Verifikation beim empfangenden Agenten
|
|
|
|
Der SAP-Agent darf sich nicht auf die mitgesendeten IDs verlassen. Er muss die gesamte Nachweiskette prüfen.
|
|
|
|
```
|
|
POST /api/v1/attestations/verify
|
|
Authorization: Bearer <service-token>
|
|
Content-Type: application/json
|
|
```
|
|
|
|
```json
|
|
{
|
|
"workflow_id": "WF-0042",
|
|
"artifact_digest": "sha256:<final hash>",
|
|
"requested_action": "expense.post_to_sap",
|
|
"target": "sap-s4hana-prod"
|
|
}
|
|
```
|
|
|
|
| Prüfung | Fehlerfall |
|
|
| -------------------------------------------------------------------- | --------------------- |
|
|
| Signatur der Benutzerfreigabe gültig (Schlüssel zum `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 |
|
|
| 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 |
|
|
|
|
Erfolgsantwort:
|
|
|
|
```json
|
|
{
|
|
"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",
|
|
"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",
|
|
"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 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.
|
|
|
|
## 6. Berechtigungssteuerung mit Open Policy Agent
|
|
|
|
Beispiel-Regeln:
|
|
|
|
- Agent A darf Belege extrahieren und Reisekosten strukturieren.
|
|
- Agent B darf Kontierungsinformationen ergänzen und SAP-Felder 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.
|
|
|
|
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**:
|
|
|
|
```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:
|
|
|
|
- Schemas werden als JSON Schema in `schemas/` im Repo versioniert.
|
|
- Jede Approval-Attestierung signiert `schema.name` und `schema.version` mit.
|
|
- Jede Transform-Attestierung signiert Input- *und* Output-Schema.
|
|
- 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
|
|
|
|
Für die S/4HANA-2023-Umgebung ist eine ABAP-Integrationsschicht vorgesehen, statt Agent C direkten Zugriff auf Buchungsfunktionen zu geben.
|
|
|
|
Fluss: `Agent C` → `ABAP REST Endpoint` (Authentifizierung · Freigabenachweis · Idempotenz) → `SAP-Anwendungslogik` (Mitarbeiterzuordnung · fachliche Prüfungen · Buchung).
|
|
|
|
```
|
|
POST /sap/bc/zexpense/v1/submit
|
|
Authorization: Bearer <sap-agent-token>
|
|
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:<final hash>"
|
|
}
|
|
```
|
|
|
|
Zusätzlich stellt ProofedMesh einen **Validierungs-Webservice** bereit, den das ABAP vor der Buchung aufruft:
|
|
|
|
```
|
|
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.
|
|
|
|
**Zwei unabhängige Prüfungen** in SAP:
|
|
|
|
- **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-agent-token** wird manuell im SAP-System hinterlegt. Rotationsprozess:
|
|
|
|
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.
|
|
|
|
**Welche SAP-Buchungsschnittstelle** verwendet wird (SAP Travel Management, Concur, kundeneigener FI-Prozess), bleibt in einem späteren ADR offen — architektonisch ist das austauschbar.
|
|
|
|
### SAP-Auditdaten
|
|
|
|
Zusätzlich zum ERP-Beleg: Tabelle `ZAGENT_AUDIT`.
|
|
|
|
| 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 (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.
|
|
|
|
## 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.
|
|
|
|
**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.
|
|
|
|
### 8.2 Datenklassen
|
|
|
|
| Daten | Speicherung |
|
|
| --------------------------------------- | ---------------------------------------- |
|
|
| Prozessstatus, Identitäten, Referenzen | 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 |
|
|
|
|
**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".
|
|
|
|
### 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.
|
|
|
|
## 9. Deployment in Kubernetes
|
|
|
|
Namespaces und Dienste:
|
|
|
|
```
|
|
identity/
|
|
pocket-id (bestehend)
|
|
|
|
agent-trust/
|
|
trust-api (Approval + Attestation + Registry + Verification)
|
|
signing-service (eigenes Deployment, enge Trust-Boundary)
|
|
policy-engine (OPA)
|
|
trust-postgres
|
|
trillian-log (Transparency Log)
|
|
|
|
transport/
|
|
nats (JetStream für Agent↔Agent)
|
|
|
|
paperclip/
|
|
paperclip
|
|
agent-travel
|
|
agent-sap-mapping
|
|
agent-sap-posting
|
|
|
|
openbao/
|
|
openbao (Transit Engine für Signaturschlüssel)
|
|
|
|
matrix/ (optional, Phase 5)
|
|
synapse
|
|
element-web
|
|
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:
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
## 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 2 — Agent Attestations in Breite**
|
|
Weitere Agenten, Schlüsselrotation, in-toto-Transformationsnachweise, Materialien-Hash-Kette, OPA-Policies in Rego, Policy-Versionierung.
|
|
|
|
**Phase 3 — Replay-Schutz, Transparency Log, Retention**
|
|
Trillian-Deployment, Decision-Nonce-Mechanik, Decision-Replay-Tabelle, Retention-Cron-Job, PII-Store-Trennung.
|
|
|
|
**Phase 4 — SAP-Integration**
|
|
ABAP-Endpunkt, serverseitige Mitarbeiterzuordnung, SAP-seitige Replay-Prüfung über Validierungs-Webservice, Operator-Queue.
|
|
|
|
**Phase 5 — Matrix für Mensch-Chat (optional)**
|
|
Nur Mensch↔Agent-Chat, E2EE. Agent↔Agent läuft weiterhin ü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".
|
|
- 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.
|
|
|
|
## 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 |
|
|
| ERP | SAP S/4HANA / ABAP REST + Validierungs-Webservice |
|
|
| 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.
|