Getting Started
This guide gets you running Attack Range using Docker Compose (recommended), then explains the web app, API, and CLI.
Prerequisites
Docker and Docker Compose installed.
A cloud account and CLI configured for one of: AWS, Azure, or GCP.
Credentials on the host so the containers can use them:
AWS:
~/.aws(e.g.aws configure)Azure:
~/.azure(e.g.az login)GCP:
~/.config/gcloud(e.g.gcloud auth login)
Running with Docker Compose (recommended)
Docker Compose runs the API, web app, and (optionally) the CLI without installing Python, Ansible, or Terraform on your machine.
Start the stack:
cd attack_range_2 docker compose -f docker/docker-compose.yml up
This starts:
API on port 4000
Web app on port 4321
Open the web app: http://localhost:4321
Build your first range:
Choose a template (e.g. aws/splunk_minimal_aws).
Click build. The backend runs Phase 1 (VPN infrastructure).
When status is Waiting for VPN, download the WireGuard client config.
Connect to the VPN using WireGuard (Desktop or mobile).
Click Continue build to run Phase 2 (lab: Splunk, Windows, etc.).
Optional — CLI in Docker:
docker compose --profile cli -f docker/docker-compose.yml run --rm attack_range build -t aws/splunk_minimal_aws
The CLI will prompt you to connect to the VPN, then continue the lab build. Other commands:
destroy,simulate,share(see Configuration and CLI sections below).
Using the Web App
Build: Select a template and start build; when status is Waiting for VPN, download the WireGuard config, connect, then continue.
List / status: See all ranges and their status (building, running, error).
Destroy: Tear down a range by its Attack Range ID.
Simulate: Run Atomic Red Team techniques against a server in a running range (attack range ID, target server, technique list).
Share: Generate a new WireGuard config for a named user; config is saved and shown for sharing.
The app talks to the API at http://localhost:4000 (or PUBLIC_API_URL in Docker).
Using the API
The REST API runs on port 4000 and provides:
Health:
GET /healthBuild (two-phase):
POST /attack-range/buildwithtemplate(phase 1) orattack_range_id(phase 2 after VPN).Status:
GET /attack-range/status/<attack_range_id>List:
GET /attack-range/listDestroy:
POST /attack-range/destroywithattack_range_idSimulate:
POST /attack-range/simulatewithattack_range_id,target,techniquesShare:
POST /attack-range/sharewithattack_range_id,nameTemplates:
GET /templates,GET /templates/<provider>/<name>Configs:
GET /configs,GET /configs/<config_id>Providers:
GET /providers/check(CLI/credentials availability)
Interactive API docs:
Swagger UI: http://localhost:4000/openapi/swagger
OpenAPI JSON: http://localhost:4000/openapi/openapi.json
All build/destroy operations are asynchronous: you get an attack_range_id and poll the status endpoint until the range is running or error.
Using the CLI
You can run the CLI:
Inside Docker (recommended):
docker compose --profile cli -f docker/docker-compose.yml run --rm attack_range <action> [options]Locally: from the project root,
python attack_range.py <action> [options](requires Python, Ansible, Terraform, and cloud CLI on the host).
CLI actions
build — Build from a template (two-phase: VPN then lab; CLI prompts for VPN connection).
python attack_range.py build -t aws/splunk_minimal_awsTemplate can be
provider/nameorname(searched intemplates/).
destroy — Tear down a range.
python attack_range.py destroyWith a single config in
config/, that config is used. Otherwise:python attack_range.py destroy -c <config_path_or_id>.
simulate — Run Atomic Red Team techniques on a target server.
python attack_range.py simulate -t <target_server_name> -te T1003.001,T1059.003 [-c config]
share — Generate a new WireGuard client config for sharing.
python attack_range.py share -n alice [-c config]
Config can be a path or an attack range ID (e.g. uuid.yml in config/). If omitted and there is exactly one *.yml in config/, it is used.
Two-phase build (VPN then lab)
Attack Range uses a two-phase build so the lab is only reachable over VPN:
Phase 1 (VPN): Terraform creates the network and a router; Ansible configures WireGuard on the router and generates a client config. Status becomes wait_for_vpn.
You: Download the WireGuard config, connect with the WireGuard client.
Phase 2 (Lab): You trigger the continuation (in the app or with a second API call or by answering the CLI prompt). Ansible provisions Splunk, Windows, Kali, etc. over the VPN. Status becomes running.
This keeps lab IPs (e.g. 10.0.2.x) off the public internet.
Next steps
Configuration — Config file layout, providers, and options.
Networking — WireGuard, VPN, and connectivity.
Sharing — Sharing access with others.
Templates — Available templates and structure.
Ansible Roles — Roles used for install and simulation.