Skip to main content

Module audit_log

Module audit_log 

Source
Expand description

Structured audit log for SOC 2 / HIPAA / ISO 27001 deploys.

Replaces the previous free-form record(action, principal, target, result, details) API with a stable JSON-Lines schema keyed on event_id, ts, principal, tenant, action, resource, outcome, detail, remote_addr, and correlation_id so external tooling (Splunk, Datadog HEC, ELK, BigQuery, Athena) can ingest the file without per-deploy regex.

Operational properties:

  • Async-write: emit sites push onto a bounded std::sync::mpsc channel; a dedicated thread owns the file handle and flushes on a periodic timer (default 250 ms) or per-event when RED_AUDIT_FSYNC=every. If the channel fills the emit site falls back to a direct sync write — losing throughput is preferable to dropping audit lines.
  • Rotation: when the active file exceeds RED_AUDIT_MAX_BYTES (default 64 MiB) the writer renames it to .audit.log.<ms>.zst, zstd-compresses it, and starts a fresh active file. The repo already pulls zstd; we don’t add a gzip dependency.
  • Hash chain (tamper-evidence): each event carries a prev_hash field — the sha256 of the previous JSON line. An auditor verifying the file recomputes the chain; a single edit anywhere in the file breaks every subsequent hash. Does not defend against an attacker with root + write (they could rebuild the chain), but it does defend against accidental edits and most insider tampering.
  • SIEM streaming: when RED_AUDIT_STREAM_URL is set every line is also POSTed to that URL fire-and-forget.

Pre-1.0: the file format breaks from the previous shape. Old .audit.log files are NOT readable by the new query endpoint. That’s an accepted regression — operators upgrading should rotate the file before the deploy.

Structs§

AuditEvent
Structured audit event. Serialised as one JSONL row per call.
AuditEventBuilder
Builder for AuditEvent. Generated by AuditEvent::builder().
AuditField
A single typed audit field (key + typed value). Construction is gated by AuditFieldEscaper::field so the typed value cannot be bypassed — there is no pub constructor for the field that accepts a free-form string value.
AuditFieldEscaper
Typed-field guard for audit emission (ADR 0010).
AuditLogger

Enums§

AuditAuthSource
Auth pathway that produced the principal. Decoupled from crate::auth::AuthSource so we can record System / Anonymous / Session / ApiKey lanes that aren’t surfaced by the runtime auth enum (which only covers Password / ClientCert / Oauth today).
AuditValue
Typed value variants accepted by the audit-field guard. The serializer (to_json_line) owns the framing; an AuditValue cannot smuggle structural bytes past the canonical encoder (crate::serde_json::Value::escape_string, RFC 8259 §7) because the variant is consumed as a typed value, not as an interpolated string. Adversarial corpora (CRLF, NUL, quote, semicolon, JSON-in-JSON, control bytes 0x00..0x20) survive the boundary because the encoder emits \u00XX escapes for every byte below 0x20.
Outcome
Outcome of the audited action.