Skip to main content

Audit webhook forwarding

Mirror every audit row to your SIEM. HMAC-signed.

An optional out-of-band mirror POSTs every audit-log row to a webhook receiver as soon as it is written. JSON-per-row body, HMAC-SHA256 signature in X-Z4J-Audit-Signature, full SSRF and DNS-pin protection. The brain's primary HMAC-chained audit log stays the source of truth; the forwarder is a best-effort mirror that fans the data out to Splunk HEC, Datadog Logs, Sumo, Elastic, or any HTTPS endpoint. A slow receiver does not slow the brain: rows go through an in-memory bounded queue drained by a background task, and queue saturation drops the row plus increments a metric instead of blocking the write path.

Ships with

  • JSON body matches the canonical HMAC-chain form, plus the row_hmac for receiver-side chain verification
  • HMAC-SHA256 over the literal request body; same envelope shape as the generic webhook notification channel
  • Required HMAC secret with a 32-byte floor enforced at Settings load (unauthenticated mirror would let downstream parsers trust forged rows)
  • Same SSRF and DNS-pin guard as notifications: loopback, RFC1918, link-local, cloud metadata, CGNAT, IPv4-mapped IPv6 all blocked
  • Bounded in-memory queue (Z4J_AUDIT_WEBHOOK_BUFFER_SIZE) so a backed-up receiver drops rows instead of blocking the audit write path

Highlights

  • 32-case test suite covers settings validation, payload shape, signature determinism, queue full / shutdown / misshapen-row paths, SSRF rejection, 5xx response handling, and full drain-task lifecycle
  • Failure surfaces show up in z4j_swallowed_exceptions_total under module=audit_forwarder with three sites (queue_full / ssrf_or_dns / send_one) so operators see steady-state drops in Grafana
  • Forwarder is constructed only when the URL is set: no queue allocation, no background task, no extra import cost on deployments that do not use it
Related

More capabilities