- This project is designed for legitimate security testing only. Ensure you have permission to scan the targets.
- Scan costs depend on the number and duration of scans run.
- The default configuration launches Fargate tasks with 0.25 vCPU and 0.5GB memory.
- Worker count is user-configurable. At 50+ workers, automatically switches to EC2 Spot Fleet for cost savings.
Heph4estus is a TUI/CLI app that handles cloud infrastructure deployment and distributed execution of red team tools. For an in-depth explanation of the architecture, roadmap, and the project as a whole please check hephaestus.tools.
You provide: cloud credentials + input files (targets, hashes). Heph4estus handles: infrastructure provisioning, container builds, job orchestration, result collection, and teardown.
Built-in modules today: nmap, nuclei, ffuf, subfinder, httpx, masscan, gobuster, feroxbuster, dnsx, katana, gospider, massdns, dalfox, gowitness. All modules run on the generic worker backend. See ARCHITECTURE.md, PLAN.md, and IMPLEMENTATION.md for the roadmap.
AWS (default, fully integrated): SQS + S3 + ECS Fargate / EC2 Spot Fleet. Infrastructure is provisioned and destroyed automatically via Terraform.
VPS providers (manual, hetzner, linode, scaleway, vultr): NATS JetStream + S3-compatible storage (MinIO) on a shared VPS runtime family. manual is the expert/operator-managed Docker-over-SSH path. hetzner, linode, and vultr are the mainstream provider-native paths: Terraform provisions the controller + workers, cloud-init boots a persistent worker service, workers self-register with the fleet manager, and scans wait for fleet readiness instead of SSH-launching ad hoc workers from the operator machine. scaleway remains in the shared runtime family but does not yet have a provider-native adapter. The legacy selfhosted selector remains accepted as a compatibility alias for manual.
- Go 1.26+: For building the application
- Docker: For building container images (managed by heph4estus)
- Terraform 1.5+: For infrastructure provisioning (managed by heph4estus)
- AWS CLI: Configured with appropriate credentials and permissions (AWS path only)
git clone <repository-url>
cd heph4estus
go build -o bin/heph ./cmd/heph
go build -o bin/heph4estus ./cmd/heph4estusaws sso login
# or configure credentials via env vars / ~/.aws/credentialsCreate a file named targets.txt with one target per line for nmap or generic target_list tools:
example.com -sV -p 80,443
10.0.0.0/24 -sS -p 22
192.168.1.1 -A
Format: <target> [nmap options]. Default options are -sS if none specified.
For wordlist-driven tools such as ffuf, create a file named words.txt:
admin
login
api
heph scan and heph nmap automatically deploy infrastructure when needed. If matching infrastructure already exists, it is reused without redeploying.
# Nmap — auto-deploys if no nmap infra exists, reuses if it does
./bin/heph nmap --file targets.txt
# Generic target_list flow — same lifecycle behavior
./bin/heph scan --tool httpx --file targets.txt
# Generic wordlist flow
./bin/heph scan --tool ffuf --wordlist words.txt --target https://example.com/FUZZ --chunks 20
# Interactive TUI (also auto-detects existing infra)
./bin/heph4estusBoth heph scan and heph nmap accept these lifecycle flags:
--no-deploy— fail instead of deploying or redeploying (power-user / CI mode)--auto-approve— skip deploy confirmation prompts when lifecycle work is needed--destroy-after— tear down infrastructure after the run completes
Both scan commands also accept provider/runtime flags including --cloud, --workers, --placement, --max-workers-per-host, --min-unique-ips, --ipv6-required, and --dual-stack-required. Placement flags matter on provider-native VPS fleets: diversity is the default and admits one worker per healthy public IP, while throughput allows multiple workers per host when raw concurrency matters more than source-IP diversity.
# CI pipeline: deploy, scan, tear down, no prompts
./bin/heph nmap --file targets.txt --auto-approve --destroy-after
# Explicit "infra must already exist" mode
./bin/heph scan --tool httpx --file targets.txt --no-deploy
# VPS diversity gate: wait for 25 unique IPv4-backed workers before scanning
./bin/heph scan --tool httpx --file targets.txt --cloud hetzner --workers 25 --min-unique-ips 25The AWS generic Terraform environment supports optional dual-stack VPC networking and optional multi-NAT IPv4 egress. Both are disabled by default, so existing AWS deployments keep the current single-NAT IPv4 behavior unless these features are explicitly enabled.
cd deployments/aws/generic/environments/dev
TF_VAR_tool_name=nmap TF_VAR_enable_ipv6=true terraform plan
# IPv4 source diversity: one NAT gateway and EIP per AZ
TF_VAR_tool_name=nmap TF_VAR_multi_nat=true terraform planWhen enable_ipv6 is true, Terraform assigns an AWS-generated IPv6 CIDR to the VPC, gives public and private subnets IPv6 /64 blocks, routes public IPv6 egress through the internet gateway, and routes private IPv6 egress through an egress-only internet gateway. IPv4 NAT remains present and unchanged.
When multi_nat is true, Terraform creates one NAT gateway and one Elastic IP per availability zone, then routes each private subnet through the NAT gateway in the same AZ. This improves IPv4 source IP diversity, but it also increases AWS NAT Gateway and Elastic IP costs.
Before relying on IPv6 egress from ECS tasks, enable the ECS dualStackIPv6 account setting in the target AWS account and region, for example:
aws ecs put-account-setting-default --name dualStackIPv6 --value enabledThis networking support only provisions the IPv6-capable VPC path and multi-NAT infrastructure. CLI/TUI controls and network status display are tracked separately.
AWS Terraform modules declare Terraform >= 1.5.0, hashicorp/aws ~> 6.0, and hashicorp/random ~> 3.0 where used. Run these checks before changing AWS infrastructure:
make tf-fmt
make tf-validate
make tf-lint
make tf-securityUse Trivy (make tf-security) for Terraform security scanning. tfsec is legacy and should not be used for new checks. Phase 11 separates Terraform lint cleanup from AWS security hardening, so Trivy findings are handled in dedicated follow-up PRs.
The AWS generic dev environment uses a customer-managed KMS key for CloudWatch log groups, VPC Flow Logs, ECR repositories, SQS queues, and the S3 result bucket. The result bucket also writes S3 server access logs to a dedicated log bucket that uses SSE-S3, which is required for S3 log delivery destinations. AWS worker images are published with generated immutable ECR tags and ECS task definitions reference the full immutable image.
Scanner worker egress defaults to arbitrary IPv4 targets because scan targets are user-supplied and may be anywhere on the public internet. Constrained environments can set scanner_egress_ipv4_cidr_blocks and scanner_egress_ipv6_cidr_blocks Terraform variables to narrower CIDR lists. The unrestricted default is explicitly documented in Terraform as an intentional scanner exception.
After the encryption, logging, immutable image-publishing, networking, and IAM baseline, make tf-security should have no unreviewed AWS findings.
The VPS-family path is intentionally split in two:
manualis the expert mode and escape hatch for operator-managed environmentshetzner,linode, andvultrare the provider-native controller-plane paths
Manual scan execution works when the operator has already provisioned:
- A reachable NATS JetStream endpoint (queue)
- A reachable MinIO or S3-compatible endpoint (storage)
- Worker hosts with Docker and SSH access
- A worker image reachable by those hosts
Set the required environment variables:
# Controller endpoints
export NATS_URL="nats://controller:4222"
export S3_ENDPOINT="http://controller:9000"
export S3_REGION="us-east-1"
export S3_ACCESS_KEY="minioadmin"
export S3_SECRET_KEY="minioadmin"
export S3_PATH_STYLE="true"
# Scan runtime contract (env-driven)
export SELFHOSTED_QUEUE_ID="heph-tasks"
export SELFHOSTED_BUCKET="heph-results"
# Worker compute config
export SELFHOSTED_WORKER_HOSTS="w1.example.com,w2.example.com"
export SELFHOSTED_SSH_USER="heph"
export SELFHOSTED_SSH_KEY_PATH="$HOME/.ssh/id_ed25519"
export SELFHOSTED_DOCKER_IMAGE="controller:5000/heph-nmap-worker:latest"
# Optional: export SELFHOSTED_SSH_PORT="22"
# Optional: export NATS_STREAM="heph-tasks"Run scans:
# Nmap scan on the manual/operator-managed VPS path
./bin/heph nmap --file targets.txt --cloud manual
# Generic tool scan on the manual/operator-managed VPS path
./bin/heph scan --tool httpx --file targets.txt --cloud manualHost and network requirements:
- Treat each worker VM as one source-IP slot when you care about IP diversity. If you run more workers than unique hosts, some workers will share the same public IP.
- Each worker host should have a stable public IPv4 address. For IPv6 scanning, each host must also have a routable public IPv6 address.
- Provider firewalls/security groups must allow outbound IPv6 and outbound access to the controller services (NATS, MinIO, registry).
- The worker container must have a validated IPv6 egress path from inside Docker. In practice that means host networking or a verified Docker IPv6 configuration on the worker VM before relying on
-6. - Each host must be able to pull the worker image, reach the controller endpoints, and accept non-interactive SSH from the operator.
Scheduler rules:
- The queue is the task scheduler; the host inventory is the source-IP pool.
- The current selfhosted path is manual: Heph launches workers across
SELFHOSTED_WORKER_HOSTS, so maximum source-IP diversity today is bounded by the number of unique hosts you supply. - For maximum diversity today, keep
--workersless than or equal to the number of unique worker hosts. - The provider-native fleet manager owns host provisioning, health, public IP metadata, IPv6 capability checks, and diversity-aware placement. Its default rule is one worker container per healthy host/public IP, with multi-worker-per-host reserved for explicit throughput mode.
What success looks like:
- Tasks enqueue to the NATS queue identified by
SELFHOSTED_QUEUE_ID - In manual mode, Heph launches workers over SSH on the configured hosts
- Workers read from NATS and upload results to
SELFHOSTED_BUCKET heph status --job-id <id>can reattach using recorded job metadata
Cleanup note: manual mode is operator-managed infrastructure, so --destroy-after is intentionally skipped. Use manual when you own the controller and worker lifecycle yourself; use hetzner, linode, or vultr when you want Heph to own deploy/destroy.
For the provider-native VPS paths, normal operator flows do not require the raw SELFHOSTED_* runtime contract above. The expected flow is:
# Provider-native deploy + scan
./bin/heph infra deploy --tool nmap --cloud hetzner
./bin/heph nmap --file targets.txt --cloud hetznerOn these paths, Terraform provisions the controller and worker VMs, cloud-init boots the persistent worker service, workers self-register with the fleet manager, and the scan waits for fleet readiness instead of SSH-launching workers from the operator machine. SSH remains a bootstrap/debug tool, not the normal orchestration model.
Provider setup:
- Hetzner: set
HCLOUD_TOKEN - Linode: set
LINODE_TOKEN - Vultr: set
VULTR_API_KEY - SSH public key: Heph uses
HEPH_SSH_PUBLIC_KEY,SSH_PUBLIC_KEY,HEPH_SSH_PUBLIC_KEY_PATH,SSH_PUBLIC_KEY_PATH, or the first existing~/.ssh/id_ed25519.pub/~/.ssh/id_rsa.pub
export HCLOUD_TOKEN="..."
export HEPH_SSH_PUBLIC_KEY_PATH="$HOME/.ssh/id_ed25519.pub"
./bin/heph init \
--cloud hetzner \
--placement diversity \
--workers 25 \
--min-unique-ips 25 \
--output-dir ./results \
--cleanup-policy destroy-after
./bin/heph doctor --cloud hetznerCost and teardown posture:
- Provider-native defaults create one controller plus three worker VMs unless
--workerson scan sets a differentworker_countfor deploy. - VPS providers bill while VMs exist. Use
--destroy-afterfor one-shot runs or./bin/heph infra destroy --tool <tool> --cloud <provider>after validation. - Use
--out <dir>or a saved output directory before destroy if you need local result copies. Results in MinIO disappear when the controller VM is destroyed.
Security posture:
- Provider-native Terraform outputs include
controller_security_mode, service TLS/auth posture, credential generation metadata, controller certificate expiry, and NATS mTLS client certificate expiry. private-authremains the default compatibility mode.tlsencrypts NATS, MinIO, and the controller registry while keeping role-scoped credentials.mtlsadditionally requires NATS client certificates for worker/operator NATS connections.- After deploy, run
./bin/heph doctor --cloud <provider> --tool <tool>to report controller posture, missing TLS/auth, certificate expiry, stale credentials, and mTLS output health. - Rotate role-scoped credentials with
./bin/heph infra rotate credentials --tool <tool> --cloud <provider> --component nats|minio|registry;--component allis a dry-run planning view. - Rotate controller certificates with
./bin/heph infra rotate certs --tool <tool> --cloud <provider> --component controller|ca;workerandallcertificate rotation are dry-run planning only. - Phase 6 production-readiness baseline is TLS plus role-scoped rotatable credentials. MinIO and registry client-certificate mTLS are intentionally deferred unless live validation shows they are needed.
Useful provider-native fleet operations:
# Provider-specific prerequisite checks
./bin/heph doctor --cloud hetzner
# Provider-specific checks plus deployed controller security posture
./bin/heph doctor --cloud hetzner --tool nmap
# Inspect fleet health, IP diversity, placement, rollout, and reputation state
./bin/heph fleet status --tool nmap --cloud hetzner
# Repair unhealthy or quarantined workers
./bin/heph fleet reconcile --tool nmap --cloud hetzner
# Quarantine or clear a public IP
./bin/heph fleet quarantine --cloud hetzner --ip 203.0.113.10 --reason "rate limited"
./bin/heph fleet unquarantine --cloud hetzner --ip 203.0.113.10
# Canary a new worker image and promote or roll back
./bin/heph fleet rollout start --tool nmap --cloud hetzner
./bin/heph fleet rollout status --tool nmap --cloud hetzner
# Benchmark deploy/readiness/IP diversity and compare recent runs
./bin/heph bench fleet --tool nmap --cloud hetzner
./bin/heph bench history --tool nmap --cloud hetzner
# Save/inspect/recover local fleet recovery metadata
./bin/heph infra backup --tool nmap --cloud hetzner --output recovery/nmap-hetzner.json
./bin/heph infra backup inspect --from recovery/nmap-hetzner.json
./bin/heph infra recover --tool nmap --cloud hetzner --from recovery/nmap-hetzner.json --dry-runWhat is not yet supported:
scalewayprovider-native deploy UX; usemanualfor operator-managed Scaleway environments todaymanualbecoming a zero-config mainstream path; it remains expert mode- Automatic controller-output consumption for
manual; the manual path still uses the env-driven contract above - MinIO or registry client-certificate mTLS; NATS mTLS strict mode is available through
controller_security_mode=mtls - Live provider validation coverage in this repo; real Hetzner/Linode/Vultr smoke tests still need to be run against throwaway accounts before calling Phase 6 fully production-ready
heph infra is still available as the power-user and CI path for managing infrastructure directly:
# Deploy infrastructure for a tool
./bin/heph infra deploy --tool nmap
# Deploy provider-native VPS infrastructure
./bin/heph infra deploy --tool nmap --cloud hetzner
# Tear down (empty S3 bucket first if destroy fails)
./bin/heph infra destroy --tool nmapInfrastructure can be destroyed after a run using --destroy-after, or manually:
./bin/heph infra destroy --tool nmap
./bin/heph infra destroy --tool httpx
./bin/heph infra destroy --tool ffufIf you previously deployed the dedicated nmap infrastructure (deployments/aws/nmap/environments/dev), you must destroy it before switching to the generic backend. The dedicated Terraform files have been removed from this repo, so you need to destroy using your existing local Terraform state:
# Option 1: Check out the last commit that still has the dedicated nmap Terraform,
# then destroy from there.
git stash # if needed
git checkout <last-commit-with-dedicated-nmap>
cd deployments/aws/nmap/environments/dev
# Empty the S3 bucket first (aws s3 rm s3://<bucket> --recursive)
terraform destroy
git checkout - # return to current branch
# Option 2: If your Terraform state is remote (S3 backend), you can run
# terraform destroy from any checkout that still has the .tf files, or
# delete the resources manually via the AWS console.Then deploy generic nmap infrastructure:
./bin/heph infra deploy --tool nmapFuture nmap results will land under the generic job-scoped prefixes (scans/nmap/<job>/...).
Before opening a PR, run the fast local checks:
make fmt-check
make vet
make test
make lintIf make lint fails because the installed golangci-lint binary was built with an older Go version than the module targets, install the repo-pinned linter and rerun it:
make install-lint
make lintFor manual infrastructure management during development:
# Deploy generic infrastructure for any tool
./bin/heph infra deploy --tool nmap
./bin/heph infra deploy --tool httpx
# Build nmap generic worker image manually
docker build -t heph-nmap-worker \
--build-arg RUNTIME_INSTALL_CMD="apk add --no-cache nmap nmap-scripts" \
-f containers/generic/Dockerfile .
# Tear down (empty S3 bucket first)
./bin/heph infra destroy --tool nmap