Splunk Attack Range v5

The Splunk Attack Range is an open source project that lets security teams spin up instrumented cloud environments, simulate adversary behavior, and use the generated telemetry to build and test detections in Splunk. Whether you are a detection engineer tuning rules, a purple team validating coverage, or a developer automating tests, Attack Range gives you a repeatable, cloud-based lab. This post highlights what Attack Range does, how it works, and how to get started - whether you prefer a web UI, a REST API, or the command line.

Check out this short demo video:

What Is Splunk Attack Range?

Splunk Attack Range builds instrumented cloud environments on AWS, Azure, or GCP. You get a small, production-like lab: a Splunk instance, Windows and Linux servers, optional Kali for red-team style testing, Zeek for network visibility, Active Directory–style layouts, and more - all provisioned with Terraform (infrastructure) and Ansible (configuration). The range can simulate attacks (e.g. via Atomic Red Team) against chosen targets; the resulting telemetry (logs, events, network data) is forwarded into Splunk so you can develop, tune, and validate detections in a safe, isolated environment.

In short: build labs → simulate attacks → use the telemetry in Splunk for detection development and testing.

Typical use cases include building new Splunk detection content, testing existing rules, running purple-team exercises, and automating detection tests in CI/CD. Because the lab is created from templates and accessed only over a VPN, you avoid exposing lab systems on the public internet and keep your detection workflow consistent across teams and clouds.

What’s New in v5.0 and How It Works

Docker Compose - First Experience

The recommended way to run Attack Range is Docker Compose. One command starts the API, web app, and (optionally) the CLI - no need to install Python, Ansible, or Terraform locally. Each component has a clear role:

Detection engineers can choose the interface that fits: the UI for ad-hoc builds and sharing, the API for CI/CD and automation, or the CLI for power users and scripting.

A screen shot of a computer AI-generated content may be incorrect.

Two-Phase Build and WireGuard VPN

Attack Range uses a two-phase build so lab machines are never exposed on the public internet:

  1. Phase 1 (VPN): Terraform creates the VPC/subnet and a router instance in the cloud. Ansible configures WireGuard on the router and generates a client config. Status becomes Waiting for VPN (or wait_for_vpn in the API).
  2. You: Download the WireGuard config (from the app or via GET /attack-range/status/<id>), import it into the WireGuard app (Desktop or mobile), and turn the tunnel on.
  3. Phase 2 (Lab): You continue the build—in the app (e.g. Continue build), via a second API call with attack_range_id, or by answering the CLI prompt. Ansible is provisioning Splunk, Windows, Kali, Zeek, etc. Status becomes running.

Lab hosts get private IPs (e.g. in 10.0.2.x); only the VPN router has a public IP. Access is VPN-only: you must be connected with a valid WireGuard client to reach Splunk, RDP, SSH, or Guacamole.

Multi-Cloud: AWS, Azure, and GCP

Attack Range supports AWS, Azure, and GCP. The same concepts apply everywhere: pick a template (e.g. aws/splunk_minimal_aws, azure/splunk_windows_azure, gcp/splunk_ad_gcp), start the build, connect to the VPN, and continue. Credentials are mounted from your host into the Docker stack: AWS uses ~/.aws (e.g. aws configure), Azure uses ~/.azure (e.g. az login), GCP uses ~/.config/gcloud (e.g. gcloud auth login). The API provides GET /providers/check to see which provider CLIs and credentials are available, which is useful when driving the stack from scripts or the CLI.

Each range has a config file in config/<attack_range_id>.yml created from the template at build start; it includes the provider block (e.g. aws.region, azure.location, gcp settings), general settings (passwords, IP whitelist, description), and the list of servers with instance types and Ansible roles. The app and API manage these configs; do not edit them manually to avoid out-of-sync state or failed operations.

A diagram of a computer server AI-generated content may be incorrect.

Templates for Every Use Case

Templates are YAML files under templates/aws/, templates/azure/, and templates/gcp/. They define the layout of a range: general settings, provider block, and the list of servers (name, instance type, IP octet, Linux/Windows, user, and roles). You reference a template by provider + name (e.g. aws/splunk_minimal_aws), by name only (searched across providers), or with the `.yml` extension.

