- Add Implementation Status section to A2H2A spec - Clarify Google Chat is notification-only - Add target approval architecture requirements - Add critical A2H2A safety principle to RUNBOOK.md - Remove unsafe approval/rejection endpoints from server.py - Enforce server-side parameter_hash calculation - Disable execution for all tools in A2H2A_TOOL_ALLOW_LIST
213 lines
7.8 KiB
Markdown
213 lines
7.8 KiB
Markdown
# OSVxCC A2H2A Ticketing System Specification
|
|
|
|
## 1. Introduksjon
|
|
|
|
A2H2A (Agent-to-Human-to-Agent) er en uomgåelig Approval Gate mellom autonome observatører/analytikere og operative eksekveringsagenter. Ingen destruktive eller privilegerte handlinger skal utføres i GCP-infrastrukturen uten at autorisert operatør eksplisitt har validert og godkjent handlingen via et kryptografisk signert grensesnitt.
|
|
|
|
## Implementation Status
|
|
|
|
**Current prototype — proposal recording only; approval and execution disabled.**
|
|
|
|
- The prototype may accept an allow-listed ticket proposal and store it as `PENDING`.
|
|
- Google Chat is notification-only. It does not verify or prove the identity of an approver.
|
|
- The current `/a2h2a/review/{ticket_id}` link is conceptual only.
|
|
- No working approval or rejection endpoint currently exists.
|
|
- No one-time action token currently exists.
|
|
- No execution worker currently exists.
|
|
- No proposed tool is executable through A2H2A at this stage.
|
|
|
|
## 2. JSON Datamodell (a2h2a-ticket-v1.json)
|
|
|
|
```json
|
|
{
|
|
"ticket_id": "A2H2A-20260904-8B3D",
|
|
"timestamp": "2026-09-04T14:20:05Z",
|
|
"severity": "CRITICAL",
|
|
"category": "SECURITY",
|
|
"source": {
|
|
"reporter": "tyr-compliance-agent",
|
|
"trigger": "Secret scanned in public repository",
|
|
"affected_service": "mcp-server-key",
|
|
"project_id": "propane-will-491900-m5",
|
|
"region": "global"
|
|
},
|
|
"context": {
|
|
"summary": "En aktiv Secret Manager-nøkkel ble funnet i en offentlig Gitea-commit.",
|
|
"evidence_logs": [
|
|
"gitea.commit.url: https://git.vauco.no/chris/OSVauco/commit/a1b2c3d4...",
|
|
"secret.name: projects/357036551735/secrets/mcp-server-key/versions/2"
|
|
]
|
|
},
|
|
"proposed_action": {
|
|
"action_type": "AUTOMATED_REMEDIATION",
|
|
"runbook_reference": "docs/RUNBOOK.md#hendelse-eksponert-hemmelighet",
|
|
"execution_tool": "opax.secrets.rotate",
|
|
"parameters": {
|
|
"secret_name": "mcp-server-key",
|
|
"disable_old_versions": true,
|
|
"notify_channel": "#security-alerts"
|
|
},
|
|
"parameter_hash": "sha256:f4a2...d8e0",
|
|
"rollback_plan": "Manuell re-aktivering av forrige hemmelighetsversjon via `gcloud secrets versions enable` etter verifisering."
|
|
},
|
|
"governance": {
|
|
"approval_status": "PENDING",
|
|
"authorized_approver": "chris.christiansen@vauco.no",
|
|
"requires_mfa": true,
|
|
"timeout_minutes": 15
|
|
}
|
|
}
|
|
```
|
|
|
|
`The ticket model is a proposal model. Fields required for secure human approval—such as approval_token_hash, verified_approver_identity, approval timestamp, token_used_at, and immutable audit-event references—are target-design fields and are not implemented in the current prototype.`
|
|
|
|
## 3. Sikkerhetsgarantier
|
|
|
|
### 3.1 Constant-Time Authentication
|
|
- Sammenligning av alle signaturer og tokens **skal** utføres med `secrets.compare_digest` eller tilsvarende for å forhindre timing-angrep.
|
|
|
|
### 3.2 Anti-Tampering
|
|
- En SHA-256 hash av `proposed_action.parameters` **skal** beregnes før ticketen sendes til operatør.
|
|
- Før eksekvering **skal** OPAX verifisere at hashen av parameterne den mottok for eksekvering stemmer overens med `parameter_hash` i den godkjente ticketen.
|
|
|
|
### 3.3 Replay-Beskyttelse
|
|
- Hver callback fra Slack/Discord **skal** inneholde et timestamp.
|
|
- Serveren **skal** avvise callbacks hvor `current_time - callback_timestamp > 300` sekunder for å forhindre gjenbruk av gamle godkjenninger.
|
|
|
|
### 3.4 Time-To-Live (TTL)
|
|
- Ubehandlede tickets utløper automatisk basert på alvorlighetsgrad:
|
|
- **CRITICAL:** 15 minutter
|
|
- **HIGH:** 60 minutter
|
|
- **MEDIUM/LOW:** 24 timer
|
|
|
|
## 4. API-Endepunkter (Prototype)
|
|
|
|
### 4.1 POST /api/v1/a2h2a/tickets
|
|
1. Motta ticket-payload fra en autorisert intern agent (f.eks. TYR).
|
|
2. Valider payloaden mot en Pydantic-modell basert på schemaet over.
|
|
3. Beregn `parameter_hash` server-side.
|
|
4. Lagre ticketen i en Firestore-collection (`a2h2a_tickets`) med status `PENDING`.
|
|
5. Formater og send en Google Chat-melding med et konseptuelt link til en fremtidig godkjennings-UI.
|
|
|
|
`Google Chat delivers a notification and review link only; it must never be used as evidence of the approver's identity or as the authority to execute a tool.`
|
|
|
|
## Target Approval Architecture — Required Before Production
|
|
|
|
The eventual review URL may use:
|
|
`/a2h2a/review/{ticket_id}?token=<opaque-random-token>`
|
|
|
|
- The token is generated with a cryptographically secure random generator.
|
|
- The raw token is returned once in the notification link and is never persisted.
|
|
- Only the SHA-256 token hash is stored server-side.
|
|
- Approval/rejection backend verifies IAP-verified identity, PENDING state, TTL, unused matching token hash, authorized approver, server-side canonical parameter hash, and tool allow-list.
|
|
- Approval only updates the ticket state.
|
|
- A separate worker later executes only server-stored, immutable, approved actions.
|
|
- Every audit event is a target requirement; do not claim it is already implemented.
|
|
|
|
## Target audit requirements
|
|
`Immutable audit events for proposal, approval, rejection, expiry, execution start, execution success, execution failure, and rollback are required before production activation; they are not implemented in the current prototype.`
|
|
|
|
## 5. Google Chat / Slack Block Kit Payload (Konseptuelt Eksempel)
|
|
|
|
```json
|
|
{
|
|
"blocks": [
|
|
{
|
|
"type": "header",
|
|
"text": {
|
|
"type": "plain_text",
|
|
"text": "🚨 A2H2A Godkjenning Kreves: CRITICAL"
|
|
}
|
|
},
|
|
{
|
|
"type": "section",
|
|
"fields": [
|
|
{"type": "mrkdwn", "text": "*Kategori:*
|
|
SECURITY"},
|
|
{"type": "mrkdwn", "text": "*Tjeneste:*
|
|
mcp-server-key"},
|
|
{"type": "mrkdwn", "text": "*Handling:*
|
|
`opax.secrets.rotate`"},
|
|
{"type": "mrkdwn", "text": "*Tidsfrist:*
|
|
15 minutter"}
|
|
]
|
|
},
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*Sammendrag:*
|
|
En aktiv Secret Manager-nøkkel ble funnet i en offentlig Gitea-commit."
|
|
}
|
|
},
|
|
{
|
|
"type": "actions",
|
|
"elements": [
|
|
{
|
|
"type": "button",
|
|
"text": {
|
|
"type": "plain_text",
|
|
"text": "✅ Godkjenn",
|
|
"emoji": true
|
|
},
|
|
"style": "primary",
|
|
"value": "approve_A2H2A-20260904-8B3D"
|
|
},
|
|
{
|
|
"type": "button",
|
|
"text": {
|
|
"type": "plain_text",
|
|
"text": "❌ Avvis",
|
|
"emoji": true
|
|
},
|
|
"style": "danger",
|
|
"value": "reject_A2H2A-20260904-8B3D"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## 6. Eksempel-Ticket (SECRET_EXPOSURE)
|
|
|
|
```json
|
|
{
|
|
"ticket_id": "A2H2A-20260904-1C4F",
|
|
"timestamp": "2026-09-04T18:05:10Z",
|
|
"severity": "CRITICAL",
|
|
"category": "SECURITY",
|
|
"source": {
|
|
"reporter": "tyr-scanner-agent",
|
|
"trigger": "Audit log anomaly: Unexpected access to mcp-server-key v2",
|
|
"affected_service": "mcp-server-key",
|
|
"project_id": "propane-will-491900-m5",
|
|
"region": "global"
|
|
},
|
|
"context": {
|
|
"summary": "Mistenkelig tilgang til mcp-server-key v2 fra en ukjent IP-adresse (35.22.88.101) utenfor GCP-nettverket.",
|
|
"evidence_logs": [
|
|
"log_explorer_link: https://console.cloud.google.com/logs/query;query=..."
|
|
]
|
|
},
|
|
"proposed_action": {
|
|
"action_type": "AUTOMATED_REMEDIATION",
|
|
"runbook_reference": "docs/RUNBOOK.md#hendelse-eksponert-hemmelighet",
|
|
"execution_tool": "opax.secrets.rotate",
|
|
"parameters": {
|
|
"secret_name": "mcp-server-key",
|
|
"disable_old_versions": true,
|
|
"notify_channel": "#security-alerts"
|
|
},
|
|
"parameter_hash": "sha256:f4a26901a511e6cb716b5a86552631521a0e71383921034293739886313ad8e0",
|
|
"rollback_plan": "Manuell re-aktivering av forrige hemmelighetsversjon (v3) via `gcloud secrets versions enable` etter verifisering."
|
|
},
|
|
"governance": {
|
|
"approval_status": "PENDING",
|
|
"authorized_approver": "chris.christiansen@vauco.no",
|
|
"requires_mfa": true,
|
|
"timeout_minutes": 15
|
|
}
|
|
}
|
|
```
|