ckms audit
Inspect and verify the KMS audit trail, reading directly from its storage backend: the
JSONL file or a PostgreSQL database. No running KMS server is required.
Choosing the audit source
export and verify read from exactly one source: a JSONL file (--path) or a PostgreSQL
database (--audit-postgres-url). The two are mutually exclusive.
With none of --path, --audit-postgres-url or --audit-instance-id, the source comes from
KMS_AUDIT_POSTGRES_URL or KMS_AUDIT_FILE_PATH; PostgreSQL wins if both are set. Any of the three
options turns this fallback off, so --audit-instance-id always needs the URL on the command line.
On a KMS host, KMS_AUDIT_POSTGRES_URL holds the writer's credentials. Pass a
read-only role with --audit-postgres-url instead.
# Verify every instance in the database
ckms audit verify --audit-postgres-url "${AUDIT_READ_URL}"
# Verify a single instance
ckms audit verify --audit-postgres-url "${AUDIT_READ_URL}" --audit-instance-id kms-eu-west-1a
# Verify an exported file
ckms audit verify --path /backup/audit.jsonl
Usage
ckms audit <subcommand>
Subcommands
export Export events from the audit log in JSON or CEF format.
verify Verify the SHA-256 hash chain of the audit log.
ckms audit export
Export events from the audit log to stdout. Supports JSON (default) and CEF output.
Usage
ckms audit export --path <FILE> [options]
Arguments
--path [-p] <FILE> Path to the JSONL audit log file. Alternative to --audit-postgres-url —
exactly one is required.
--audit-postgres-url <URL> PostgreSQL connection URL for the audit database, as an
alternative to --path.
--audit-instance-id <ID> With --audit-postgres-url, restricts the export to a single KMS
instance's chain. Omit to export every instance present in the database. An ID with no events
in the database is an error, not an empty export.
--since <RFC3339> Export only events whose timestamp is greater than or equal to this value.
The value must be an RFC 3339 timestamp, e.g. 2026-05-01T00:00:00Z.
--format <FORMAT> Output format. One of json (default) or cef.
--kms-version <STRING> KMS version string to embed in the CEF device version header.
Defaults to the ckms binary's own version. Useful when merging exports from multiple nodes.
Output formats
json — Emits one JSON object per line on stdout (JSONL).
File exports retain the stored JSONL schema.
PostgreSQL exports add instance_id and chain_generation alongside the unchanged audit event fields.
cef — Emits one CEF line per event on stdout, per the ArcSight CEF Implementation
Standard v27:
CEF:0|Cosmian|KMS|<version>|<operation>|<operation>|<severity>|rt=<epoch_ms> suser=<user> ...
PostgreSQL CEF exports include deviceExternalId (instance ID) and cn2 (chain generation),
with cn2Label=chainGeneration.
Their externalId is <generation>:<id>; identify an event by the pair deviceExternalId and externalId.
File CEF exports retain the numeric event ID in externalId and have no instance metadata.
See CEF export for the full field mapping and severity rules.
Examples
Export all events as JSONL:
ckms audit export --path /var/log/cosmian-kms/audit.jsonl > events.jsonl
Export events since a given date as CEF, piped to a SIEM:
ckms audit export \
--path /var/log/cosmian-kms/audit.jsonl \
--format cef \
--since "2026-05-01T00:00:00Z" \
| nc splunk-host 5514
Export a single instance's events from a PostgreSQL audit database:
ckms audit export \
--audit-postgres-url postgresql://kms_audit:password@db-host:5432/kms_audit \
--audit-instance-id kms-eu-west-1a
ckms audit verify
Verify the SHA-256 hash chain of the audit trail — a JSONL file (or directory of files), or
every instance's chain in a PostgreSQL audit database.
Checks that:
- Each event's
row_hashmatches a freshly computed hash of its fields. - Each event's
prev_hashmatches therow_hashof the previous event (or is all-zeros for the first event). - (File source only) every
audit:reanchorevent's sealed evidence file still exists next to the log and its SHA-256 still matches the digest recorded in the event. This is what makes deleting or altering sealed evidence after the fact detectable. ThePostgreSQLbackend also seals a corrupted chain and starts a fresh one with its ownaudit:reanchorevent, but this command does not yet check its recorded evidence digest against the sealed generation; see PostgreSQL backend for the manual check.
Exits with code 0 when every chain is intact, or 1 when a broken link, tampered event,
altered/missing sealed-evidence file, or an unknown --audit-instance-id (no events found) is
detected.
With --audit-postgres-url, broken chains and row-decoding errors do not stop later generations or instances.
The final error lists each failing generation and names the generations that verified clean.
Connection or query failures still abort the run.
Usage
ckms audit verify --path <FILE|DIRECTORY> [options]
ckms audit verify --audit-postgres-url <URL> [--audit-instance-id <ID>] [options]
Arguments
--path [-p] <FILE|DIRECTORY> Path to a JSONL audit log file, or a directory containing one or
more. A directory is scanned for every non-sealed *.jsonl file, each verified as its own
independent chain. Sealed *.corrupt.jsonl evidence files are intentionally not verified
as chains — their corruption is why they were sealed — but are SHA-256 checked through the live
log's audit:reanchor record. Alternative to --audit-postgres-url — exactly one is required.
--audit-postgres-url <URL> PostgreSQL connection URL for the audit database, as an
alternative to --path. Verifies every instance's chain in the database, each as its own
independent chain, unless --audit-instance-id restricts it to one. See
Choosing the audit source.
--audit-instance-id <ID> With --audit-postgres-url, restricts verification to a single KMS
instance's chain.
--verbose Print a summary line for every event even when the chain is valid.
Default: false.
Exit codes
| Code | Meaning |
|---|---|
0 | All events (and, for reanchor events, all sealed evidence) verified — intact. |
1 | A tampered/broken link, or missing/altered sealed evidence, was detected. |
Output examples
Chain intact:
/var/log/cosmian-kms/audit.jsonl: chain OK: 42 events verified
Tampered file:
TAMPERED: /var/log/cosmian-kms/audit.jsonl event id=17 (line 18) has an invalid row_hash
Missing sealed evidence (a seal-and-roll recovery's corrupted file was deleted or moved):
MISSING EVIDENCE: /var/log/cosmian-kms/audit.jsonl: reanchor event id=0 references sealed file
audit.20260814T140233Z.9f3ac1b2.corrupt.jsonl which no longer exists
PostgreSQL source (one section per instance in the database):
ckms audit verify --audit-postgres-url postgresql://kms_audit:password@db-host:5432/kms_audit
== instance_id: kms-eu-west-1a ==
instance_id=kms-eu-west-1a: chain OK: 128 events verified
== instance_id: kms-eu-west-1b ==
instance_id=kms-eu-west-1b: chain OK: 96 events verified
Verbose mode:
id=0 2026-05-06T20:31:15Z Create chain=ok
id=1 2026-05-06T20:31:15Z Encrypt chain=ok
...
Examples
Verify a log file and fail CI if the chain is broken:
ckms audit verify --path /var/log/cosmian-kms/audit.jsonl
Verify every live JSONL chain in a directory; sealed evidence is checked through its reanchor:
ckms audit verify --path /var/log/cosmian-kms/
Verbose verification for debugging:
ckms audit verify --path audit.jsonl --verbose