This section applies only when
enable_external_vpn = true is set in terraform.tfvars. The default redStack deployment uses a public domain, trusted TLS, and htaccess filtering. Only follow this guide if you are targeting an isolated OpenVPN environment.How it works
AWS VPC peering cannot deliver packets whose destination IP falls outside either VPC’s CIDR. Packets to a target like10.13.38.33 are silently dropped at the AWS fabric regardless of route tables or security groups. WireGuard solves this by creating an encrypted Layer 3 tunnel between Guacamole and the redirector. Internal machines route ExtVPN-bound traffic to Guacamole’s ENI within the same VPC. Guacamole encapsulates those packets in WireGuard UDP frames addressed to the redirector’s VPC IP (10.60.x.x), which passes VPC peering cleanly. The redirector decapsulates and forwards out tun0 (OpenVPN) to the target network.
Traffic path:
tun0 IP; conntrack reverses both MASQUERADEs on the way back.
What Terraform provisions when enable_external_vpn = true:
- Installs OpenVPN client on the redirector (
ext-vpnsystemd service) - Installs WireGuard on redirector and Guacamole (keys generated on Guacamole at boot — no pre-deployment setup needed)
- Enables IP forwarding on both instances
- Disables AWS
source_dest_checkon both ENIs (required for packet forwarding) - Adds VPC route table entries that send each CIDR in
external_vpn_cidrsto Guacamole’s ENI
| Instance | Interface | Address |
|---|---|---|
| Redirector | wg0 (server) | 10.100.0.1/30 |
| Guacamole | wg0 (client) | 10.100.0.2/30 |
Step 1: Configure terraform.tfvars
Before deploying, add the following toterraform.tfvars:
enable_redirector_htaccess_filtering = false disables scanner and AV vendor blocking. That filter is not useful in isolated lab environments and would add unnecessary latency.
Skip the following steps from the main deployment guide — they do not apply in OpenVPN mode:
- Step 1.6 (Point Domain to Redirector) — no domain or DNS record is needed
- Step 3.1 (Obtain SSL Certificate via Certbot) — a self-signed certificate with the redirector’s public Elastic IP as the Subject Alternative Name is generated automatically
Step 2: Deploy and obtain your .ovpn file
Deploy the infrastructure
yes when prompted. Guacamole automatically configures the WireGuard tunnel with the redirector during cloud-init. Wait approximately 5 minutes for all instances to finish initializing.Step 3: Transfer the .ovpn file to the redirector
Drop the.ovpn file into ~/vpn/ on the redirector. The ext-vpn service picks up whichever file is present in that directory. If multiple files are present, it uses the first one alphabetically.
- SCP from WIN-OPERATOR
Step 4: Start the VPN tunnel
SSH to the redirector from WIN-OPERATOR:ext-vpn service runs OpenVPN under systemd with --pull-filter ignore "redirect-gateway". This filter is critical — it prevents the VPN from hijacking the redirector’s default route, which would break all VPC peering and C2 proxy connectivity. iptables MASQUERADE rules are applied automatically when tun0 comes up and removed when it goes down.
Check real-time VPN logs:
Step 4b: Get the tun0 IP for C2 callbacks
The OpenVPN server assigns a dynamic IP totun0 at connect time. In a fully isolated environment where target machines can only reach the VPN network (not the public internet), use this IP as the C2 callback address.
Generate C2 agents after starting
ext-vpn. The tun0 IP is only assigned after the VPN connects, and it changes each time you reconnect. Agents with a baked-in tun0 IP stop working after a reconnection that assigns a different IP.tun0 IP. Traffic between the target and the redirector travels inside the encrypted OpenVPN tunnel, so it is already protected in transit.
| Framework | Callback address |
|---|---|
| Mythic | callback_host = "http://<tun0-ip>", callback_port = 80 |
| Sliver | --http http://<tun0-ip>/cloud/storage/objects/ |
| Havoc | Hosts: <tun0-ip>, PortConn: 80 |
X-Request-ID header) remain the same as in a standard deployment.
If the target machine has outbound internet access (most HTB standalone boxes do), you can use the public Elastic IP with HTTPS instead. The
tun0 IP is only required when targets are fully isolated and can only reach the VPN network.Step 5: Verify connectivity from internal machines
After the VPN tunnel is up, verify that all internal lab machines can reach the target network. Routing is configured at the VPC level — the Windows workstation, all C2 servers, and Guacamole can all reach targets through the tunnel without any additional configuration.- Windows workstation (PowerShell)
- C2 server or Guacamole (bash)
Step 6: Stop the VPN
tun0. The .ovpn file is preserved in ~/vpn/ — restart the tunnel any time with sudo systemctl start ext-vpn without re-uploading.
WireGuard status checks
Verify the WireGuard tunnel is healthy at any time. Both peers should show a recent handshake timestamp.Important notes
Only the configured CIDRs are routed
Only the configured CIDRs are routed
Traffic to other destinations — the public internet, VPC peers, C2 backends — is completely unaffected. Only CIDRs listed in
external_vpn_cidrs are sent through the WireGuard/OpenVPN path. Add or modify CIDRs in terraform.tfvars and redeploy if your platform uses different subnets.WireGuard starts automatically; OpenVPN does not
WireGuard starts automatically; OpenVPN does not
The WireGuard service (
wg-quick@wg0) is enabled at boot on both the redirector and Guacamole and comes up automatically after a reboot. The OpenVPN tunnel (ext-vpn) does not auto-start. Run sudo systemctl start ext-vpn after each reboot or whenever you want to connect to the target platform.WireGuard keys require no pre-deployment setup
WireGuard keys require no pre-deployment setup
Guacamole generates both keypairs at boot, writes its own WireGuard config, and SSHes into the redirector to push the server config and start the service. There is nothing to configure before running
terraform apply.source_dest_check is disabled on both ENIs
source_dest_check is disabled on both ENIs
AWS disables the source/destination check on both the redirector and Guacamole ENIs when
enable_external_vpn = true. This is required for packet forwarding — without it, AWS drops packets whose source or destination IP does not match the interface’s assigned IP.tun0 IP changes on every reconnect
tun0 IP changes on every reconnect
Agents built with a hardcoded
tun0 IP stop working after a VPN reconnection that assigns a different IP. Check ip addr show tun0 after each reconnect and regenerate agents if the IP changed. If targets have internet access, use the stable public Elastic IP with HTTPS to avoid this.redirect-gateway is filtered
redirect-gateway is filtered
The
ext-vpn service runs with --pull-filter ignore "redirect-gateway". This prevents the OpenVPN server from pushing a default route that would overwrite the redirector’s existing default route and break VPC peering and all C2 traffic. Only the specific CIDRs in external_vpn_cidrs are routed through the tunnel.