Configuration reference¶
The configuration file of each binary: its shape, secrets, shared blocks and refusals. Keys per binary: writer, observe and query, jobs. See also emitter library and chart values.
One installation serves one application (0053).
The configuration file¶
Only the file configures a process; no flag has an environment fallback (0063). Everything here is version 2.
| Command | Flags |
|---|---|
audit-writer, audit-observe, audit-query |
--config <file>, --version, --help |
audit verify, purge, clock-sync, migrate |
--config <file> replaces every other flag. Only --json may accompany it. A command line naming both a file and another flag is refused |
Interactive audit commands |
Their own flags, for a person at a keyboard |
The file is YAML. The binary's JSON Schema in schemas/config/ validates it before anything starts. The schemas ship in the release.
| Binary or command | Schema |
|---|---|
audit-writer |
audit-writer.schema.json |
audit-observe |
audit-observe.schema.json |
audit-query |
audit-query.schema.json |
audit verify, purge, clock-sync, migrate |
audit-verify.schema.json, audit-purge.schema.json, audit-clock-sync.schema.json, audit-migrate.schema.json |
| Rule | Detail |
|---|---|
apiVersion |
audit.truvity.github.io/<kind>/v2. <kind> is the schema name, such as audit-writer-lambda |
| Versions | A binary reads N and N-1 (ADR 0067). Version 1 is deprecated, converted on load with a warning, and read for one more minor (v0.13 upgrade). Another version or kind is refused |
| Schemas | Version 2: schemas/config/<kind>.schema.json, $id https://truvity.github.io/sluis/schemas/audit/v2/config/<kind>.schema.json. Version 1: frozen in schemas/config/v1/ |
| Errors | An unknown key, a missing required key or a wrong type is a start-up error naming the path. Rules a schema cannot say run after it (Refusals) |
| Regeneration | just audit-config-schemas regenerates the schemas from internal/config/schema/schema.go. The chart validates the same files when it renders |
| Durations | Go notation: 30s, 2m, 168h |
AUDIT_CONFIG |
Where the file is. The six binaries and four audit jobs read it. --config wins. For an audit job it counts only on a command line with no option of its own |
| Lambda default | Without flag or variable: /opt/audit/audit.yaml, then /var/task/audit.yaml (kept one release after the move to the layer) |
Secrets¶
A ...Secret field holds a secret's name, never the secret. The file's secrets block says how to find it. An absent or empty secret is an error naming the field, source and root, never a value.
| key | holds |
|---|---|
database.passwordSecret |
the Postgres password |
bucket.credentialsSecret.accessKeyID, .secretAccessKey |
the static credentials of an S3-compatible store |
openbao.tokenSecret |
an OpenBAO token |
secrets:
source: file # env (the default), file or ssm
root: /etc/audit/secrets # a directory (file) or a parameter path (ssm); not with env
source |
A name is | root |
|---|---|---|
env |
The name of an environment variable | Refused |
file |
A path under root, one file per secret, read as is except one trailing newline: a mounted Kubernetes Secret |
An absolute directory, required |
ssm |
A SecureString parameter <root>/<name> in AWS Systems Manager Parameter Store, read decrypted with the process's identity |
A path starting with / and not ending in one, required |
| Rule | Detail |
|---|---|
| Names | For file and ssm: relative, segments of letters, digits, ., _, -, no ... A root has no empty, . or .. segment |
| AWS Lambda | Use ssm. source: env is refused when AWS_LAMBDA_FUNCTION_NAME is set, including a converted version-1 ...Env. The Pulumi library renders the block and grants ssm:GetParameter(s) on the root only (AWS) |
| Kubernetes | Use file. The chart's secretFiles projects each Secret key as the named file |
| Database URL | A password in it is refused |
| Files | Token, key and root files are referenced by path: tokenFile, jwtFile, rootFile, keyFile.path, caFile |
Telemetry¶
The file holds none. The OTEL_* variables configure telemetry. The chart's telemetry.otlp renders them (telemetry); on Lambda see AWS.
Health: /healthz and /readyz¶
audit-writer, audit-query and audit-observe serve both on listen. Checks run at every probe, in parallel, within 2 seconds. A 503 names the failed checks, not their errors.
| Endpoint | Probe | Passes when | On failure |
|---|---|---|---|
/healthz |
Liveness | The process is up, and a stream or queue consumer has not stopped on its own | Restarts the pod |
/readyz |
Readiness | The database answers (writer with database, query with the postgres searcher, observe); the catalogue registry reads (writer with database); the archive lists (query with s3scan, observe's catalogues); a consumer runs. A receiver with neither is ready when up |
Removes the pod from the Service, no restart |
Evidence: the writer's start-up record¶
audit.writer.started carries these as data (schema writer-started.json). The writer refuses a file that changed between its two reads, before and after validation.
| Field | Value |
|---|---|
config_file |
The file read |
config_digest |
sha256: and the SHA-256 of the file's bytes, as sha256sum prints |
deployment_digest, workloads_digest |
Digests of the named documents |
catalogues_digest |
Digest of each file's relative name and digest, in name order |
layer |
Lambda: the layer version ARN from AUDIT_CONFIG_LAYER |
function_version |
Lambda: AWS_LAMBDA_FUNCTION_VERSION. An unknown field is left out |
Documents the file points at¶
The file names four documents by path. The first three carry apiVersion and have a schema in schemas/config/: audit-deployment, audit-grants, audit-workloads (.schema.json).
| Key | Document | In the chart |
|---|---|---|
deployment |
The profile configuration: the framework profiles each profile composes, and externalIdentifiersAreOpaque |
/etc/audit/deployment.yaml, from profiles and externalIdentifiersAreOpaque |
workloads |
Trusted issuers and which service account speaks for which source (Workload identity) | /etc/audit/workloads.yaml, from workloadIdentity |
grants |
The query service's issuers, presets and rules (Grants file) | /etc/audit/grants.yaml, from query.grants |
catalogues |
A directory of catalogue documents registered at start-up | /etc/audit/catalogues, from catalogues |
Shared blocks¶
These blocks recur under several keys. They follow the shared fragments of the
component contract (postgres.json, bucket.json, listen.json,
nats.json).
database (a PostgreSQL connection)
| key | type | default | meaning |
|---|---|---|---|
url |
string, required | a postgres:// or postgresql:// URL without a password. A URL with one is refused, and one that does not parse is refused |
|
passwordSecret |
string | none: the connection needs no password | secret by reference: the name of the secret holding the password |
maxConnections |
integer, at least 1 | 10 | the pool size of this process. Size it against the server's limit divided by the number of processes |
bucket (an object store addressed by the S3 API)
| key | type | default | meaning |
|---|---|---|---|
name |
string, required | the bucket, which exists already | |
region |
string | the SDK's own resolution | the region the bucket is in |
endpoint |
URI | the SDK's own resolution for the region | override the API endpoint, for a store that is not AWS |
ca |
path | the system trust store | a CA bundle trusted for that endpoint, mounted by the platform |
pathStyle |
boolean | false | address the bucket as a path rather than a host, for a certificate that does not cover a bucket subdomain |
credentialsSecret.accessKeyID, .secretAccessKey |
strings, both required if the block is present | none: the SDK's ambient credentials, which is what a workload identity provides | secret by reference: the names of the secrets holding static credentials |
archive (what the process adds to the deployment's presets). Where the archive is -- the bucket, prefix,
region and endpoint of each install preset -- and the Object Lock it is written under (compliance for the
attested preset, none for the others) are the deployment document's presets
(0068, profiles).
The processes that open the archive take it: audit-writer (mode writer), the writer Lambda, audit-query, audit-observe, audit-notary and audit verify. The receiver, audit migrate, audit purge and audit clock-sync open no archive. The process names the deployment (deployment) and may carry:
| key | type | default | meaning |
|---|---|---|---|
stateRoot |
string | none | the root of the installation's state store, below which a preset's credentials address is read. Needed when a preset is at an endpoint with credentials |
sluisRoot |
string | none | the SSM root of the sluis installation (/sluis/<instance>) below which a preset's credentials_ref is read with the process's identity. Exclusive with sluisDir |
sluisDir |
path | none | the directory a secrets operator projects a preset's credentials_ref into, read at <sluisDir>/<credentials_ref>. Exclusive with sluisRoot |
ca |
path | the system trust store | a CA bundle for a store whose certificate is not signed by a public root |
kmsKey |
string | the bucket's default encryption | the key objects are encrypted with where a preset names no key_alias. Only the writer and the notary have it |
listen: address (string, host:port such as :8080, required when the
block is present). Both servers default it to :8080.
sink (the writer a process records through)
| key | type | default | meaning |
|---|---|---|---|
url |
string | the writer's base URL. Exactly one of url and sqs |
|
sqs |
queueUrl (required), region, fifo |
the ingest queue of a writer that runs elsewhere, such as the writer Lambda: records are sent to the queue and acknowledged queued. There is no credential in the file: the pod's own identity is it (EKS Pod Identity, or IRSA through the service account's annotation), and its role needs sqs:SendMessage on the queue. tokenFile is refused with it, and expect is queued and may be left out |
|
tokenFile |
path | none: no token, which only an anonymous trial install accepts | the file holding the bearer token, read afresh on every request; in a cluster the pod's projected service-account token |
expect |
logged, queued or archived |
none: the client claims nothing | what the writer at url is configured to give. A client cannot learn that until it writes, so the file says (sink.Client.Expecting); the process's require is checked against it at start-up and against every acknowledgement afterwards |
openbao (how a process reaches an OpenBAO transit engine)
| key | type | default | meaning |
|---|---|---|---|
address |
string, required | the server, for example https://openbao.example.com:8200 |
|
mount |
string | transit |
where the transit engine is mounted |
namespace |
string | the root namespace | the namespace the engine and the auth mount are in |
caFile |
path | the system roots | a PEM bundle trusted beside them |
login.mount, .role, .jwtFile |
strings, all required | sign in with a JWT: the auth mount, the role on it, and the file holding the pod's projected token, read at every login. Nothing is stored | |
tokenFile |
path | sign in with a token read from a file on every call | |
tokenSecret |
string | secret by reference: the name of the secret holding a token |
Exactly one of login, tokenFile and tokenSecret.
keys (where the keys live, by purpose: the storage port's shape, the adapter block)
| key | type | default | meaning |
|---|---|---|---|
adapter |
kms, transit or local |
the key service: kms (AWS KMS, keys by alias), transit (OpenBao) or local (a root file; development) |
|
seal |
a key name, or {key, context} |
the notary's seal key: asymmetric ECC P-384 (ES384). It signs and takes no encryption context. The notary takes keys.seal: exactly one of seal and signer |
|
pseudonym |
a key | wraps the per-tenant pseudonym secrets. Provisioned only for an installation that pseudonymises (the attested preset, or a profile that needs pseudonyms) |
|
conceal |
a key | identities sealed where the law requires them to be recoverable | |
archive |
a key | the key the archive's objects are encrypted with (for S3, the SSE-KMS alias) | |
instance |
string | names the installation in the default encryption context {instance, purpose}; bound into ciphertexts, so choose something stable and non-secret |
|
state |
{root, address} |
with kms: where the wrapped per-tenant secrets behind pseudonym are kept (the installation's SSM store). Nothing in it is usable without the pseudonym key |
|
openbao |
openbao |
with transit: the engine and how to sign in |
|
rootFile |
path | with local: a file of 32 bytes |
|
provider |
none, local or transit |
deprecated: the first releases' shape, still loaded. Use adapter and a key per purpose. Unset, or none, means no pseudonyms, no key material and no resolve (0055). The local and transit blocks beside it are deprecated with it |
A key is an alias or a transit key name; an ARN or key id is refused. The archive's own credentials ({root, address})
read {accessKeyID, secretAccessKey} from an internal/ address, for an archive on an endpoint
(archive on R2).
Refusals¶
Every refusal is a start-up error naming the key. The grants file has its own, under Grants file.
| Refused by the schema |
|---|
workloads and anonymousWrites together, or neither |
mode: receiver with archive, catalogues, keys or consume, or with neither stream nor forward |
forward with none or several of nats, sqs, log; consume with none or both of nats, sqs; forward in a writer |
require: archived in a receiver; forward.log without require: logged; require on an emitter with no sink |
A writer without archive |
keys with no adapter, or with the removed provider, local or transit keys |
An openbao with none or several of login, tokenFile, tokenSecret |
secrets with root and source env; source file or ssm with a root that is not an absolute directory or SSM path |
A signer with none or several of kms, file |
| A database URL with a password |
A query service with the postgres searcher and no database, or s3scan and no archive |
| Refused after the schema | Reason |
|---|---|
A require the chain can never give (the guard); an emitter require with no sink.expect or a weaker one |
Start-up guard |
forward.sqs.fifo: true on a URL not ending in .fifo |
URL and flag disagree |
stream.ackWait not longer than roll.interval |
The stream would offer unacknowledged records to another writer |
replicas above 1 without database |
In-process deduplication misses a redelivery landing on another replica |
keys on the query service without archive |
Resolve opens what the writer sealed in the archive |
A database.url that does not parse |
Invalid URL |
A profile demanding a stricter Object Lock than its preset's bucket gives, or whose preset is not under presets |
The writer names the profile and preset |
A profile name containing / |
It is a key component |