SIEM Integration

Splunk HEC

Ship Arbiter authentication rejects and security events into Splunk via the HTTP Event Collector. Same data shape as the Sentinel integration, simpler auth model (a single static token rather than an Entra app), one less Azure-only concept to learn.

How it fits together

Arbiter posts events as JSON to Splunk's HTTP Event Collector endpoint, authenticated with a static token in the request header. No agent on either side. The chain looks like this:

Your Splunk stackArbiter CoreSIEM forwarder(cadence-aware)HTTPStoken in headerHEC/services/collectorIndexarbiterSearch / SPLdashboards, alerts
Arbiter Core opens a TLS connection to the Splunk HEC endpoint on every cadence tick, posts a batch of events with the HEC token in the Authorization header, and Splunk routes them into the configured index. Search reads from there.

Two Splunk-side concepts the rest of the guide will touch:

  • HEC token: a UUID that authorises a writer. You create one in Splunk and paste it into Arbiter. Tokens are bound to an index and (optionally) a sourcetype.
  • Sourcetype: how Splunk tags an event for parsing. Arbiter always sends sourcetype=arbiter:security_event regardless of stream; the per-stream tag lives inside the JSON body under source (e.g. arbiter.auth_log_rejects).

Available streams

Each Arbiter SIEM target ships exactly one stream. To ship two, create two targets pointing at the same HEC endpoint (one token per target is cleanest; one token shared is fine too).

StreamPurposeVolumeSplunk filter
Security eventsRule-based detections (SOC alerting and triage)Very low: tens per tenant per daysource=arbiter.security_events
Auth log rejectsFailed authentication attempts (forensics, compliance)Moderate: 5 to 15% of total auth eventssource=arbiter.auth_log_rejects
Auth log (all)Permits and rejects, full RADIUS verdict feedHigh: every authenticationsource=arbiter.auth_log_all
Accounting eventsAcct-Start / Stop / Interim with session lifetimeHigh: scales with session countsource=arbiter.accounting_events
Audit logOperator actions (policy edits, RBAC changes)Very lowsource=arbiter.audit_log
Endpoints snapshotFull device inventory, dailyOne snapshot per daysource=arbiter.endpoints_snapshot

Security events

Rule-based detections fired by Arbiter: suspicious traffic on a guest VLAN, unknown MAC bursts, expired-certificate attempts. Negligible ingest cost for SME tenants.

Auth log rejects

Every rejected authentication attempt: failed 802.1X, unknown MAC, policy-denied, expired cert. Includes the matched policy and auth policy so denial reasons are correlatable.

Before you start

Prerequisites

  • A Splunk instance you can reach. Splunk Cloud Platform free trial (14 days, 5 GB/day) is the lowest-friction option. A self-hosted Splunk Enterprise on Docker works too: docker run -p 8000:8000 -p 8088:8088 -e SPLUNK_START_ARGS=--accept-license -e SPLUNK_PASSWORD=changeme splunk/splunk:latest.
  • An Arbiter tenant where you are signed in as an admin.
  • Permission to create indexes and HEC tokens in Splunk (Admin role or equivalent custom role).
  • Outbound HTTPS from arbiter-radius to your Splunk HEC URL on port 443 (Splunk Cloud) or 8088 (self-hosted). No inbound rules at the customer site.
Allow about 15 minutes end-to-end. The Splunk side is faster than Sentinel because there is no DCR or app-registration flow: create an index, create a token, paste the token into Arbiter.

Confirm your HEC endpoint URL

Why: Splunk Cloud uses a different host for HEC than the web UI. Sending events to the wrong host fails quietly with DNS or TLS errors that look like bugs.

The HEC URL follows the same pattern as your web UI URL but the port and (sometimes) hostname change:

Splunk flavourHEC URL
Splunk Cloud Platformhttps://<stack>.splunkcloud.com:8088/services/collector/event
Splunk Cloud (older Victoria experience)https://http-inputs-<stack>.splunkcloud.com/services/collector/event
Splunk Enterprise (self-hosted)https://<your-host>:8088/services/collector/event