You can create a custom template by copying an existing file (e.g. splunk_windows_aws.yml), editing the general and attack_range sections (add/remove servers, change instance types, adjust roles and vars), and building from it (e.g. aws/my_custom_template). Do not set attack_range_id or status in the template—those are set when a range is created. The API offers GET /templates to list all templates and GET /templates/<provider>/<name> to fetch the full content.

A screenshot of a computer AI-generated content may be incorrect.

Simulate and Build Detections

Once a range is running, you can simulate attacks (e.g. Atomic Red Team techniques) against a target server. You specify the attack range ID, the target server name (as in the template), and a comma-separated list of technique IDs.

The simulation runs the selected techniques on the target host; the resulting telemetry flows into Splunk so you can build, tune, and validate detections. Config can be a path or an attack range ID (e.g. the UUID); if omitted and there is exactly one `*.yml` in `config/`, that config is used.

A screenshot of a computer AI-generated content may be incorrect.

Share Access with Your Team

You can give others access to the same range by generating additional WireGuard client configs. The VPN supports multiple peers: the first (client1) is created at build time; sharing adds a new peer (e.g. alice). The backend generates a new key pair and WireGuard config, updates the router via the VPN playbooks, and stores the config in the range’s YAML under general.sharing.<name> (and returns it in the API response).

You can share when the range is in running. In the app, open the range, use the Share action, and enter a name; the app shows or downloads the new config. Via API: POST /attack-range/share with {"attack_range_id": "<id>", "name": "alice"}; the response includes the new client config. Via CLI: attack_range share -n alice (and -c <attack_range_id_or_path> if you have multiple configs). Send the config and the same credentials (Splunk, RDP, SSH) to the other person over a secure channel; they import the config into WireGuard and connect. Multiple users can be connected at once. Revocation of a single user is not automated; to revoke someone you would need to remove their peer from the WireGuard server or destroy and rebuild the range.

Use Any Ansible Galaxy Role

Templates define which Ansible roles run on each server. Attack Range installs every role you list (via ansible-galaxy install) and runs them at build time in the order specified. You can use any Ansible Galaxy role - not only the ones shipped with Attack Range. Use the Galaxy role name as on Ansible Galaxy (e.g. namespace.role_name like P4T12ICK.ludus_ar_splunk or geerlingguy.nginx). In the template you can list a role as a string or as a dict with role and optional vars (and inventory_name if the role expects a specific host group). Example:

A screenshot of a computer AI-generated content may be incorrect.

To add a custom Splunk app, monitoring, or security tool: copy a template, add the Galaxy role to the right server’s roles list (with vars if needed), save, and build from that template. No Attack Range code changes are required; the controller scans the config for all role names and runs ansible-galaxy install for each before executing the generated lab playbook.

Summary

Splunk Attack Range gives security teams a consistent way to:

Feedback

Any feedback or requests? Feel free to put in an issue on GitHub and we’ll follow up. Alternatively, join us on the Slack channel #security-research.

Contributors

We would like to thank Patrick Bareiss for authoring this post and the entire Splunk Threat Research Team for their contributions.

Related Articles

Unknown and unseen, the cyberwar between Crimsonia and Berylia
Security
3 Minute Read

Unknown and unseen, the cyberwar between Crimsonia and Berylia

First week of December, unbeknown to many the island of Berylia engaged in cyberwarfare with their neighbors Crimsonia after a number of months of heightened tensions. The goal of the Berylian attackers was to disable as many critical infrastructure components of the Crimsonian Ministry of Defense in order to prevent the Crimsonian Navy from sailing. This would give the Berylian fleet the time to aid and protect critical locations and assets.
UEBA Superpowers: Enhance Security Visibility with Rich Insights to Take Rapid Action Against Threats
Security
4 Minute Read

UEBA Superpowers: Enhance Security Visibility with Rich Insights to Take Rapid Action Against Threats

Splunk UBA illuminates hidden corners of your org's digital ecosystem, providing unparalleled visibility into behaviors and patterns that define the network's pulse.
Detect Money Laundering, Healthcare Fraud, and Unemployment Fraud with the New Version of the Splunk App for Fraud Analytics
Security
4 Minute Read

Detect Money Laundering, Healthcare Fraud, and Unemployment Fraud with the New Version of the Splunk App for Fraud Analytics

Detect money laundering, healthcare fraud, and unemployment fraud with Splunk App Fraud Analytics 1.2.4.