Submit a ticket My Tickets
Welcome
Login  Sign up

PowerDMARC and Splunk - Integration Guide

PowerDMARC and Splunk Integration Guide

PowerDMARC → Solution home → Integrations → SIEM

With PowerDMARC's Splunk integration, you can ingest and monitor your email authentication and domain security data directly within your Splunk environment. By leveraging the PowerDMARC API, organizations can build a streamlined SIEM integration without complex configurations — connect, run, and gain centralized visibility into their email security posture across all domains.

This guide focuses on setup and ingestion. Splunk dashboards and advanced visualizations are out of scope.

API Documentation

  • Swagger Documentation: https://app.powerdmarc.com/swagger-ui/index.html

  • Alternative Documentation: https://api.powerdmarc.com/

Note: Naming conventions (index names, sourcetypes, file paths) are suggestions, not requirements. Adjust them to match your environment's standards.

What the Script Collects

The integration script pulls two data sets from the PowerDMARC API:

Data set

API endpoint

Sourcetype

Audit logs

/api/v1/audit-logs

dmarc:audit

DMARC aggregate reports (per sending source)

/api/v1/reports/aggregate/per-sending-source

dmarc:aggregate


Aggregate reports are collected for every domain in your account, across the compliantfailed, and forwarded statuses. Domains are enumerated automatically via /api/v1/domains.

Architecture Overview

PowerDMARC API

      ↓

Python script (scheduled via cron / systemd timer / Task Scheduler)

      ↓

Splunk HTTP Event Collector (HEC)

      ↓

Splunk (search, dashboards, alerts, correlation)

Splunk receives data through its HTTP Event Collector (HEC) endpoint, which allows secure data ingestion from external sources.

The script also supports writing newline-delimited JSON files instead of — or in addition to — HEC, for environments where outbound HTTPS to the Splunk HEC port isn't permitted. See Alternative: File Monitor Ingestion.

Prerequisites

  • Splunk Enterprise or Splunk Cloud with administrative access

  • Permission to create HEC tokens, create indexes, and configure data inputs

  • Python 3.7 or later on the system running the script

  • A PowerDMARC API bearer token with permission to access audit logs and aggregate reports

  • Network connectivity from the script host to:

    • PowerDMARC API — https://app.powerdmarc.com (TCP 443)

    • Your Splunk HEC endpoint (TCP 8088 for Splunk Enterprise, TCP 443 for Splunk Cloud)


Splunk Configuration


Step 1: Create a Dedicated Index

  1. Navigate to Settings → Indexes

  2. Click New Index

  3. Configure:

    • Index Name: powerdmarc

    • Index Data Type: Events

    • App: search (or your preferred app)

    • Leave other settings at their defaults, or adjust for your retention requirements

  4. Click Save

Step 2: Enable HTTP Event Collector (HEC)

  1. Navigate to Settings → Data inputs

  2. Click HTTP Event Collector

  3. Click Global Settings

  4. Configure:

    • All Tokens: Enabled

    • Enable SSL: Enabled (recommended)

    • HTTP Port Number: 8088 (default)

  5. Click Save

Splunk Cloud customers: HEC is enabled by default and listens on port 443. You do not need to change global settings, but you may need to file a support request to enable HEC on some stack types.

Step 3: Create the HEC Token

  1. Still in Settings → Data inputs → HTTP Event Collector, click New Token

  2. Configure token settings:

    • Name: PowerDMARC_Integration

    • Source name override: powerdmarc:api

    • Description: Token for PowerDMARC audit log and aggregate report ingestion

  3. Click Next

  4. Input settings:

    • Source type: Select Automatic

    • Allowed Indexes: include powerdmarc

    • Default Index: powerdmarc

  5. Click Review, then Submit

Important: Copy and save the token value immediately — you cannot retrieve it later.

Why "Automatic" matters: the script sets a per-event sourcetype (dmarc:audit or dmarc:aggregate) in the HEC payload. Selecting a fixed sourcetype on the token would override those values and merge both data sets into one sourcetype.


Integration Script Setup


