Skip to main content

SIEM & Webhooks

DVARA writes every security-relevant event to an append-only, HMAC-signed, hash-chained audit log. For compliance and incident response, you'll almost certainly need to ship those events to a SIEM or fan them out to webhooks. This page covers both.


SIEM export

DVARA ships three SIEM exporters out of the box: Splunk HEC, AWS CloudWatch Logs, and Apache Kafka. Each exporter subscribes to the audit event stream and forwards events as they are written. Any combination can be enabled simultaneously — events are dispatched to every active exporter, and failure on one exporter never blocks the others or the primary audit persistence.

Splunk HEC

Splunk's HTTP Event Collector receives audit events as JSON over HTTPS. DVARA POSTs to the HEC endpoint using the configured token and index.

dvara:
llm-gateway:
siem:
splunk:
enabled: true
hec-url: https://splunk.example.com:8088/services/collector
token: ${SPLUNK_HEC_TOKEN}
index: dvara-audit # blank = default index
source: dvara-gateway
source-type: _json
timeout-seconds: 10
PropertyDefaultDescription
enabledfalseEnable Splunk export
hec-urlSplunk HEC endpoint
tokenHEC authentication token
indexblankTarget Splunk index (blank = HEC default)
sourcedvara-gatewaySplunk source field
source-type_jsonSplunk sourcetype field
timeout-seconds10HTTP timeout

The source-type: _json default tells Splunk to parse events as structured JSON, so every DVARA audit field becomes a searchable attribute. No Splunk-side field extraction required.

AWS CloudWatch Logs

CloudWatch Logs batches events and flushes to a log group + log stream on a schedule. DVARA uses the AWS SDK under the hood and honors the default credential provider chain (IRSA on EKS, instance profile on EC2, env vars otherwise).

dvara:
llm-gateway:
siem:
cloudwatch:
enabled: true
log-group: /dvara/audit
log-stream: dvara-audit
region: us-east-1
endpoint: # blank = default regional endpoint
batch-size: 25
timeout-seconds: 10
PropertyDefaultDescription
enabledfalseEnable CloudWatch export
log-groupCloudWatch Logs group name (must exist)
log-streamdvara-auditLog stream name
regionus-east-1AWS region
endpointblankCustom endpoint URL (for GovCloud, etc.)
batch-size25Events per PutLogEvents call
timeout-seconds10AWS SDK timeout

IAM permissions — the task / pod identity must have logs:CreateLogStream and logs:PutLogEvents on the target log group.

Apache Kafka

Kafka is the highest-throughput option — use it when your SIEM is a Kafka consumer (Fluentd, Logstash, Vector) or when you need a durable buffer in front of your SIEM. DVARA publishes to Kafka with SASL and SSL authentication support.

dvara:
llm-gateway:
siem:
kafka:
enabled: true
bootstrap-servers: broker1.example.com:9092,broker2.example.com:9092
topic: dvara-audit
dead-letter-topic: dvara-audit-dlq
acks: all
security-protocol: SASL_SSL
sasl-mechanism: SCRAM-SHA-512
sasl-jaas-config: >-
org.apache.kafka.common.security.scram.ScramLoginModule required
username="dvara" password="${KAFKA_PASSWORD}";
PropertyDefaultDescription
enabledfalseEnable Kafka export
bootstrap-serversComma-separated broker list
topicdvara-auditPrimary target topic
dead-letter-topicblankDLQ for delivery failures (blank = DLQ disabled)
acksallProducer acks — all waits for ISR replication, protecting audit events from broker failures
security-protocole.g. SASL_SSL, PLAINTEXT
sasl-mechanisme.g. PLAIN, SCRAM-SHA-256, SCRAM-SHA-512
sasl-jaas-configFull JAAS config string

The default acks=all is deliberate: audit events must survive broker failures. Dropping this to acks=1 or acks=0 improves throughput but risks silent data loss — don't do it for compliance use cases.

Multi-destination export

Every exporter runs independently. Enabling all three ships each event to Splunk, CloudWatch, and Kafka in parallel — useful for migration scenarios or when different teams own different pipelines.


Webhooks

Webhooks are the outbound side of DVARA's event system — HTTPS callbacks fired when specific events occur (policy decisions, budget breaches, approval gates, MCP tool calls, etc.). They're per-tenant and managed via the DVARA Flightdeck or the Automation API.