If you're unsure which pattern your stack uses, open the HEC page in Splunk (Settings → Data Inputs → HTTP Event Collector) and click Global Settingsat the top right. The URL hint is on that screen.

Trailing slashes matter. Save the URL exactly as /services/collector/event, no slash after event.

Create a dedicated index

Why: keep Arbiter data isolated from the rest of your Splunk estate so retention, RBAC and dashboards stay tidy. One index per tenant works too if you run several tenants into one Splunk stack.

Top nav → SettingsIndexesNew Index:

  • Index name: arbiter
  • Index Data Type: Events
  • App: Search & Reporting
  • Leave size and retention on defaults; tune later.

Save. The new index appears in the list immediately.

Create the HEC token

Why: the token is the credential Arbiter uses to POST events. One token per tenant is cleanest because rotation, revocation and per-tenant volume tracking all key off the token.

a. Enable HEC if it isn't already

Settings → Data InputsHTTP Event Collector. Top right click Global Settings and set All Tokens to Enabled. On Splunk Cloud HEC is already on, this is a no-op.

b. Issue a new token

Back on the HEC page top right New Token:

  • Name: arbiter
  • Description: Arbiter SIEM egress
  • Source name override: leave blank.

Click Next. On the Input Settings page:

  • Source type: select New and enter arbiter:security_event (one underscore-free colon-separated string; Splunk treats it as one token).
  • App context: leave on Search & Reporting.
  • Select Allowed Indexes: tick arbiter.
  • Default Index: arbiter.

Click Review Submit. The token value appears once, formatted like 1a2b3c4d-5e6f-7890-abcd-ef1234567890. Copy it now. If you navigate away without copying, the value is unrecoverable: delete the token and create a new one.

Treat the HEC token like a password. Arbiter encrypts it at rest with AES-256-GCM and never returns it on the wire, but you should still avoid copy-pasting it through chat or email.

Smoke-test the HEC token with curl

Why: proving the token works from a plain shell before you point Arbiter at it eliminates 90% of the things that can go wrong. If curl can't post, Arbiter can't either.

TOKEN=<paste your HEC token here>
curl -k https://<your-stack>.splunkcloud.com:8088/services/collector/event \
  -H "Authorization: Splunk $TOKEN" \
  -d '{"event":"hello from arbiter","sourcetype":"arbiter:security_event","index":"arbiter"}'

Expected response:

{"text":"Success","code":0}

Then in the Splunk search bar (Apps → Search & Reporting), confirm it landed. Set the time picker to Last 15 minutes:

index=arbiter sourcetype=arbiter:security_event earliest=-15m

You should see the "hello from arbiter" event. If you don't, troubleshoot before moving on:

  • DNS error: the http-inputs-prefix may not exist on your stack. Try the URL without the prefix (Step 1, first row).
  • TLS verification error: self-signed cert on a self-hosted Splunk. Add -k to curl for the smoke test; in Arbiter, untick Verify TLS certificate on the target config.
  • "Invalid token": token wasn't pasted in full. HEC tokens are 36 chars (full UUID); confirm with echo -n "$TOKEN" | wc -c.

Configure the SIEM target in Arbiter

Why: the SIEM target row is what tells the Arbiter forwarder where to ship events.

In the Arbiter admin portal, open the tenant you want shipping to Splunk. Switch to the SIEMtab → + Add target.

FieldValue
NameSplunk - auth rejects (free text)
DestinationSplunk HEC
StreamAuth log rejects (or whichever you want)
CadenceEvery minute (default for this stream)
Rate cap (events/h)Pre-filled with the per-stream default; raise it if your Splunk licence is sized for more.
Splunk HEC URLfrom Step 1, ends with /services/collector/event
HEC Tokenfrom Step 3
Verify TLS certificateOn for Splunk Cloud; off only for self-signed lab setups