Step 4: Prepare the Python Environment

The script has a single third-party dependency: requests.

Option A — Online installation (recommended)

pip3 install requests


Option B — Offline installation

On a machine with internet access:

pip3 download requests -d ./packages

Transfer the packages folder to the target system, then: 

pip3 install --no-index --find-links=./packages requests

Verify the installation:

python3 -c "import requests; print(requests.__version__)"

Any reasonably current version (2.25 or later) is fine.

Step 5: Deploy the Script

Create a dedicated service account and directory structure rather than running the integration as root:

sudo useradd -r -s /usr/sbin/nologin dmarc

sudo mkdir -p /opt/dmarc /etc/dmarc /var/lib/dmarc /var/log/dmarc

sudo chown dmarc:dmarc /var/lib/dmarc /var/log/dmarc

sudo chmod 750 /var/lib/dmarc /var/log/dmarc

Copy dmarc_to_splunk.py into place:

sudo install -o dmarc -g dmarc -m 750 dmarc_to_splunk.py /opt/dmarc/


Step 6: Configure the Script

Every setting can be supplied either by editing the config dictionary in main() or by setting an environment variable. Environment variables are strongly recommended so that credentials never live inside the script file.

Environment variable

Config key

Default

Purpose

DMARC_API_KEY

dmarc_api_key

(none — required)

PowerDMARC API bearer token

DMARC_DAYS_TO_FETCH

days_to_fetch

7

Lookback window in days

DMARC_OUTPUT_MODE

output_mode

hec

hecfile, or both

SPLUNK_HEC_URL

splunk_hec_url

(placeholder)

Full HEC event endpoint URL

SPLUNK_HEC_TOKEN

splunk_hec_token

(none — required for HEC)

HEC token from Step 3

SPLUNK_INDEX

splunk_index

powerdmarc

Target index

SPLUNK_SOURCE

splunk_source

powerdmarc:api

Value for the event source field

SPLUNK_VERIFY_SSL

splunk_verify_ssl

true

TLS certificate verification

SPLUNK_BATCH_SIZE

splunk_batch_size

500

Events per HEC POST

DMARC_OUTPUT_DIR

output_dir

/var/log/dmarc

JSON output directory (file/both modes)

DMARC_STATE_FILE

state_file

/var/lib/dmarc/state.json

Deduplication state


HEC endpoint URL formats:

  • Splunk Enterprise / on-premises: https://your-splunk-instance:8088/services/collector/event

  • Splunk Cloud: https://http-inputs-<your-stack>.splunkcloud.com/services/collector/event

Splunk Cloud hostnames vary by stack age and type — some use http-inputs-<stack>.splunkcloud.com on port 443, others use a .splunkcloud.com:8088 form. Confirm yours under Settings → Data inputs → HTTP Event Collector in your Splunk Cloud console rather than assuming.

Create the credentials file:

sudo tee /etc/dmarc/splunk.env >/dev/null <<'EOF'

DMARC_API_KEY=your_powerdmarc_bearer_token

SPLUNK_HEC_URL=https://your-splunk-instance:8088/services/collector/event

SPLUNK_HEC_TOKEN=your_hec_token

SPLUNK_INDEX=powerdmarc

DMARC_DAYS_TO_FETCH=7

EOF


sudo chown root:dmarc /etc/dmarc/splunk.env

sudo chmod 640 /etc/dmarc/splunk.env

Step 7: Test Connectivity

The script accepts a --test flag that sends a single probe event to HEC and exits. This validates the token, URL, TLS chain, and firewall path without waiting for a full collection run:

sudo -u dmarc bash -c 'set -a; . /etc/dmarc/splunk.env; set +a; python3 /opt/dmarc/dmarc_to_splunk.py --test'

Expected output:

============================================================

PowerDMARC to Splunk Integration

Output mode: hec

============================================================

Testing Splunk HEC connectivity...

Sent batch of 1 dmarc:audit events (1/1)

HEC summary for dmarc:audit — sent: 1, failed: 0, total: 1

Confirm the probe arrived:

