Skip to content

Audit log and SIEM export

Tested with: Audit service (Go) · signed webhook · Kafka with SASL/TLS · S3 Object Lock

Every control-plane action (create, resize, restore, rotate, member change, key create), every admin action by Databasezy staff on your org, every gateway authentication failure and every break-glass command is an audit event with actor, IP, request id, resource and outcome. Retention is one year on standard plans and six years on secure placement and Enterprise.

shell
zb api GET "/v1/orgs/{org}/audit?from=2026-09-24T00:00:00Z&actor_id=usr_01J9...&action=credentials.reveal"
zb api GET "/v1/orgs/{org}/audit/export?from=2026-09-01T00:00:00Z&to=2026-10-01T00:00:00Z" > audit-sep.csv

Each event is a JSON object:

event
{
"id": "evt_01J9QK8X6Z4M2T5N8R3B7C1D9E",
"time": "2026-09-27T10:14:03.221Z",
"org_id": "org_01J8...",
"actor": { "type": "user", "id": "usr_01J8...", "ip": "203.0.113.5", "mfa": true },
"action": "instance.credentials.rotate",
"resource": { "type": "instance", "id": "inst_01J9..." },
"outcome": "success",
"request_id": "req_7f3k...",
"prev_hash": "sha256:…",
"hash": "sha256:…"
}

Events form a hash chain per org; the daily chain head is written to an S3 Object Lock bucket, so a deleted or altered event is detectable.

An org owner adds destinations under Compliance → Audit log streaming, or with POST /v1/orgs/{org}/audit/siem-deliveries. Adding, changing or removing a destination needs a recent second-factor step-up and is itself an audit event. Each destination receives your org’s audit log, your org’s security events, or both, from the moment you add it (or from the start of your retained log).

DestinationWhat we sendYou provide
WebhookHTTPS POST batches, JSON or OCSF, signed (below)An https:// URL on a public address. We generate a signing secret (whsec_...) and show it once, or you supply your own
KafkaOne record per event, protobuf (zb.events.EventRecord, our own schema), JSON or OCSFBootstrap brokers (TLS required), a topic, and SASL scram-sha-512, scram-sha-256 or plain credentials
S3gzip NDJSON objects under your prefixA bucket and prefix that our writer may write to
  • Filters. sources (audit, security), action_prefixes (for example instance. or auth.), and min_severity for security events.
  • Formats.
    • json is one object per event, as shown above.
    • ocsf maps to OCSF 1.1: API Activity (6003) for audit events and Detection Finding (2004) for security events.
    • proto is Kafka only.
  • Delivery. Delivery is at-least-once, in order per source. Failures are retried with a backoff from 30 seconds up to 1 hour, and the portal shows the last error.
  • Errors. The last error is a short reason, such as “the destination answered HTTP 503” or “TLS certificate verification failed”. It never contains your endpoint’s response body.
  • Test. The Test action (.../actions/test) sends one synthetic event now and reports the outcome. You can run it once every 10 seconds per destination.
  • Destinations we refuse. Destinations that resolve to private, loopback, link-local or cloud-metadata addresses, or to Databasezy’s own hosts, are refused when you add them and again on every connection. Redirects are not followed.
  • Secrets. Signing secrets and Kafka passwords are encrypted with our key management service. After creation we never show them again.
  • What we send. We send only your org’s events. Values that look like secrets (passwords, tokens, keys, connection strings) are masked before export. An audit event whose change set was masked carries "redacted": true.

Every request carries X-ZB-Signature: t=<unix seconds>,v1=<hex>. v1 is HMAC-SHA256 with your signing secret over <t>.<raw body>. Reject requests whose t is more than 5 minutes old, and compare in constant time:

verify.py
import hashlib, hmac, time
def verify(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
t, sig = int(parts["t"]), parts["v1"]
if abs(time.time() - t) > tolerance:
return False
mac = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(mac, sig)

The body is {"delivery_id", "org_id", "format", "events": [...]}. X-ZB-Delivery names the destination and X-ZB-Batch the batch, so a retried batch can be deduplicated.

  • Kafka (recommended). Point a Kafka destination (format: json or ocsf) at a topic that Splunk Connect for Kafka reads into your HEC index.
  • S3. Use an S3 destination and the Splunk Add-on for AWS (Generic S3 or SQS-based S3 input).
  • Webhook. HEC expects its own Authorization header. Put a small verifier in front of HEC: check X-ZB-Signature, then forward events to /services/collector/event.
  • S3. Use an S3 destination with the Datadog Forwarder, or Datadog’s S3 log collection, on the bucket.
  • Webhook. Use a verifier that forwards events to the Logs intake (https://http-intake.logs.<site>/api/v2/logs) with your DD-API-KEY. Use ddsource=databasezy.
  • Event Hubs (Kafka endpoint). Create an Event Hubs namespace (Standard tier or above) and an event hub. Add a Kafka destination:
    • brokers <namespace>.servicebus.windows.net:9093;
    • topic = the event hub name;
    • SASL plain, with username $ConnectionString and the namespace connection string as the password;
    • format: ocsf.
  • Ingesting into Sentinel. Read the hub into a Log Analytics workspace with a data collection rule or the Event Hubs data connector.
  • Webhook. Alternatively, use a webhook to a Logic App or Function that verifies the signature and calls the Logs Ingestion API.

Besides the audit log, security-relevant events about your org are emitted as SecurityEvents and can be exported (sources: ["security"]). Examples are failed key or token authentications, rate-limit storms, step-up refusals, egress changes and changes to your export destinations. Each event has a name (e.g. auth.api_key_failed), category, severity, outcome and actor. Events about the platform itself are not exported.