Save the target, then click the Testpaper-plane icon next to the row. The status flips to OK (green tick) within about 10 seconds on success.

If it stays red, hover the Error icon. The tooltip shows the response from Splunk:

  • 401: token missing or wrong.
  • 403: token correct but disabled, or not allowed to write to this index.
  • 400: payload format issue. Should not happen on this path; if it does, email support.

Test it's working

Why: verify the pipeline end-to-end in two stages before you trust it for production alerting.

a. Canary check (Test button)

In Arbiter, on the SIEM tab, click the paper-plane icon next to the target row. The forwarder posts a single synthetic event matching the stream's schema; the status flips to OK within about 10 seconds.

Confirm it landed in Splunk:

index=arbiter sourcetype=arbiter:security_event earliest=-5m

You should see one event whose body starts "Arbiter SIEM test event...".

b. Real data check

Real events from the tenant start flowing on the next cadence tick. The default for auth_log_rejectsis every 60 seconds, so a failed authentication on your network should be visible within a minute or two:

index=arbiter sourcetype=arbiter:security_event source=arbiter.auth_log_rejects earliest=-15m
| table _time mac_address nas_name auth_method reason auth_policy_name
| sort - _time

If your tenant has any failing auths (blocked MABs, expired certs, default-deny matches), rows appear here. If nothing's appearing, check the Auth log tab in the Arbiter portal first to confirm rejects are actually being produced.

Expected latency

StageTime
Endpoint fails auth, row written to auth_logt + 0 s
Arbiter forwarder picks the row up on next tickt + 0 to 60 s (cadence-dependent)
POST accepted by Splunk HECt + 60 to 70 s
Row queryable from searcht + 60 to 90 s
Canary delivered and real rejects visible in Splunk? You're done. The integration runs unattended from here.

Build dashboards and alerts (optional)

Why: the value of a SIEM over a passive log store is in dashboards and alerts. Starter SPL below.

# Failed-auth rate by hour, useful for a dashboard panel
index=arbiter sourcetype=arbiter:security_event source=arbiter.auth_log_rejects earliest=-7d
| timechart span=1h count

# Top reject reasons over the last 24 hours
index=arbiter sourcetype=arbiter:security_event source=arbiter.auth_log_rejects earliest=-24h
| stats count by reason
| sort - count
| head 10

# Endpoints producing the most rejects (potential misconfig or attack)
index=arbiter sourcetype=arbiter:security_event source=arbiter.auth_log_rejects earliest=-24h
| stats count as attempts, values(reason) as reasons by mac_address
| sort - attempts
| head 20

To turn one of these into an alert, save the search and click Save As → Alert. Set a schedule (e.g. every 5 minutes), a trigger condition (e.g. "Number of Results > 20") and an action (email, webhook, ServiceNow, etc.).

Sample event for context

This is the full shape of an auth-log-reject event as it lands in Splunk:

arbiter_authlog_rejects_sample.json

HEC payload format. The Arbiter event lives under the event key; everything else is HEC metadata.

{
  "event": {
    "time": "2026-05-21T19:39:31.315147Z",
    "event_id": 3637403,
    "tenant_id": 6,
    "mac_address": "b827ebbec2db",
    "user_name": "b827ebbec2db",
    "nas_ip": "192.168.0.21",
    "nas_name": "HOMESW",
    "nas_port": "GigabitEthernet0/1/1",
    "vlan_id": null,
    "ssid": null,
    "ap_mac": null,
    "auth_method": "mab",
    "eap_type": null,
    "reason": "Denied by default policy",
    "policy_name": "Default Deny",
    "auth_policy_name": "Wired MAB",
    "access_profile_name": null,
    "monitor_mode": false,
    "monitor_coerced": false,
    "client_cert_cn": null,
    "client_cert_serial": null,
    "client_cert_issuer": null,
    "client_cert_issuer_org": null,
    "source": "arbiter.auth_log_rejects"
  },
  "time": 1747856371,
  "sourcetype": "arbiter:security_event",
  "source": "arbiter"
}