index=powerdmarc action="integration_connectivity_test"

Step 8: Run a Full Collection

sudo -u dmarc bash -c 'set -a; . /etc/dmarc/splunk.env; set +a; python3 /opt/dmarc/dmarc_to_splunk.py'

Expected output (abbreviated):

============================================================

PowerDMARC to Splunk Integration

Output mode: hec

============================================================

Processing DMARC aggregate reports...

Fetching aggregate reports from 2026-01-30 to 2026-02-06

Fetching all domains...

Fetched page 1: 24 domains (total so far: 24)

Fetched 24 total domains

Progress: 1.4% (1/72) | Domain 1/24: example.com | ETA: 4.7 min remaining

...

Processed 318 unique aggregate report events

Sent batch of 318 dmarc:aggregate events (318/318)

HEC summary for dmarc:aggregate — sent: 318, failed: 0, total: 318

Processing audit logs...

Fetching audit logs from 2026-01-30 to 2026-02-06

Fetched 15 total audit log entries

Processed 15 unique audit log events from last 7 days

HEC summary for dmarc:audit — sent: 15, failed: 0, total: 15

============================================================

Integration completed successfully

============================================================

The first run will be the longest, since it collects the full lookback window. Subsequent runs skip anything already ingested (see Deduplication).


Schedule Automated Execution

Linux/Unix (cron)

sudo crontab -u dmarc -e

Hourly:

0 * * * * set -a; . /etc/dmarc/splunk.env; set +a; /usr/bin/python3 /opt/dmarc/dmarc_to_splunk.py >> /var/log/dmarc/run.log 2>&1

The script logs to standard output, so the redirect above is what captures the run log. Add a logrotate rule for /var/log/dmarc/run.log in production.

Sizing the interval. The script paces itself at roughly 2 seconds between API calls to stay inside PowerDMARC's rate limit, and it makes three aggregate requests per domain. A rough estimate of aggregate collection time is domains × 3 × 4 seconds — about 5 minutes for 25 domains, but nearly 2 hours for 500. If your account has more than ~100 domains, an hourly schedule will overlap itself. Either:

  • Split the schedule — run audit log collection hourly and aggregate collection once daily, or

  • Add a lock file (flock) so overlapping runs exit cleanly:

0 * * * * /usr/bin/flock -n /tmp/dmarc-splunk.lock -c 'set -a; . /etc/dmarc/splunk.env; set +a; /usr/bin/python3 /opt/dmarc/dmarc_to_splunk.py' >> /var/log/dmarc/run.log 2>&1


Linux (systemd timer)

A systemd timer is generally preferable to cron for this workload — it handles the environment file natively, prevents overlapping runs, and sends output to the journal.

/etc/systemd/system/dmarc-splunk.service:

[Unit]

Description=PowerDMARC to Splunk ingestion

After=network-online.target


[Service]

Type=oneshot

User=dmarc

Group=dmarc

EnvironmentFile=/etc/dmarc/splunk.env

ExecStart=/usr/bin/python3 /opt/dmarc/dmarc_to_splunk.py

/etc/systemd/system/dmarc-splunk.timer:

[Unit]

Description=Run PowerDMARC to Splunk ingestion hourly


[Timer]

OnCalendar=hourly

Persistent=true


[Install]

WantedBy=timers.target

Enable it:

sudo systemctl daemon-reload

sudo systemctl enable --now dmarc-splunk.timer

sudo systemctl list-timers dmarc-splunk.timer

journalctl -u dmarc-splunk.service -f

Windows (Task Scheduler)

  1. Open Task Scheduler and click Create Task

  2. General tab:

    • Name: PowerDMARC Splunk Integration

    • Security options: Run whether user is logged on or not

  3. Triggers tab: New → Begin: On a schedule → Daily, repeat every 1 hour

  4. Actions tab: New → Start a program

    • Program: python.exe

    • Arguments: C:\dmarc\dmarc_to_splunk.py

  5. Click OK

