SIEM Integration: Splunk
This guide connects Splunk to the GrantFlow audit feed with a scripted input: a small script that Splunk runs every minute, which pulls new events and hands them to Splunk as JSON. Create a feed token first; see SIEM Integration.
A packaged add-on is planned
A GrantFlow add-on for Splunk is planned. Until it ships, the scripted input below is the supported way to connect. It uses the same feed, so moving to the add-on later only means carrying over the cursor.
Before you start
You need:
- Splunk Enterprise, or a heavy forwarder that sends to Splunk Cloud. Splunk Cloud itself does not run custom scripted inputs without app vetting.
- Outbound HTTPS from that machine to the GrantFlow API.
- A feed token and the endpoint from Audit & Compliance → SIEM Integration.
- An index for the events, for example
grantflow.
1. Create the app
On the Splunk machine, create an app folder with this layout:
$SPLUNK_HOME/etc/apps/grantflow_feed/
├── bin/
│ ├── grantflow_feed.py
│ └── grantflow_feed.sh
├── default/
│ ├── inputs.conf
│ └── props.conf
└── local/
└── feed-tokenCopy the reference poller to
bin/grantflow_feed.py.Create
bin/grantflow_feed.sh. Replace the endpoint with the one from GrantFlow:sh#!/bin/sh APP_DIR="$(cd "$(dirname "$0")/.." && pwd)" export GRANTFLOW_FEED_URL="https://api.grantflow.cloud/api/v1/audit-feed/events" export GRANTFLOW_FEED_TOKEN="$(cat "$APP_DIR/local/feed-token")" export GRANTFLOW_CURSOR_FILE="$APP_DIR/local/feed.cursor" exec "$SPLUNK_HOME/bin/splunk" cmd python3 "$APP_DIR/bin/grantflow_feed.py"Put the token into
local/feed-token, and make both files readable only by the Splunk user:bashchmod 700 bin/grantflow_feed.sh chmod 600 local/feed-token
2. Configure the input and the sourcetype
default/inputs.conf:
[script://./bin/grantflow_feed.sh]
interval = 60
sourcetype = grantflow:audit
index = grantflow
disabled = 0default/props.conf:
[grantflow:audit]
SHOULD_LINEMERGE = false
LINE_BREAKER = ([\r\n]+)
KV_MODE = json
TIME_PREFIX = "timestamp":"
TIME_FORMAT = %Y-%m-%dT%H:%M:%S.%3QZ
MAX_TIMESTAMP_LOOKAHEAD = 30
TZ = UTC
TRUNCATE = 65536Restart Splunk, or reload the app.
On its first run the input starts at "now". To import history once, add export GRANTFLOW_START_TIME="2026-10-01T00:00:00Z" to grantflow_feed.sh before the first run, and remove it afterwards.
3. Verify
- After a minute or two, the token's card in GrantFlow shows Pulling.
- Search
index=grantflow sourcetype=grantflow:auditand check that events arrive. Events appear about 60 seconds after they happen. - Script errors appear in
index=_internal sourcetype=splunkd ExecProcessor grantflow_feed.
Example searches
Activations approved, by approver:
index=grantflow sourcetype=grantflow:audit action=activation.approve outcome=success
| stats count by actor.upnPrivileged actions from weak sign-ins:
index=grantflow sourcetype=grantflow:audit category=change
(auth.strength=single_factor OR auth.strength=mfa)
| table _time action actor.upn auth.strength auth.methods{}Signs of a stolen feed token:
index=grantflow sourcetype=grantflow:audit
(action=audit_feed_token.new_origin OR action=audit_feed_token.history_requested OR action=audit_feed_token.auth_failed)
| table _time action actor.id details.name details.sourceIp details.countryThe full list of fields is in the event reference.
Troubleshooting
| Symptom | What to check |
|---|---|
| The card stays Never used | The script does not run: check _internal for ExecProcessor errors and the file permissions. |
HTTP 401 in _internal | The token is wrong, revoked or expired. Create a new one and replace local/feed-token. |
HTTP 422 cursor_rejected | Delete local/feed.cursor, set GRANTFLOW_START_TIME to just before the last event you have, run once, then remove it. Splunk may then index some events twice; deduplicate on id. |
| Events appear with the wrong time | Check that props.conf is in place on the machine that parses the data (the heavy forwarder or the indexer). |