SIEM/SOAR Integration
Pavri can forward alerts to your existing SIEM or SOAR platform in addition to delivering them through the standard alert channels (webhook, Slack, email). SIEM forwarding is best-effort and fail-open — a SIEM outage never blocks alert delivery through primary channels.
Supported Platforms
| Platform | Protocol | Free Tier | Local Testing |
|---|---|---|---|
| Splunk | HTTP Event Collector (HEC) | Splunk Free (500MB/day) | Docker |
| Elasticsearch | Bulk API (NDJSON) | Open source, fully free | Docker |
| Azure Sentinel | Log Analytics Data Collector API | 31-day free trial + $200 Azure credit | Azure account |
| IBM QRadar | Syslog RFC5424 + CEF | QRadar Community Edition (free, 50 EPS) | VM image |
Configuration
SIEM targets are configured via environment variables. Multiple targets can be enabled simultaneously.
Splunk HTTP Event Collector
SIEM_SPLUNK_ENDPOINT=https://your-splunk-host:8088
SIEM_SPLUNK_TOKEN=your-hec-token
SIEM_SPLUNK_INDEX=pavri_alerts # optional, default: pavri_alerts
Elasticsearch
SIEM_ELASTIC_ENDPOINT=https://your-elastic-host:9200
SIEM_ELASTIC_TOKEN=base64(user:password) # optional, leave empty for open access
SIEM_ELASTIC_INDEX=pavri-alerts # optional, default: pavri-alerts
Azure Sentinel (Log Analytics Data Collector API)
SIEM_SENTINEL_ENDPOINT=https://YOUR_WORKSPACE_ID.ods.opinsights.azure.com
SIEM_SENTINEL_WORKSPACE=YOUR_WORKSPACE_ID
SIEM_SENTINEL_TOKEN=YOUR_WORKSPACE_PRIMARY_KEY
SIEM_SENTINEL_INDEX=PavriAlerts # optional, default: PavriAlerts
IBM QRadar (Syslog)
SIEM_QRADAR_ENDPOINT=your-qradar-host:514 # UDP by default
# For TCP syslog:
SIEM_QRADAR_ENDPOINT=tcp:your-qradar-host:514
TLS Configuration
# Skip TLS certificate verification (development/self-signed certs only):
SIEM_TLS_SKIP_VERIFY=true
SIEM_TLS_SKIP_VERIFY=true should never be used in production. It disables certificate verification for all SIEM targets.
Event Format
Splunk HEC Payload
{
"time": 1742987200.0,
"host": "pavri-alert-svc",
"source": "pavri",
"sourcetype": "pavri_alerts",
"event": {
"alert_id": "alert-abc123",
"org_id": "org-tenant-1",
"rule_name": "High Confidence Prompt Injection",
"threat_type": "prompt_injection",
"severity": "high",
"confidence": 0.94,
"action": "block",
"agent_id": "agent-xyz",
"session_id": "sess-123",
"deep_link": "/sessions/sess-123?event=evt-456",
"created_at": "2026-03-26T12:00:00Z"
}
}
Elasticsearch Document
{
"@timestamp": "2026-03-26T12:00:00.000Z",
"alert_id": "alert-abc123",
"org_id": "org-tenant-1",
"threat_type": "prompt_injection",
"severity": "high",
"confidence": 0.94,
"source": "pavri"
}
QRadar CEF (via syslog)
<9>1 2026-03-26T12:00:00Z pavri-alert-svc - - - - \
CEF:0|Pavri|PavriAlertService|1.0|prompt_injection|High Confidence Prompt Injection|8|\
src=pavri suser=agent-xyz msg=prompt_injection cs1Label=OrgId cs1=org-1 \
cs3Label=AlertId cs3=alert-abc123 rt=2026-03-26T12:00:00Z
Free Tier Setup Guides
Splunk (Docker — Fully Local)
The easiest way to test Splunk HEC locally:
docker run -d \
-p 8088:8088 \
-p 8000:8000 \
-e SPLUNK_START_ARGS=--accept-license \
-e SPLUNK_PASSWORD=changeme123 \
--name splunk \
splunk/splunk:latest
Then:
- Wait for Splunk to start (~2-3 minutes):
docker logs -f splunk | grep "Splunk is up" - Open
http://localhost:8000(admin / changeme123) - Go to Settings → Data Inputs → HTTP Event Collector
- Click Global Settings → Enable HEC → Save
- Click New Token → Name:
pavri→ Source Type:pavri_alerts→ Submit - Copy the token and set
SIEM_SPLUNK_TOKEN=<token> - Set
SIEM_SPLUNK_ENDPOINT=https://localhost:8088andSIEM_TLS_SKIP_VERIFY=true(self-signed cert)
Free tier limit: 500MB/day indexing. Sufficient for development and small production workloads.
Elasticsearch (Docker — Fully Free, Open Source)
docker run -d \
-p 9200:9200 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
--name elasticsearch \
docker.elastic.co/elasticsearch/elasticsearch:8.12.0
Verify it's running:
curl http://localhost:9200
Set environment variables:
SIEM_ELASTIC_ENDPOINT=http://localhost:9200
# No token needed when xpack.security.enabled=false
View alerts: open Kibana or query directly:
curl http://localhost:9200/pavri-alerts/_search?pretty
Cost: Free forever for the open-source distribution. Elastic Cloud offers a 14-day free trial.
Azure Sentinel (Cloud — Free Trial)
- Create an Azure free account ($200 credit for 30 days)
- Create a Log Analytics workspace in Azure Monitor
- In the workspace, go to Agents management → copy Workspace ID and Primary Key
- Set the environment variables:
SIEM_SENTINEL_ENDPOINT=https://YOUR_WORKSPACE_ID.ods.opinsights.azure.com
SIEM_SENTINEL_WORKSPACE=YOUR_WORKSPACE_ID
SIEM_SENTINEL_TOKEN=YOUR_PRIMARY_KEY
View logs: Azure Portal → Log Analytics workspace → Logs → query PavriAlerts_CL.
Cost: First 31 days free on a new workspace. After that, pay-per-GB ingestion (~$2.76/GB).
The Data Collector API (/api/logs) is a legacy endpoint. For new Azure deployments, consider migrating to the Logs Ingestion API.
IBM QRadar Community Edition (VM — Free, 50 EPS)
- Download QRadar CE from the IBM Community (requires free IBM ID)
- Deploy the VM image in VMware Workstation or VirtualBox
- In QRadar admin console: Admin → Data Sources → Log Sources → Add
- Select Syslog as the log source type
- Configure the listener IP and port (default: UDP/514)
- Set
SIEM_QRADAR_ENDPOINT=YOUR_QRADAR_IP:514
Cost: Free. Limited to 50 EPS (events per second). Sufficient for testing and small production deployments.
Helm Chart Configuration
Add SIEM environment variables to your Helm values.yaml:
services:
alert:
env:
SIEM_SPLUNK_ENDPOINT: "https://splunk.internal:8088"
SIEM_SPLUNK_TOKEN: "" # Set via external-secrets or sealed-secrets
SIEM_ELASTIC_ENDPOINT: "https://elastic.internal:9200"
For secrets, use Kubernetes secrets or the external-secrets-operator:
# values.yaml
services:
alert:
envFrom:
- secretRef:
name: pavri-siem-credentials
Observability
SIEM forwarding failures are logged at WARN level by the alert service:
alert-svc: SIEM forwarding enabled for 2 target(s)
siem: forward to splunk failed (alert=alert-abc123): splunk: unexpected status 503
SIEM failures do not appear as alert status=failed — the alert record's delivery status only reflects primary channel delivery.
Integration Testing
Pavri includes end-to-end integration tests that verify alerts are actually ingested by real Splunk and Elasticsearch instances running in Docker containers.
Prerequisites
- Docker and Docker Compose v2
- Go 1.21+
- Ports 8088, 8089, 9200 available on localhost
Quick Start
Run the full test cycle (start containers, run tests, tear down):
./scripts/siem-test.sh
Step-by-Step
- Start the SIEM test stack:
./scripts/siem-test.sh --up
This starts Splunk (with HEC pre-configured) and Elasticsearch (single-node, security disabled) in Docker, then waits for both to become healthy. Splunk typically takes 2-3 minutes to start.
- Run the integration tests:
go test -tags integration ./services/alert/internal/siem/ -v -count=1 -timeout 120s
The tests will:
- Forward test alerts to Splunk HEC and verify them via the Splunk REST search API
- Forward test alerts to Elasticsearch and verify them via the
_searchAPI - Test the multi-SIEM dispatcher against both systems simultaneously
- Tear down:
./scripts/siem-test.sh --down
Test Architecture
The integration tests use the //go:build integration build tag, so they never run during normal go test ./... invocations. Each test also checks TCP reachability before running and calls t.Skip() if the target service is not available.
| Test | What it verifies |
|---|---|
TestSplunkForwarder_Integration | Alert forwarded via HEC, searchable via REST API, correct fields indexed |
TestElasticForwarder_Integration | Alert indexed via Bulk API, searchable via _search, correct document structure |
TestMultiSIEMDispatcher_Integration | Single alert appears in both Splunk and Elasticsearch |
The Docker Compose file is at services/alert/internal/siem/testdata/docker-compose.siem-test.yml.
Troubleshooting
| Symptom | Likely Cause | Resolution |
|---|---|---|
| No events in Splunk | HEC not enabled, or wrong token | Settings → Data Inputs → HTTP Event Collector → verify token |
splunk: unexpected status 401 | Invalid HEC token | Regenerate token in Splunk HEC settings |
splunk: unexpected status 400 | Malformed event (sourcetype issue) | Verify SIEM_SPLUNK_INDEX matches a valid sourcetype |
elastic: unexpected status 400 | Wrong Content-Type or index routing | Check index template; re-create index if schema mismatch |
sentinel: build signature: decode workspace key | Workspace key is not valid base64 | Copy the primary key directly from Azure Portal (it is already base64) |
| No events in QRadar | UDP packet lost or wrong port | Try TCP: set SIEM_QRADAR_ENDPOINT=tcp:<host>:514 |
| All SIEM errors but alerts still delivered | Expected — SIEM is fail-open | Check logs; primary alert channels are unaffected |