On Windows, set the configuration values in the config dictionary directly or define the environment variables at the machine level, and change output_dir / state_file to Windows paths such as C:\dmarc\logs and C:\dmarc\state\state.json.


Validate Data Ingestion in Splunk

Audit logs

index=powerdmarc sourcetype=dmarc:audit

| sort - _time

| head 20

| table _time, user_name, action, ip_address, admin_username

Fields you should see:

  • user_name — user who performed the action

  • action — description of the action performed

  • ip_address — IP address of the user

  • admin_username — administrator account, where applicable

  • timestamp — original PowerDMARC event time

Aggregate reports

index=powerdmarc sourcetype=dmarc:aggregate

| stats sum(email_volume) as volume, avg(dmarc_pass_percentage) as avg_pass by domain_name

| sort - volume

Aggregate events carry per-domain, per-sending-source counts and percentages for DMARC, SPF, and DKIM, plus the policy actually applied.

Sample event structures

dmarc:audit

{

  "sourcetype""dmarc:audit",

  "timestamp""2026-02-04 14:29:24",

  "user_name""John Doe",

  "action""Updated attached domains",

  "ip_address""12.111.67.123",

  "admin_username""N/A",

  "other_info""N/A"

}

dmarc:aggregate (abbreviated)

{

  "sourcetype""dmarc:aggregate",

  "timestamp""2026-02-06",

  "report_date_from""2026-01-30",

  "report_date_to""2026-02-06",

  "domain_id"1234,

  "domain_name""example.com",

  "sending_source""Google",

  "status""compliant",

  "email_volume"4821,

  "dmarc_pass_count"4810,

  "dmarc_pass_percentage"99.77,

  "spf_align_percentage"99.77,

  "dkim_align_percentage"100.0

}

Event timestamps

The script sets the HEC time field from each event's own timestamp where it can parse one, so _time reflects when the event occurred rather than when it was ingested. This matters on the first run: without it, a seven-day backfill would land entirely in the current minute and look wrong in every time-series panel.


Deduplication

The script maintains a state file (default /var/lib/dmarc/state.json) containing SHA-256 fingerprints of every event already delivered. On each run, events matching a stored fingerprint are skipped. Fingerprints older than 14 days are pruned automatically to keep the file from growing without bound.

Fingerprints are only committed after delivery succeeds, so a failed HEC POST leaves those events eligible for retry on the next run rather than silently dropping them.

Two operational consequences:

  • The state file must persist across runs and reboots. Don't place it in /tmp or inside a container layer that gets discarded.

  • Deleting the state file causes the next run to re-ingest the full lookback window. That's the correct way to force a backfill, but expect duplicates in Splunk if the data is already there.


Alternative: File Monitor Ingestion

If outbound access to the HEC port isn't available, set DMARC_OUTPUT_MODE=file (or both). The script writes newline-delimited JSON to output_dir, one file per run per data set:

/var/log/dmarc/dmarc_aggregate_20260206_140312.json

/var/log/dmarc/audit_logs_20260206_140312.json

Configure a Splunk forwarder to monitor that directory. In $SPLUNK_HOME/etc/system/local/inputs.conf:

