HailBytes SAT Tutorial

Deploy on AWS via the CLI

Programmatic, reproducible HailBytes SAT deployment using the AWS CLI. Designed for CI pipelines, agents, and infrastructure-as-code workflows.

Overview

HailBytes SAT publishes a hardened AMI to the AWS Marketplace (built nightly via Packer on Ubuntu 24.04). This tutorial shows how to subscribe, locate the AMI, and launch an instance entirely from the AWS CLI, with no console clicks. If you'd rather use the console, see the marketplace UI tutorial.

Prerequisites

  • AWS CLI v2 configured with credentials that can call ec2:* and aws-marketplace:Subscribe
  • An AWS account already subscribed to HailBytes SAT in the AWS Marketplace (one-click; required before RunInstances succeeds)
  • A VPC and public subnet, or use the default VPC
  • An EC2 key pair name for SSH

Step 1: Find the Latest AMI ID

HailBytes publishes the AMI ID through SSM Parameter Store so it can be queried without hard-coding:

AMI_ID=$(aws ssm get-parameter \
  --region us-east-1 \
  --name /aws/service/marketplace/prod-hailbytes-sat/latest \
  --query 'Parameter.Value' \
  --output text)
echo "$AMI_ID"

Or query the Marketplace catalog directly by owner alias and name pattern:

aws ec2 describe-images \
  --region us-east-1 \
  --owners aws-marketplace \
  --filters "Name=name,Values=hailbytes-sat-*" \
  --query 'sort_by(Images, &CreationDate)[-1].[ImageId,Name,CreationDate]' \
  --output text

Step 2: Create a Security Group

HailBytes SAT serves the admin UI on 3333, the phishing landing pages on 80/443, and SSH on 22. Restrict admin and SSH to your IP range.

VPC_ID=$(aws ec2 describe-vpcs --filters Name=isDefault,Values=true \
  --query 'Vpcs[0].VpcId' --output text)

SG_ID=$(aws ec2 create-security-group \
  --group-name hailbytes-sat-sg \
  --description "HailBytes SAT inbound" \
  --vpc-id "$VPC_ID" --query 'GroupId' --output text)

MY_IP=$(curl -s https://checkip.amazonaws.com)/32

# Admin UI & SSH locked to your IP
aws ec2 authorize-security-group-ingress --group-id "$SG_ID" \
  --protocol tcp --port 3333 --cidr "$MY_IP"
aws ec2 authorize-security-group-ingress --group-id "$SG_ID" \
  --protocol tcp --port 22   --cidr "$MY_IP"

# Phishing landing pages open to the world
aws ec2 authorize-security-group-ingress --group-id "$SG_ID" \
  --protocol tcp --port 80   --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id "$SG_ID" \
  --protocol tcp --port 443  --cidr 0.0.0.0/0

Step 3: Launch the Instance

Use t3.medium for trials, m6i.large for production. Pass an optional admin email through user data so first-boot emails the bootstrap credentials.

cat > user-data.yaml <<'EOF'
#cloud-config
hailbytes_sat:
  admin_email: admin@your-domain.com
  hostname:    sat.your-domain.com
EOF

INSTANCE_ID=$(aws ec2 run-instances \
  --image-id "$AMI_ID" \
  --instance-type m6i.large \
  --key-name YOUR_KEY_PAIR \
  --security-group-ids "$SG_ID" \
  --block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=50,VolumeType=gp3,Encrypted=true}' \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=hailbytes-sat},{Key=Product,Value=HailBytes-SAT}]' \
  --user-data file://user-data.yaml \
  --query 'Instances[0].InstanceId' --output text)

echo "Launched: $INSTANCE_ID"
aws ec2 wait instance-status-ok --instance-ids "$INSTANCE_ID"

PUBLIC_DNS=$(aws ec2 describe-instances --instance-ids "$INSTANCE_ID" \
  --query 'Reservations[0].Instances[0].PublicDnsName' --output text)
echo "Open https://$PUBLIC_DNS:3333/"

Step 4: First-Boot Output

First boot takes 2–3 minutes. The bootstrap admin password is written to /var/log/hailbytes-sat-first-boot.log. Pull it via SSH or the console:

aws ec2 get-console-output --instance-id "$INSTANCE_ID" \
  --query 'Output' --output text | grep -A1 "ADMIN PASSWORD"

# Or via SSH:
ssh -i ~/.ssh/YOUR_KEY.pem ubuntu@$PUBLIC_DNS \
    'sudo cat /var/log/hailbytes-sat-first-boot.log'

Step 5: Wire DNS & TLS

Point an A record at the instance's public IP and use the built-in ACME flow to issue Let's Encrypt certs from Settings → Certificates. For production deployments use an Elastic IP so DNS doesn't drift on reboot:

EIP_ALLOC=$(aws ec2 allocate-address --domain vpc \
  --query 'AllocationId' --output text)
aws ec2 associate-address \
  --instance-id "$INSTANCE_ID" --allocation-id "$EIP_ALLOC"

Step 6: Verify

# Liveness probe
curl -k https://$PUBLIC_DNS:3333/api/health

# Readiness (DB up)
curl -k https://$PUBLIC_DNS:3333/api/ready

GovCloud Notes

For AWS GovCloud (US), swap --region us-east-1 for us-gov-west-1 or us-gov-east-1 and use the GovCloud Marketplace listing. AMI IDs differ per partition; the SSM parameter path is the same.

Teardown

aws ec2 terminate-instances --instance-ids "$INSTANCE_ID"
aws ec2 wait instance-terminated --instance-ids "$INSTANCE_ID"
aws ec2 delete-security-group --group-id "$SG_ID"
aws ec2 release-address --allocation-id "$EIP_ALLOC"

Next Steps

Quickstart

Now that the instance is up, log in and run your first campaign in 10 minutes.

View Tutorial →

Connect an AI Assistant

Wire Claude or Cursor to the built-in MCP server.

View Reference →

Related Tutorials

Get the Free HailBytes SAT Getting Started Guide

A 7-part email series covering everything from your first deployment to advanced configuration and real-world workflows. One email per day, no spam.