Security Control Verification Matrix¶
| Control Area | Control | Owner | Verification Method | Frequency |
|---|---|---|---|---|
| Auth | OIDC + short-lived access tokens | Security | integration tests + pen-test | each release |
| AuthZ | Role/tenant policy enforcement | Backend | authz test suite + code review gates | each PR |
| Secrets | secret manager only, no hardcoded secrets | Security/Platform | secret scan + config review | each PR |
| Transport | TLS at edge, secure internal transport | Platform | config validation + periodic scan | monthly |
| Session security | admin token emergency deny-list | Security/Backend | revocation drill + auth middleware test | each release |
| Realtime channel isolation | Redis ACL for notification publish/subscribe | Security/Platform | ACL config review + negative subscribe test | each release |
| Runtime key handling | No persistent user private-key storage for allocation access | Security/Platform | API contract review + storage/log scan + negative endpoint test | each release |
| Runtime key handling | User-managed SSH public key path only for runtime access | Security/Backend | request/response contract checks + integration tests | each release |
| Terminal session auth | Single-use terminal token atomic consume (Redis GETDEL) — no replay | Backend/Security | replay attack test (reuse consumed token → 401) | each release |
| Terminal session binding | Session bound to {session_id, user_id, allocation_id, node_id, expires_at} — gateway enforces at open | Backend | binding invariant test + mismatch rejection test | each release |
| Terminal session concurrency | Single active terminal session per allocation enforced at open | Backend | concurrent open attempt test → second open rejected | each release |
| Terminal session TTL | Active session closed at terminal.session_max_ttl_seconds (policy key, default 4h) — not inherited from OIDC token TTL |
Backend | TTL expiry test with short policy override | each release |
| Terminal task signing | terminal.open task signed with Ed25519 — node rejects unsigned or replayed task |
Security/Node | signature bypass test + replay test → node rejected | each release |
| Terminal least-privilege boundary | Terminal path allows only user impersonation bootstrap; interactive shell runs as allocation user with no privileged lifecycle operations | Security/Backend | integration test verifies effective uid/gid; negative test forbids privileged terminal operations; sudoers policy review | each release |
| SKU lifecycle governance | SKU lifecycle changes (create/update/activate/deactivate) require approval policy and node-registration references only active catalog SKUs | Platform/Inventory | change-review evidence + negative registration test for invalid/inactive SKU reference + runbook mapping check | each release |
| Terminal release sequencing | Allocation release closes terminal first (allocation_released frame + ack/timeout) before allocation.revoke_user |
Backend | release-during-active-terminal integration test | each release |
| Terminal session audit | Every terminal open/close recorded in audit_logs with session_id, user_id, allocation_id, reason |
Backend | audit log presence check in integration tests | each release |
| Payments | webhook raw-body signature verification before JSON parse + event-id idempotency | Payments | integration replay tests + signature bypass tests | each release |
| Billing | immutable ledger writes | Billing | ledger invariant tests | each release |
| Audit | privileged action logging | Platform | log schema checks + spot audit | weekly |
| Abuse | WAF/rate limits/bot controls | Platform | load+abuse tests | monthly |
Release Blocking Controls¶
- Auth/AuthZ verification pass
- Admin token revocation drill pass
- Redis notification ACL isolation test pass
- Runtime key handling checks pass (no persistent private-key endpoint/data path)
- Secrets scan pass
- Webhook replay/idempotency tests pass
- Webhook signature bypass test (
AT-053) pass - Ledger integrity tests pass
- Terminal token replay rejection test pass
- Terminal session binding invariant test pass
- Terminal least-privilege boundary checks pass
- SKU lifecycle governance checks pass
- Terminal release sequencing test pass (terminal closed before revoke_user)
Implementation Requirements¶
Stripe Webhook Signature Verification¶
The Payments service MUST verify the Stripe webhook signature against the raw request body bytes before any JSON parsing or deserialization occurs.
- Read the raw body stream once and buffer it.
- Verify the Stripe-Signature header against the buffered bytes using the signing secret.
- Only proceed to JSON parse if verification passes.
- Reject any request that pre-parses JSON before signature check — this is a known class of signature bypass attack.
- Required test case: AT-053 — reuse a previously valid Stripe-Signature header with a modified request body and confirm 400 rejection.
Runtime Access Key Handling (Post-Cutover)¶
Runtime access MUST avoid persistent user private-key storage and re-download paths.
- Allowed model: user-managed public key registration and runtime access via terminal/SSH proxy controls.
- Disallowed model: API or database persistence of user private key material for later retrieval.
- Verification evidence for this control family:
- threat baseline linkage: doc/architecture/Threat_Model.md
- ops tracking: doc/governance/Agent_Work_Queue.yaml task C-OPS-003