[monitor:///var/log/dmarc/dmarc_aggregate_*.json]

disabled = false

index = powerdmarc

sourcetype = dmarc:aggregate


[monitor:///var/log/dmarc/audit_logs_*.json]

disabled = false

index = powerdmarc

sourcetype = dmarc:audit

And in props.conf, so that events are split per line and timestamped correctly:

[dmarc:aggregate]

INDEXED_EXTRACTIONS = json

KV_MODE = none

SHOULD_LINEMERGE = false

TIME_PREFIX = "report_date_to":\s*"

TIME_FORMAT = %Y-%m-%d


[dmarc:audit]

INDEXED_EXTRACTIONS = json

KV_MODE = none

SHOULD_LINEMERGE = false

TIME_PREFIX = "timestamp":\s*"

TIME_FORMAT = %Y-%m-%d %H:%M:%S

The Splunk user needs read access to the directory — add it to the dmarc group, or relax the directory mode to 0755. Add a cleanup job (find /var/log/dmarc -name '*.json' -mtime +7 -delete) so old output files don't accumulate.


Troubleshooting

No data appearing in Splunk

  • Run with --test first to isolate whether the problem is HEC or the PowerDMARC side

  • Verify the HEC token is correct and enabled (Settings → Data inputs → HTTP Event Collector)

  • Confirm the token's allowed indexes include powerdmarc

  • Check that the index exists and your role has access to search it

  • Verify firewall rules permit outbound HTTPS from the script host to the HEC endpoint

  • Review the run log for HEC returned HTTP … lines — Splunk's error body names the specific problem

HTTP 403 "Invalid token" from HEC

The token value is wrong, disabled, or belongs to a different Splunk stack. Note that the header format is Authorization: Splunk <token> — not Bearer.

HTTP 400 "Incorrect index"

The token doesn't permit the index the script is targeting. Either add powerdmarc to the token's allowed index list, or change SPLUNK_INDEX to an index the token already allows.

SSL certificate errors

Install a certificate trusted by the script host — this is the correct fix. As a temporary measure in non-production environments only, set SPLUNK_VERIFY_SSL=false. Never do this in production; it disables the protection that makes HEC over TLS meaningful.

PowerDMARC API authentication failures

  • Verify the API token is valid and hasn't expired

  • Confirm the token has permission for both audit logs and aggregate reports

  • Confirm the API base URL is reachable from the host

Script runs but no logs fetched

  • Check whether audit logs actually exist for the lookback period

  • Increase DMARC_DAYS_TO_FETCH temporarily

  • Remember that deduplication suppresses previously ingested events — a run reporting Processed 0 unique audit log events after a successful earlier run is normal, not a fault

Permission denied on startup

The service account can't create or write /var/lib/dmarc or /var/log/dmarc. Pre-create both directories and chown them to the account the script runs as, as shown in Step 5.

Run takes longer than the schedule interval

See the sizing note under Schedule Automated Execution. Add flock or split the collection schedule.


Next Steps

With data flowing, you can:

  • Build custom dashboards for DMARC compliance trending by domain and sending source

  • Alert on audit events such as policy changes or logins from unexpected IP ranges

  • Alert on compliance regressions — a sending source whose dmarc_pass_percentage drops sharply week over week

  • Correlate PowerDMARC data with other security logs (mail gateway, identity, EDR)

  • Build compliance and executive reporting from the aggregate data set

Recommended Enhancements

  • Additional API endpoints: extend the script to fetch forensic reports or per-domain configuration data

  • Log rotation: add a logrotate rule for the script's run log in production

  • Failure notifications: wrap the script in a call that alerts on a non-zero exit status, or alert in Splunk on absence of the expected hourly event volume

  • Package as a Splunk TA: bundle the inputs, props, and index-time configuration as a Technology Add-on for easier distribution

  • Secrets management: replace the environment file with a secrets manager (Vault, AWS Secrets Manager, systemd credentials) where one is available

Security Considerations

  • Store credentials outside the script. Use the environment file (mode 640, owned root:dmarc) or a secrets manager. Never commit tokens to version control.

  • Keep TLS verification enabled. SPLUNK_VERIFY_SSL defaults to true for a reason.

  • Run as a dedicated unprivileged account. The integration needs no root privileges.

  • Restrict the HEC token. Limit it to the powerdmarc index only.

  • Rotate both tokens on a schedule — the PowerDMARC bearer token and the Splunk HEC token.

  • Monitor execution. Alert on failed runs and on unexpected gaps in ingestion.

  • Review Splunk access controls. Audit log data identifies users and source IPs; restrict the index to roles that need it.

Support and Resources

  • PowerDMARC API documentation: https://api.powerdmarc.com/

  • Splunk HEC documentation: https://docs.splunk.com/Documentation/Splunk/latest/Data/UsetheHTTPEventCollector

  • Splunk Answers: https://community.splunk.com/



Did you find it helpful? Yes No

Send feedback
Sorry we couldn't be helpful. Help us improve this article with your feedback.