And a security event:

{
  "event": {
    "time": "2026-05-21T14:30:00.123456Z",
    "event_id": 1042,
    "tenant_id": 6,
    "rule_name": "ssh-on-guest-vlan",
    "severity": "high",
    "mac_address": "aabbccddeeff",
    "nas_ip": "10.0.0.5",
    "nas_port_id": "GigabitEthernet0/1",
    "summary": "SSH (TCP/22) seen from a guest-VLAN endpoint",
    "details": {
      "flow_src": "192.168.30.42",
      "flow_dst_port": 22,
      "flow_proto": "tcp"
    },
    "source": "arbiter.security_events"
  },
  "time": 1747837800,
  "sourcetype": "arbiter:security_event",
  "source": "arbiter"
}

Troubleshooting

"Delivered" in Arbiter but nothing in Splunk search

By far the most common confusion. Arbiter always sends sourcetype=arbiter:security_event regardless of which stream the target is configured for. If you set a different default sourcetype on the HEC token (e.g. arbiter:auth), the payload sourcetype overrides the token default and events land under arbiter:security_event instead. Search for that sourcetype:

index=arbiter sourcetype=arbiter:security_event earliest=-15m

To split streams in Splunk after the fact, filter on the source field inside the event body, e.g. source=arbiter.auth_log_rejects.

DNS error from Arbiter or curl

Splunk Cloud HEC has two URL patterns depending on stack age (see Step 1). If http-inputs-<stack>.splunkcloud.comdoesn't resolve, drop the prefix and use the same hostname as the web UI on port 8088.

TLS verification failure

Self-hosted Splunk often ships with a self-signed cert. The smoke-test curl needs -k; the Arbiter target needs Verify TLS certificate unticked. For production, install a publicly-trusted cert on the HEC port and turn TLS verification back on.

HTTP 401 / 403 from HEC

  • 401 Invalid token: the token in the Authorization header is wrong or truncated. Re-paste the full 36-character UUID into the Arbiter target.
  • 403 Token disabled: the token is disabled in Splunk. Re-enable it from Settings → Data Inputs → HTTP Event Collector.
  • 403 Index not allowed: the token's allowed-index list doesn't include the index it's trying to write to. Edit the token and tick the arbiter index.

Rate cap warning on the target row

If the row shows "Rate cap hit", forwarding is paused for the rest of the rolling-hour window. This is a guardrail against runaway loops, not a Splunk-side issue. Either:

  • Raise the cap on the Arbiter target if your Splunk licence is sized for more.
  • Set the cap to 0 to disable it (no ceiling).
  • Switch the cadence from Real-time to Every minute or Hourly to spread the volume.

Cost and volume

Splunk Cloud charges by ingest GB per day on Workload Pricing tiers and by indexed volume on legacy Ingest Pricing. Self-hosted Enterprise is licensed by daily indexed volume. Either way, the variable that matters is how many MB per day Arbiter pushes:

  • Security events are sparse. A few dozen events per tenant per day at most: negligible cost.
  • Auth log rejects scale with how noisy your network is. The stream filters to result = 'reject' on the Arbiter side, so the typical volume is 5 to 15% of total auth events. Each row is under a kilobyte. A 500-endpoint SME tenant typically ships well under 100 MB per month.
  • Auth log (all) and accounting events are higher volume. The per-target hourly rate cap is the easy way to bound worst-case ingest cost: 30,000 events/hour on auth_log_all at ~500 bytes each is ~360 MB per day per tenant.

If a noisy supplicant or misconfigured NAS pushes volume up, the rate cap surfaces on the Arbiter target row so the operator notices instead of getting a surprise bill.

Need help?

Stuck on a token or want us to look at your Splunk target config? Email support@arbiter.ie with a screenshot of the SIEM tab and the error tooltip. We usually reply same business day.

More guidesIntegrations overview