-
Notifications
You must be signed in to change notification settings - Fork 14
Deploying a Range
You deploy the export from your own machine, under your own credentials. redStackPRO is not in the loop once you press Download.
Caution
Deploying creates real, billed resources in your own cloud account: VMs, storage, a public IP or two, and the rest. Nothing in this pipeline stops the clock for you. Tear the range down when you are done (see Teardown below), and check your cloud console if a build ever fails partway through.
On AWS, scope your quotas for the target region before the first apply. A compile does not check them, and a shortfall surfaces mid-apply, after instances are up, leaving partial infrastructure to destroy. Each item is per region, so a new region means re-checking.
- Elastic IPs: the default is 5 per region. A defense/AD range uses about 2, an offense range about 3, so the default holds only one or two concurrent ranges. Request an increase in advance.
- vCPUs: a large AD range (for example full GOAD plus a SIEM) can exceed the default running On-Demand vCPU limit. Raise it before large deploys.
- Kali: a Kali operator needs a one-time Marketplace subscription on the account, per region. redStackPRO touches no account, so you subscribe once per region.
- Key pair name: it is region-global and defaults to
<prefix>-key, so keep the topology prefix unique per range to avoid a collision.
See Providers for the quota table and the increase commands.
An SSH key pair is two matching files: a private half you keep and a public half you can hand out. The deploy authenticates to the hosts with the private half, and the public half is written into each host at creation, so make the pair before the first apply.
Run this from the export's root folder, the one holding deploy.sh and keys/
(the command below creates keys/id_ed25519 and keys/id_ed25519.pub there):
macOS, Linux, or Git Bash on Windows:
ssh-keygen -t ed25519 -f keys/id_ed25519 -N ""
Windows PowerShell (the quoting differs):
ssh-keygen -t ed25519 -f keys\id_ed25519 -N ''
keys/ sits beside the export's README. Already have a key? Point at it with
REDSTACKPRO_SSH_KEY=/path/to/key.
terraform.tfvars is a plain text file, one setting per line as name = "value"
(or name = ["value"] for a list). Open export/terraform/terraform.tfvars and set:
-
ssh_public_key: the single line fromkeys/id_ed25519.pub. -
operator_source_ranges: the addresses you connect from, each as a/32. A CIDR like203.0.113.7/32means exactly that one address; find yours withcurl ifconfig.meor by searching "what is my ip".[!CAUTION] The shipped default is
["0.0.0.0/0"], meaning anyone on the internet. This variable gates management access (SSH, RDP, the Guacamole portal) next to a deliberately vulnerable range, so narrow it to your own/32(or your team's known ranges) before you apply. Leaving it open is the single easiest way to hand your range to someone else. -
region(AWS) orprojectandregion(GCP), plus any topology-specific inputs the briefing names. A region is the cloud's data center location (for exampleus-east-1on AWS,us-east4on GCP); pick one close to you or your target. A GCP project is the billing and resource container every GCP resource lives in; if you do not have one yet, see Providers for how to create one and enable billing.
Authenticate to your cloud first: aws configure, then aws sts get-caller-identity,
or gcloud auth application-default login. For the full auth steps and the
permissions your identity needs, see Cloud Prerequisites.
An attack-infrastructure jumpbox names its team directly. Two overlay fields control it, both optional:
-
operators: a list of{handle, role}entries, one per teammate. Each handle is unique and lowercase. Every operator gets a Guacamole portal login (the handle as the username, on the shared lab password), regardless of access mode. -
access_mode:public(default),wireguard, oropenvpn.vpn_portdefaults to 51820 for WireGuard or 1194 for OpenVPN, andvpn_protocolisudportcp(WireGuard is udp only; OpenVPN can run tcp/443 to get through a restrictive network).
On a VPN access mode, apply also generates each operator a personal client
credential on the jumpbox itself: a WireGuard .conf or an OpenVPN .ovpn.
The keys are generated on the jumpbox and never leave it or enter the export,
only the client config file does. Each lands at
/opt/redstackpro/vpn/<handle>.conf (or .ovpn) on the jumpbox, owned by the
platform account, so you fetch it yourself over your own ssh session:
scp -i keys/id_ed25519 admin@<jumpbox-ip>:/opt/redstackpro/vpn/<handle>.conf .
Firewall posture changes with the access mode:
-
public(default): both ssh (22) and the Guacamole portal (443) stay open tooperator_source_ranges, same as today. -
wireguardoropenvpn: ssh (22) stays open tooperator_source_rangesso the admin can keep deploying and managing the box, the public portal (443) closes to the internet and is reached instead over the tunnel at the jumpbox's private/tunnel address, and the VPN listen port opens tooperator_source_rangesin its place. The jumpbox keeps the same public IP either way; it is the VPN endpoint too.
ARTIE-BRIEFING.md in the export gets an "Operators & VPN access" section
listing the endpoint (jumpbox public IP plus port and protocol), each
operator's portal account, and the path to their credential file, with the
scp line to fetch it.
Add or remove a teammate on a running jumpbox without a redeploy:
sudo rsp-operator add <handle> [role]
sudo rsp-operator remove <handle>
sudo rsp-operator list
rsp-operator generates or revokes the VPN credential and the portal account,
and keeps a durable roster at /opt/redstackpro/vpn/operators.json, so an
operator added this way survives the next redeploy.
A HAVEN range ignores all of this: operators, access_mode, and the rest
are attack-infrastructure-only fields, and a defense range keeps the plain
public portal.
The generated terraform/versions.tf declares only required_version and
required_providers, no backend block, on both GCP and AWS. That means Terraform
keeps local state: a terraform.tfstate file inside the export's own terraform/
folder, on your machine. There is no remote backend and no state locking, so this is
a single operator workflow. Do not run terraform apply against the same export from
two machines at once, and never commit terraform.tfstate (it can hold values that
should stay private).
If you deploy redStack (attack infrastructure) and a range as two separate exports,
each gets its own terraform/ folder and its own state file: two independent
deploys, and two independent teardowns. See Teardown below.
Windows PowerShell, from the export folder:
.\deploy.ps1
macOS, Linux, or Git Bash:
bash deploy.sh
On Windows, do not run bash deploy.sh at a PowerShell prompt: that bash is the WSL
launcher. WSL (Windows Subsystem for Linux) runs a separate Linux environment with its
own filesystem, home directory, and credentials, so the deploy would run somewhere your
SSH key and cloud login are not. deploy.ps1 finds Git Bash and calls it correctly.
deploy.sh applies the Terraform, then provisions from the range's own jumpbox. The
managed hosts sit on a private subnet nothing else can reach, so provisioning runs from
inside the range rather than from your laptop. Your cloud credentials stay on your
machine throughout.
ARTIE-BRIEFING.md (attack infrastructure) or HAVEN-BRIEFING.md (a range) in
the export lists the credentials and what is planted where.
Every run of deploy.sh (and deploy.ps1, which just calls it) writes one
timestamped log to logs/deploy-<UTC-timestamp>.log in the export, capturing
both the Terraform apply and the jumpbox-staged provisioning run. It opens
with a header (redStackPRO version, provider, Terraform version, your
system), and is scrubbed of secrets, private keys, and any password,
secret, or token assignment, before it is written, so it is safe to
attach to a public issue.
If a run fails, deploy.sh prints the log's path and a link to open an
issue. The repo ships GitHub issue templates (Deploy failure, Bug report)
that ask for it: if a deploy fails, or a range comes up wrong, attach the
newest logs/deploy-*.log to the issue.
A redirector is the one host that answers to the internet by name. A domain has to be
registered and pointed at the box by a human, and nothing can invent one. Any shipped
example that carries a redirector arrives one field short on purpose, and the
validator says so with RDR001.
Supply a domain you control, either in the canvas inspector before you compile, or on the command line:
redstackpro compile <template> --hostname your-domain.example -o export
After apply, create the A record the briefing names, pointing your subdomain at the redirector's address. A DNS A record is the entry that maps a domain name to an IPv4 address; you create it in your domain registrar's or DNS provider's control panel (wherever you manage the domain), not anywhere in redStackPRO. See Redirectors and Cover Stories.
Note
This is a different field from the operator access_mode covered above.
access_mode is how your team reaches the jumpbox and its Guacamole
portal, and is fully wired. transport below is about how the jumpbox
itself reaches the hosts it provisions, and remains partially built.
A jumpbox's transport overlay can be set to wireguard instead of the default
ssh, meaning it would reach the hosts it manages over a WireGuard tunnel rather
than plain ssh. Grounding what actually happens today:
- The jumpbox role does bring up a real WireGuard server on UDP 51820, generating
its own server keypair at first run and starting
wg-quick@wg0. - Peers are not generated from the topology. The role says so directly when it
finishes installing: add operator peers by hand with
wg set. - The generated firewall opens no rule for that port on either GCP or AWS, so the tunnel is not reachable from outside until you open it yourself.
- The validator flags a
wireguardtransport withBOOT001: reaching the range over WireGuard needs a two stage play order, because Ansible cannot configure WireGuard over WireGuard, so the initial bootstrap still has to run over plain ssh on the private address first.
Note
Flag for review: treat this as a partially built capability, not a supported deploy mode. The server comes up; the peer wiring and the firewall rule needed to reach it from outside do not exist yet.
Teardown is a Terraform command, not a button in the canvas or a script the export
generates for you. Ranges are meant to be stood up, used, and torn down, so nothing
keeps costing money after the work is done. From the export root (the folder holding
deploy.sh):
terraform -chdir=terraform destroy
This is the same -chdir=terraform invocation deploy.sh uses for apply, run in
reverse. Confirm the plan it shows before approving it.
Note
Flag for review: the briefing (HAVEN-BRIEFING.md or ARTIE-BRIEFING.md) does not currently print this command; it
covers access, credentials, and the planted attack surface, not teardown. Until a
teardown.sh (or an explicit mention in the briefing) ships, this page is the
place to look. If you deployed redStack (attack infrastructure) and a range as
separate exports, each has its own terraform/ state and needs its own destroy.
GCP and AWS are tested end to end. Azure, Proxmox, and ESXi are on the roadmap, not yet supported. See Providers for the full matrix and the setup notes for each.