This guide describes how to provision, harden, and verify a Google Compute Engine (GCE) VM sandbox for dynamic exploit reproduction and patch verification in Mantis.
An automated idempotent setup script is provided at
reference/scripts/setup_gce_sandbox.sh:
PROJECT_ID="your-project-id" SOURCE_INSTANCE="your-dev-vm" ./reference/scripts/setup_gce_sandbox.shSet these environment variables in your shell before running the manual setup commands:
export PROJECT_ID="${PROJECT_ID:-$(gcloud config get-value project)}"
export REGION="us-central1"
export ZONE="us-central1-a"
export VPC_NAME="mantis-isolated-vpc"
export SUBNET_NAME="mantis-isolated-subnet"
export SUBNET_RANGE="10.0.0.0/24"
export DNS_POLICY_NAME="mantis-block-public-dns"
export IMAGE_NAME="mantis-assessment-disk-v1"
export DEV_BUILD_VM="my-dev-build-vm"Before capturing your golden assessment disk image from the source build VM, ensure the following prerequisites are installed and configured:
-
Passwordless
sudo(NOPASSWD):- During instance initialization,
GceEnvironmentprovisions the guest workspace directory via SSH (core/environments/gce_env.py:269):sudo mkdir -p /workspace && sudo chown -R $(whoami) /workspace
- The SSH user connecting to the sandbox VM must have passwordless
sudorights in/etc/sudoersor/etc/sudoers.d/(e.g. standard%sudo ALL=(ALL) NOPASSWD:ALLor%admin ALL=(ALL) NOPASSWD:ALL). Standard GCP Ubuntu LTS images configure this by default for the provisioning user.
- During instance initialization,
-
python3Interpreter:GceEnvironmentruns automated active in-guest security isolation audits (_verify_guest_isolation()incore/environments/gce_env.py:338) by piping a base64-encoded isolation verification script directly topython3:echo '<probe_script>' | base64 -d | python3 -
- Ensure
python3(orpython3-minimal) is installed on the image and available inPATH(/usr/bin/python3). Withoutpython3, instance startup fails fail-closed during guest isolation verification.
-
Pre-Warmed Build Tools & Dependencies:
- Because the isolated VPC has zero external internet routing and no Cloud NAT, all compilers, build runtimes, package manager caches, test frameworks, and dependencies needed to compile the target repository and reproduce vulnerabilities must be pre-installed and pre-built on the VM before capturing the disk image.
- Provision a development VM with all necessary build runtimes, compilers, package managers, and test suites.
- Confirm that passwordless
sudoandpython3are configured as described above. - Build your target repository on the VM to warm all local build caches, dependencies, and artifacts.
- Capture a custom disk image from the source build VM:
gcloud compute images create "${IMAGE_NAME}" \
--project="${PROJECT_ID}" \
--source-disk="${DEV_BUILD_VM}" \
--source-disk-zone="${ZONE}" \
--force \
--description="Assessment disk image with pre-warmed build dependencies for Mantis"[!IMPORTANT] Disk Images vs Machine Images: Custom disk images (
gcloud compute images create --source-disk=...) allow full instance identity override (--no-service-account --no-scopes), ensuring the sandbox VM runs with zero IAM credentials (serviceAccounts: null). GCE Machine Images (--source-machine-image) lock in the service account identity from the source VM and disallow--no-service-account.
Create a dedicated VPC with zero external access and Private Google Access disabled:
# 1. Custom VPC
gcloud compute networks create "${VPC_NAME}" \
--project="${PROJECT_ID}" \
--subnet-mode=custom
# 2. Private subnet (no internet route, no Cloud NAT, no Google API access)
gcloud compute networks subnets create "${SUBNET_NAME}" \
--project="${PROJECT_ID}" \
--network="${VPC_NAME}" \
--region="${REGION}" \
--range="${SUBNET_RANGE}" \
--no-enable-private-ip-google-access
# 3. Allow SSH strictly from Google Cloud Identity-Aware Proxy (IAP) IP range
gcloud compute firewall-rules create "allow-iap-ssh-${VPC_NAME}" \
--project="${PROJECT_ID}" \
--network="${VPC_NAME}" \
--allow=tcp:22 \
--source-ranges=35.235.240.0/20By default in GCE, queries to the link-local metadata resolver
(169.254.169.254:53) perform recursive public DNS lookups out-of-band via the
hypervisor, creating an exfiltration path even without external IP routing.
Seal this path at the VPC infrastructure level using Cloud DNS:
# Create response policy bound to isolated VPC
gcloud dns response-policies create "${DNS_POLICY_NAME}" \
--project="${PROJECT_ID}" \
--networks="${VPC_NAME}" \
--description="Block all public DNS lookups"
# Wildcard rule returning 0.0.0.0 for all domains (*.)
gcloud dns response-policies rules create block-all-domains \
--project="${PROJECT_ID}" \
--response-policy="${DNS_POLICY_NAME}" \
--dns-name="*." \
--local-data=name="*.",type="A",ttl=300,rrdatas="0.0.0.0"# Redirect all VM DNS queries away from public recursion to an unassigned private IP
gcloud dns policies create mantis-dns-blackhole \
--project="${PROJECT_ID}" \
--networks="${VPC_NAME}" \
--description="Redirect VM DNS queries to private blackhole" \
--private-alternative-name-servers=10.0.0.254 \
--enable-loggingAdd the GCE sandbox configuration to workflow.json:
{
"sandbox": {
"type": "gce",
"options": {
"project": "YOUR_PROJECT_ID",
"zone": "us-central1-a",
"image": "mantis-assessment-disk-v1",
"subnet": "mantis-isolated-subnet",
"workdir": "/workspace",
"tunnel_through_iap": true,
"no_service_account": true,
"no_external_ip": true,
"verify_isolation": true,
"timeout_seconds": 60
}
}
}When verify_isolation: true is set (the default), GceEnvironment executes an
active in-guest probe before executing any PoCs or analysis tasks:
- IAM Token Leak Probe: Queries
http://169.254.169.254/.../service-accounts/default/token. Fails if access tokens are accessible. - Direct Internet Egress Probe: Attempts TCP connection to external IP
(
1.1.1.1:80). Fails if reachable. - Public DNS Recursion Probe: Attempts resolving
example.com. Fails if public IP is returned. - Private Google Access Probe: Attempts TCP connection to
storage.googleapis.com:443. Fails if reachable.
If any check fails, the VM is immediately deleted and Mantis halts with a
fail-closed RuntimeError detailing the misconfiguration.
[!NOTE] The GCE sandbox setup is currently designed and configured for single-VM execution only.
If an operator wants to adapt this setup for multi-VM campaigns (e.g. distributed targets or multi-node exploit chains), they must resolve at least the following architectural constraints:
- DNS Name Resolution (
*.internal): The wildcard Cloud DNS response policy (*.→0.0.0.0) catches everything, including internal metadata domains (*.internal), making peer VMs unresolvable by hostname. Multi-VM setups require explicit private DNS zone rules bypassing the wildcard sinkhole for internal peer records. - Internal VM-to-VM Ingress: The firewall section creates IAP ingress on
tcp:22and nothing else. Because GCP denies ingress by default, all VM-to-VM network traffic between sandbox instances is blocked (there is noallow-internalrule). - Instance Tagging & Firewall Scoping: Instances created by
GceEnvironmentdo not currently attach network--tags. An operator adding an internal communication rule cannot scope it to sandbox VMs by tag, but only by CIDR (which means scoping it to the entire subnet).