Skip to content

Configuration: the jobs

The notary and the four scheduled commands of audit, each reading one --config file. Shared blocks are in configuration.

Scheduled jobs

Each job runs audit <command> --config <file> to completion. The notary is its own binary: audit-notary --config <file>. A job records what it did through the writer's sink, so it needs sink and, where the writer verifies callers, a tokenFile. Each job has its own identity.

audit-notary

Seals the archive (0061). Hourly in the chart.

Behaviour Detail
Seal One signed seal per profile, tenant and ended, settled hour, chained to the previous one
Path seals/<profile>/<tenant>/<yyyy>/<mm>/<dd>/<hh>.jws (bucket contract)
Signer A managed key the writer's identity cannot use (key custody); the chart enforces a separate identity
Rerun Writes nothing new
Mismatch An hour whose objects do not match their metadata is not sealed, nor is any later hour
First seal The hour of the tenant's first object; empty hours are sealed from then on
key type default meaning
archive archive, required the archive to read and to put seals in (bucket, prefix, lockMode, kmsKey); lockMode defaults to compliance, and a seal is locked as long as the records it covers
signer object, required exactly one of kms, transit and file
signer.kms {key, region} an AWS KMS key, ECC_NIST_P384 SIGN_VERIFY, by ARN, ID or alias; the credentials are the SDK's ambient ones, the notary's role
signer.file {path} a P-384 private key in PEM (PKCS#8 or SEC 1), for development
profiles list of strings, at least one, unique every profile the archive has records for the profiles to seal
settle duration 10m how long after an hour has ended it is sealed, so that a batch put late in the hour it is keyed by is in the seal
sink sink none the writer the job records each seal through (audit.seal.written)
require logged, queued or archived none the weakest durability the writer's acknowledgements may carry; needs sink and sink.expect

It reports audit.seal.age (newest sealed hour per profile, of the tenant furthest behind), audit.seal.written and audit.seal.failures over OTLP (telemetry).

audit verify

Checks the record objects of a range of ingest time against the bucket contract (verification). It reads the archive only, so archive has no lockMode and no key is needed. Nightly in the chart, over the last 24 hours, for each profile it names or the deployment composes.

key type default meaning
deployment path, required the profile configuration; each object's lock is held to what its profile demands
archive archive, required the archive to read (bucket, prefix)
profiles list of strings, at least one, unique every profile the deployment composes the profiles whose objects to check
last duration 24h check the objects ingested in the last this long, ending at the hour that has closed
seals object none also check the seals of the range: roots (list of thumbprints, at least one, required) are the only keys trusted; settle (default 10m, keep it equal to the notary's) and grace (default 1h) say when a seal is due. Without it no seal is checked
sink sink none the writer the job records what it checked through (audit.seal.verified or audit.seal.failed per ingest hour, recorded only with seals)
require logged, queued or archived none the weakest durability the writer's acknowledgements may carry; needs sink and sink.expect (durability)

The v0 keys publicKeyFile, lookback and record are gone.

audit purge

Brings the index and the deduplication table within the profiles. Daily in the chart. It never touches the archive.

key type default meaning
deployment path, required the profile configuration
database database, required the index and the deduplication table, as the purge job's own role (audit migrate --purge): delete from both, and add nothing to either
identifyingAfter duration unset: nothing is forgotten early how long the index keeps who an event happened to. No shipped framework profile states one, so it is the deployment's own policy
dedupeWindow duration the widest window the profiles ask for how long a written identifier is remembered

audit clock-sync

Compares the clock with UTC and records the answer. Daily in the chart.

key type default meaning
ntp list of strings, at least one, required time references, host or host:port; the quickest to answer is believed, and one being unreachable is survivable
sink sink none the writer the reading is recorded through
require logged, queued or archived none the weakest durability the writer's acknowledgements may carry; needs sink and sink.expect (durability)
maxOffset duration 1s the offset beyond which the run fails. 0s records any offset and never fails
timeout duration 5s how long to wait for a reference

audit migrate

Applies the schema, grants each part's database role what it needs, and takes back the rest. In the chart it is a pre-install and pre-upgrade hook Job; otherwise run it by hand from one place.

key type default meaning
database database, required the database, as the owner of the tables. No part connects as the owner: an owner is bound by no grant and no row-level security, so the migration refuses to grant a role that is the owner
writer string none the write path's role: the deduplication table, the catalogue registry and the key directory, and none of the index
observe string none the indexer's role: read and write on the index and its cursors, and execute on audit_ensure_month(date), the function that creates a month's partition as the owner
reader string none the query service's role: select on the index's tables, bound by row-level security to the tenants of each request, and nothing else
purge string none the purge job's role: delete from the index and the deduplication table

Each role must already exist, and no role may serve two parts. A part left unnamed gets no grant. A part that connects as the owner has no separation.