Skip to main content

Audit Gateway and Evidence Service: security model

This page lists the guarantees checked by the kit section 11 tests (services/control-plane/tests/test_evidence_gateway.py, services/control-plane/tests/test_evidence_config_redaction.py). Operations are in ../../operations/en/siem-audit.md.

Guarantees​

GuaranteeMechanismTest evidence
No event lostevent and eai.audit_outbox row written in the transaction of the change; rollback = neither change nor eventtest_rolled_back_change_leaves_no_event_and_committed_one_always_has_it
Delivery without sampling, recovery after an outageaudit_gateway job, exponential backoff, sequence order, idempotency key, receiver side deduptest_gateway_redelivers_after_target_outage_without_loss_or_duplicate, test_gateway_publishes_to_real_jetstream_with_dedup (real nats-server 2.15.2)
Sequence gaps detectedoutbox contiguity check, sequence_gap alerttest_gateway_detects_outbox_sequence_gap
Verifiable sealingRFC 8785 canonical JSON, sha256 Merkle root, previous seal hash, Ed25519 signature, key idtest_seal_signature_verifies_online_and_offline, test_forged_seal_signature_is_rejected
Tampering detectedaudit_integrity monitor over chain, seals and timestampstest_monitor_detects_sql_tampering_of_a_sealed_event
Distinct timestampsevent_time < ingested_at < sealed_at, bounded skew tolerancetest_event_time_ingested_at_sealed_at_are_distinct_and_ordered
Payload access separationTink envelope, key outside the database, decryption for auditor and security_officer only, refused to platform_admintest_payload_encrypted_and_only_auditor_decrypts_with_audited_reason
Audited accessevery read, search, verification, export writes its eventtest_reads_searches_and_exports_are_audited
Legal holdblocks purge and erasure, released by two distinct approvers, purge evidence without contentstest_legal_hold_blocks_purge_and_release_needs_two_distinct_approvers
No secret or personal data in logsmasking in eai.logs (message, fields, exceptions); credentials masked in audit metadatatest_secrets_and_pii_never_reach_logs, test_audit_metadata_has_no_credentials_and_pii_goes_to_the_encrypted_payload
Backup and restorechain, seals, legal hold and purge evidence verified after pg_backup.sh and pg_restore.shtest_restored_backup_keeps_verifiable_chain_seals_and_hold_state

Roles and access​

OperationRouteRoles
List seals, verify a seal or the whole chainGET /v1/evidence/seals, GET /v1/evidence/seals/{seal_id}/verify, GET /v1/evidence/verifyauditor, security_officer, tenant_admin
Seal nowPOST /v1/evidence/sealssecurity_officer, auditor
Export the offline verifiable bundleGET /v1/evidence/bundleauditor, security_officer
Decrypt the payload of an event, with a reasonPOST /v1/evidence/events/{event_id}/payloadauditor, security_officer only (explicit check, platform_admin refused)
Access logGET /v1/evidence/access-logauditor, security_officer
Integrity alerts, gateway statusGET /v1/evidence/alerts, GET /v1/evidence/gatewayauditor, security_officer, tenant_admin
Set, list, release a legal holdPOST /v1/evidence/holds, GET /v1/evidence/holds, POST /v1/evidence/holds/{hold_id}/releaseauditor, security_officer, tenant_admin
Run the payload purgePOST /v1/evidence/retention/runsecurity_officer, tenant_admin
Read purge evidenceGET /v1/evidence/retention/evidenceauditor, security_officer, tenant_admin

Releasing a legal hold takes two calls by two distinct approvers: the hold is released at the second approval; the same approver twice gets 409 audit_hold_same_approver.

Settings required in production​

The startup guard (eai.security.startup) refuses in production:

  • EAI_AUDIT_SEAL_SIGNING_KEY_REF missing (the Ed25519 seal key must come from OpenBao, EAI_AUDIT_SEAL_SIGNING_KEY as a PEM is for development and test only);
  • EAI_AUDIT_PAYLOAD_KEK other than openbao-transit;
  • EAI_AUDIT_SIGNING set to hmac, or EAI_OPENBAO_URL and EAI_OPENBAO_TOKEN missing (WORM export signature);
  • EAI_AUDIT_CLOCK_SKEW_SECONDS outside 0 to 3600.

The full list of Audit Gateway settings (intervals, batches, attempts, NATS subject, HTTP collector) is in ../../operations/en/siem-audit.md.

Verify evidence offline​

The bundle of GET /v1/evidence/bundle carries a manifest signed by the seal key. It is verified without access to the platform with the eai.domains.evidence.verify module:

cd services/control-plane
.venv/bin/python -m eai.domains.evidence.verify <bundle.json>

<bundle.json>: the file returned by GET /v1/evidence/bundle. Result: a JSON report (valid, chain, seals, clock), exit code 0 when the bundle is valid, 1 otherwise.

A wrong signature or an event modified after sealing is reported (test_seal_signature_verifies_online_and_offline, test_forged_seal_signature_is_rejected).

See also: risk-compliance.md (evidence and control catalogue), retention-privacy.md (legal holds and erasure).

Limits​

  • The database owner role can modify rows: tampering is detected (chain, signed seals), not prevented. Storage immutability belongs to the WORM export, qualified only with a storage profile whose object lock was verified.
  • The OPA bundle revision is recorded only when the decision reports it.