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:

text
$SPLUNK_HOME/etc/apps/grantflow_feed/
├── bin/
│   ├── grantflow_feed.py
│   └── grantflow_feed.sh
├── default/
│   ├── inputs.conf
│   └── props.conf
└── local/
    └── feed-token
  1. Copy the reference poller to bin/grantflow_feed.py.

  2. 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"
  3. Put the token into local/feed-token, and make both files readable only by the Splunk user:

    bash
    chmod 700 bin/grantflow_feed.sh
    chmod 600 local/feed-token

2. Configure the input and the sourcetype ​

default/inputs.conf:

ini
[script://./bin/grantflow_feed.sh]
interval = 60
sourcetype = grantflow:audit
index = grantflow
disabled = 0

default/props.conf:

ini
[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 = 65536

Restart 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:audit and 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:

text
index=grantflow sourcetype=grantflow:audit action=activation.approve outcome=success
| stats count by actor.upn

Privileged actions from weak sign-ins:

text
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:

text
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.country

The full list of fields is in the event reference.

Troubleshooting ​

SymptomWhat to check
The card stays Never usedThe script does not run: check _internal for ExecProcessor errors and the file permissions.
HTTP 401 in _internalThe token is wrong, revoked or expired. Create a new one and replace local/feed-token.
HTTP 422 cursor_rejectedDelete 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 timeCheck that props.conf is in place on the machine that parses the data (the heavy forwarder or the indexer).