SIEM & Webhooks
Not included in DVARA Open Source.
The Enterprise platform writes security-relevant events to an append-only, HMAC-signed, hash-chained audit log. Use its managed exporters and webhooks to send that evidence to the systems where your security and compliance teams already work.
SIEM export
DVARA ships three SIEM exporters out of the box: Splunk HEC, AWS CloudWatch Logs, and Apache Kafka. Each exporter receives persisted audit envelopes through its own bounded queue, so a slow SIEM does not delay the request that produced the event. Any combination can be enabled simultaneously, and failure on one exporter never blocks the others or 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
| Property | Default | Description |
|---|---|---|
enabled | false | Enable Splunk export |
hec-url | — | Splunk HEC endpoint |
token | — | HEC authentication token |
index | blank | Target Splunk index (blank = HEC default) |
source | dvara-gateway | Splunk source field |
source-type | _json | Splunk sourcetype field |
timeout-seconds | 10 | HTTP 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 them to a log group and stream. DVARA signs the HTTP request directly; it does not use the AWS SDK credential chain. Set access-key, secret-key, and, for temporary credentials, session-token. If those properties are blank, DVARA reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN. IRSA and EC2 instance-profile credentials are not read in 1.8.0.
dvara:
llm-gateway:
siem:
cloudwatch:
enabled: true
log-group: /dvara/audit
log-stream: dvara-audit
region: us-east-1
access-key: ${AWS_ACCESS_KEY_ID}
secret-key: ${AWS_SECRET_ACCESS_KEY}
session-token: ${AWS_SESSION_TOKEN:}
endpoint: # blank = default regional endpoint
batch-size: 25
timeout-seconds: 10
flush-interval-seconds: 5
max-buffered-events: 10000
export-queue-capacity: 10000
| Property | Default | Description |
|---|---|---|
enabled | false | Enable CloudWatch export |
log-group | — | CloudWatch Logs group name (must exist) |
log-stream | dvara-audit | Log stream name |
region | us-east-1 | AWS region |
endpoint | blank | Custom endpoint URL (for GovCloud, etc.) |
access-key | AWS_ACCESS_KEY_ID | Access key used for SigV4 signing |
secret-key | AWS_SECRET_ACCESS_KEY | Secret key used for SigV4 signing |
session-token | AWS_SESSION_TOKEN | Session token for temporary credentials |
batch-size | 25 | Events per PutLogEvents call |
timeout-seconds | 10 | HTTP request timeout |
flush-interval-seconds | 5 | Maximum wait before a partial batch is sent |
max-buffered-events | 10000 | Maximum events retained by the CloudWatch exporter buffer |
export-queue-capacity | 10000 | SIEM-wide maximum queued export jobs; events are dropped when the queue cannot accept more work |
The supplied IAM principal needs logs:CreateLogStream and logs:PutLogEvents on the target log group. CloudWatch sends a full batch immediately, sends a partial batch every five seconds by default, and flushes at shutdown. A failed send remains buffered for a later attempt. When max-buffered-events is reached, the oldest buffered event is dropped and logged.
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}";
| Property | Default | Description |
|---|---|---|
enabled | false | Enable Kafka export |
bootstrap-servers | — | Comma-separated broker list |
topic | dvara-audit | Primary target topic |
dead-letter-topic | blank | DLQ for delivery failures (blank = DLQ disabled) |
acks | all | Producer acks — all waits for ISR replication, protecting audit events from broker failures |
security-protocol | — | e.g. SASL_SSL, PLAINTEXT |
sasl-mechanism | — | e.g. PLAIN, SCRAM-SHA-256, SCRAM-SHA-512 |
sasl-jaas-config | — | Full 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.
Verify delivery and chain fields
Every exported record includes the event data plus hmac, previous_hash,
pod_instance_id, chain_epoch, and chain_sequence. Group records by
pod_instance_id and chain_epoch, order by chain_sequence, verify each
previous_hash against the preceding hmac, and then recompute the HMAC with
the protected audit secret. sequence_number is arrival order, not the
position within a chain.
gateway_siem_export_total{exporter,outcome} records success, failure, and
dropped. A non-2xx Splunk response is a failure. A dropped event means the
export queue could not keep up; the primary audit record remains stored. Alert
on any increase in failure or dropped, and update strict SIEM schemas to
accept the chain fields added in 1.8.
A2A events
The A2A plane writes to its own tamper-evident audit chain, separate from the shared LLM/MCP chain. Those A2A_* events (hop intent/result/denied, delegation records, per-hop PII and loop detections, approval decisions) are fanned out to the same three exporters — Splunk, CloudWatch, Kafka — with no separate configuration, inheriting the same source / sourcetype / index. So a single SIEM pipeline sees governance events from all three planes. A2A events likewise appear in the SOC 2 / HIPAA / GDPR / RBI / SEBI compliance reports.
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-workspace and managed from the DVARA Flightdeck.
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. Subscription uses the
WebhookEventTypeenum names; ten of the twelve are identical to the audit event string and the underlying header value, two are not. The full set:Subscription name (the WebhookEventTypeenum)Underlying audit event / X-Gateway-Eventheader valuePOLICY_DENIALPOLICY_DENIEDBUDGET_WARNINGBUDGET_CAP_WARNINGPII_DETECTEDPII_DETECTEDIP_ACCESS_DENIEDIP_ACCESS_DENIEDBUDGET_CAP_SOFTBUDGET_CAP_SOFTBUDGET_CAP_HARDBUDGET_CAP_HARDINJECTION_DETECTEDINJECTION_DETECTEDGUARDRAIL_BLOCKEDGUARDRAIL_BLOCKEDAGENT_LOOP_DETECTEDAGENT_LOOP_DETECTEDMCP_APPROVAL_REQUESTEDMCP_APPROVAL_REQUESTEDMCP_APPROVAL_TIMEOUTMCP_APPROVAL_TIMEOUTCOST_ANOMALYCOST_ANOMALYSubscribe with the left-column names — that's what the
eventTypesarray in the create payload expects, what the DVARA Flightdeck UI lists, and what gets stored. Route receivers on the right-column header value (X-Gateway-Event), or oneventTypeinside the JSON body — both forms are the audit-event string, not the enum name. The two-name relationship for the first two rows is a deliberate carry-over from the audit-event taxonomy; the table above and the audit and compliance guide are the source of truth for the audit-event-string form. If you need a fan-out for events outside this set (WORKSPACE_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 -
Status —
ACTIVEorDISABLED
A webhook URL is fetched server-side by DVARA. When a workspace registers a
webhook through workspace 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 workspace 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 workspace portal registration path
only. The platform-wide Flightdeck page (/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.*:
| Property | Default | Description |
|---|---|---|
enabled | true | Master switch |
max-retries | 3 | Max delivery retry attempts |
base-retry-delay-ms | 1000 | Initial retry delay |
retry-multiplier | 4 | Exponential backoff multiplier (1s → 4s → 16s → 64s) |
delivery-timeout-ms | 5000 | HTTP timeout per attempt |
approval-base-url | blank | Base URL used to build approval action links in MCP webhook payloads |
approval-ttl-minutes | 15 | TTL 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.
Flightdeck rereads the active webhook list at most once every five seconds. Delivery uses 16 workers and a queue of 1,000 waiting jobs. When that queue is full, DVARA drops the oldest waiting delivery and increments gateway_webhook_deliveries_dropped_total; alert on any increase because the dropped delivery is not retried.
Payload headers and signing
Every POST carries three headers:
| Header | Purpose |
|---|---|
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.
Where to manage them
| Action | Where |
|---|---|
| Create, list, edit, delete | Webhooks; Flightdeck applies the signed-in user's role and workspace scope |
| Send a synthetic test event | Test on the webhook's row |
| Per-webhook delivery log | open the webhook — the delivery log is on its detail view |
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→ HTTP404,type: not_found_error
Related
- Observability — Prometheus metrics and the audit event system overview
- Compliance Reports — SOC2 / HIPAA / GDPR / India RBI / SEBI report generation, which consumes the same audit chain
- Configuration — full property reference