Skip to main content
Relay keeps an append-only record of administrative activity: every change made through the control API, every request that was refused, and every login. It answers “who changed this, when, and from where” without an external tool. Inference traffic is not audited here; every inference request already produces a usage event.

What is recorded

One row per HTTP request against the control API, when the request earns one: Each row carries the actor (user id and name, session id, client IP, or anonymous with the attempted username for a failed login), the action, the target resource with its owner and project or team scope, the outcome (allowed, denied or error, plus the HTTP status), and the request’s method, path and id. An apply records one row per change it made. The relay secret commands, which change the secret key ring directly in Postgres, write rows too: the actor kind is cli, its name the operating-system user, the status the one the control API would have answered, and the path the command (relay secret rotate). They write synchronously and fail the command when the write fails. Writes made by a SCIM client carry the actor kind scim-client and the client’s name.

What is never recorded

Values. A write records only the JSON paths it touched, such as metadata.displayName and spec.enabled, never the content of those fields before or after. Creates and deletes record * rather than list every field. Paths that name a credential are dropped entirely: value, keyHash, previousKeyHash, password, passwordHash, token and secret. A rotation is visible as an event, but the audit log never becomes a map of where credentials live.

Reading it back

Results are newest first. Reading the audit log needs read on audit: an admin has it, and so does the built-in auditor role.

Retention

The audit settings section holds retentionDays (default 365). Rows older than the window are removed by an hourly pass; a change takes effect on the next pass, without a restart. Set it to 0 to keep rows forever, for example when you archive the audit_events table yourself. Only an admin may change this section.

Delivery guarantees

Audit writes from the control API are asynchronous and bounded: an admin request never waits on the audit store. When the queue is full, or a batch write fails twice, the rows are dropped rather than blocking the control plane. Drops are counted in relay_audit_dropped_total; alert on it if you need a complete audit trail.