Each webhook has:

  • URL — target HTTPS endpoint
  • Event types — which DVARA event types to subscribe to. Webhook fan-out is selective, not general: it covers a fixed set of 12 operational and security events, not every audit event the gateway writes. The full set (see the WebhookEventType enum) is POLICY_DENIAL, PII_DETECTED, IP_ACCESS_DENIED, BUDGET_CAP_SOFT, BUDGET_CAP_HARD, BUDGET_WARNING, INJECTION_DETECTED, GUARDRAIL_BLOCKED, AGENT_LOOP_DETECTED, MCP_APPROVAL_REQUESTED, MCP_APPROVAL_TIMEOUT, and COST_ANOMALY. Subscribe with these names; two of them ship on the X-Gateway-Event delivery header in a slightly different form — POLICY_DENIAL arrives as POLICY_DENIED and BUDGET_WARNING arrives as BUDGET_CAP_WARNING. If you route on the header value (rather than parsing the JSON body), match both forms or filter on the body's eventType. If you need a fan-out for events outside this set (TENANT_CREATED, GATEWAY_RESPONSE, etc.), use SIEM export instead — SIEM ships every audit event the gateway writes.
  • Secret — HMAC-SHA256 signing secret, sent as the X-Gateway-Signature: sha256=<hex> header
  • StatusACTIVE or DISABLED

:::note SSRF protection on tenant-supplied URLs

A webhook URL is fetched server-side by DVARA. When a tenant registers a webhook through tenant self-service, the URL is validated at save time: it must be an http/https endpoint that does not resolve to a loopback, private, link-local, or cloud-metadata address (e.g. 127.0.0.1, 10.0.0.0/8, 192.168.0.0/16, 169.254.169.254). This blocks server-side request forgery — a tenant cannot turn webhook delivery into a probe of your internal network or cloud metadata. As defense-in-depth, operators should also run a network egress policy so the gateway can only reach intended destinations.

Scope: this validation runs on the tenant portal registration path only. The platform admin REST endpoint (POST /v1/admin/webhooks, owner role) deliberately does not validate — it's a privileged path used for operator tooling like internal monitoring webhooks. Scripts that accept arbitrary URLs and call the admin endpoint should add their own URL allowlist; otherwise an owner-scoped PAT can register a webhook to any address the gateway can reach.

:::

Retry and delivery

Webhook delivery uses exponential backoff with a bounded retry count. Global config under dvara.llm-gateway.webhooks.*:

PropertyDefaultDescription
enabledtrueMaster switch
max-retries3Max delivery retry attempts
base-retry-delay-ms1000Initial retry delay
retry-multiplier4Exponential backoff multiplier (1s → 4s → 16s → 64s)
delivery-timeout-ms5000HTTP timeout per attempt
max-delivery-log-entries50000Total delivery log cap (oldest evicted)
approval-base-urlblankBase URL used to build approval action links in MCP webhook payloads
approval-ttl-minutes15TTL for HMAC-signed approval tokens

Every delivery attempt (success or failure) is recorded in the delivery log. The DVARA Flightdeck surfaces this log per webhook so you can debug 502s, timeouts, and signature mismatches.

Payload headers and signing

Every POST carries three headers:

HeaderPurpose
X-Gateway-Signature: sha256=<hex>HMAC_SHA256(secret, rawBody). Your receiver must verify this before trusting the payload.
X-Gateway-Event: <event-type>The DVARA event type (one of the 12 above). Use this to route on the receiver side without parsing the body.
X-Gateway-Delivery: <uuid>Stable delivery ID. Same value across every retry of the same event, so it doubles as a natural idempotency key.

A reference signature-verification implementation in Python:

import hashlib, hmac

def verify(request, secret):
signature = request.headers.get("X-Gateway-Signature", "")
if not signature.startswith("sha256="):
return False
expected = hmac.new(
secret.encode(),
request.body, # raw bytes — must be pre-parse
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature[len("sha256="):], expected)

The signature is over the raw request body bytes as sent on the wire. If your receiver framework parses and re-serializes JSON before handing it to your code (common in some middleware stacks), capture the raw body upstream — re-serialized JSON will not byte-match and signature verification will fail.

Approval webhooks (MCP)

When an MCP tool call hits an approval gate, DVARA fires an approval webhook with signed action links so a human approver can click "Approve" or "Deny" directly from a Slack / email message. The links are HMAC-signed bearer tokens with a TTL of approval-ttl-minutes (default 15) and resolve via POST /v1/webhooks/actions/{action}?token=<signed-token>.

Configure approval-base-url to your public gateway URL so the links are clickable from outside your cluster.

Admin API

EndpointPurpose
POST /v1/admin/webhooksCreate webhook
GET /v1/admin/webhooksList (filter by ?tenant_id=)
PUT /v1/admin/webhooks/{id}Update
DELETE /v1/admin/webhooks/{id}Delete
POST /v1/admin/webhooks/{id}/testSend a synthetic test event
GET /v1/admin/webhooks/{id}/deliveriesPer-webhook delivery log

Use the test endpoint when onboarding a new webhook to validate signature verification on the receiver side before going live.

Error codes

  • webhook_not_found → HTTP 404, type: not_found_error