Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Sovereign, high-performance data protection

Audit events

Every audit event has the same fields, whether it is an ordinary KMIP operation or one of the system events described below. ckms audit export and ckms audit verify both read this shape.

Fields

FieldTypeNullableDescription
idintegerNoMonotonically increasing row counter, starting at 0 for each chain (for each chain generation with the PostgreSQL backend).
timestampstring (RFC 3339 / UTC)NoWall-clock time of the KMIP operation.
operationstringNoKMIP operation name, e.g. "Create", "Encrypt", "Destroy". Batch requests produce a +-joined name such as "Create+Encrypt".
userstringNoAuthenticated username. "unauthenticated" when no identity was presented (e.g. 401 paths). "server" for a system event.
object_uidstring or nullYesKMIP UniqueIdentifier of the object involved. null when unavailable (e.g. failed auth, batch, system event).
algorithmstring or nullYesCryptographic algorithm, e.g. "AES", "RSA". null when the operation carries no algorithm.
client_ipstring or nullYesThe direct TCP peer address, or the rightmost X-Forwarded-For entry that is not a trusted proxy when the request comes from a trusted proxy (the peer address when that entry is not a valid IP). See Client IP and reverse proxies.
result"Success" or {"Failure": "<reason>"}NoOutcome of the operation.
duration_msintegerNoWall-clock duration of the operation in milliseconds.
request_idstring (UUID) or nullYesCorrelation ID across operations from the same request. null for system events.
detailsstring or nullYesStructured JSON payload attached to a system event. null for ordinary KMIP events. See System events.
prev_hashstring (64 hex chars)NoSHA-256 of the previous row's canonical bytes. All-zeros for the first row (id = 0).
row_hashstring (64 hex chars)NoSHA-256 of this row's canonical bytes (including prev_hash).

PostgreSQL backend

The PostgreSQL backend stores the user field in a username column. ckms audit export from a PostgreSQL source adds two fields, instance_id and chain_generation, to every JSON event; the stored event and its hashes are unchanged. Because id restarts in each generation and instance, identify an event by (instance_id, chain_generation, id). See SIEM integration.

Example event (file backend):

{
  "id": 4,
  "timestamp": "2026-05-06T20:31:42.321328507Z",
  "operation": "Encrypt",
  "user": "admin",
  "object_uid": "417fe2de-827d-48d0-8d51-851bec315b76",
  "algorithm": "AES",
  "client_ip": "127.0.0.1",
  "result": "Success",
  "duration_ms": 1,
  "request_id": "c1f728c0-85f2-498c-8f47-9759d57a2745",
  "prev_hash": "e492c0f02860bc6c428259d44414651eda3aaaee2f48eb857144c940ac0fe909",
  "row_hash": "699a2837830af4a26fe79aeb48509fc707507e514da5850d953366a14e730c38"
}

System events

The KMS appends these events for its own recovery and operational actions. They join the same hash chain as ordinary KMIP events, with user set to "server".

EventWritten whenresultdetails
audit:evictionOne or more events were dropped because the writer's queue was full.Failure, with the count of dropped events.null
audit:size-cap-reachedThe file backend's --audit-file-max-size-bytes cap was reached.Failurenull
audit:torn-write-recoveredFile backend only: an incomplete trailing row was found and discarded after an ungraceful restart.Successbytes_discarded and offset of the discarded fragment.
audit:reanchorThe KMS started a fresh chain after finding the previous one corrupted (seal-and-roll).Successreason (see Reanchor reasons) plus backend-specific evidence fields, described in File backend and PostgreSQL backend.

Reanchor reasons

Both backends classify the corruption that triggered a seal-and-roll with one of these values in the reason field of the audit:reanchor event's details:

ReasonMeaning
hash_mismatchA complete row whose own hash doesn't match its stored bytes.
broken_linkA row that verifies on its own but doesn't chain to its predecessor.
unparsableA row or column doesn't decode as an audit event at all.
id_overflowA valid tail row at the maximum event ID: continuing in place would overflow.

Hash chain

Every event includes a SHA-256 hash chain that makes tampering detectable offline.

The hash is computed over a canonical byte sequence of the event's fields, in this order: prev_hash || id || timestamp || operation || user || object_uid || algorithm || client_ip || result || duration_ms || request_id || details

request_id and details are each included only when present, so events written before a field was added still hash to the same bytes.

prev_hash of the first event (id = 0) is the 32-byte all-zeros sentinel.

Any modification to a field in any row, including reordering rows, deleting rows, or appending forged rows, breaks at least one prev_hash → row_hash link and is detected by ckms audit verify.