Skip to content

Instantly share code, notes, and snippets.

@gbraad
Created June 27, 2026 06:58
Show Gist options
  • Select an option

  • Save gbraad/4ebc13a14e65c694240ad5f8f14b8e6a to your computer and use it in GitHub Desktop.

Select an option

Save gbraad/4ebc13a14e65c694240ad5f8f14b8e6a to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
# --- CONFIGURATION ---
VM_NAME="ducttape-guest"
IMAGE_PATH="./ducttape-output.qcow2" # Path to your ducttape QCOW2 image
FW_PATH="./hypervisor-fw" # Path to store/read the CH firmware
SSH_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK...your...ssh...key...here..."
VM_CPUS="2"
VM_MEM="2G"
# --- VALIDATION ---
if [ ! -f "$IMAGE_PATH" ]; then
echo "[-] Error: ducttape image not found at $IMAGE_PATH"
exit 1
fi
# Automatically fetch cloud-hypervisor firmware if it's missing
if [ ! -f "$FW_PATH" ]; then
echo "[+] Downloading cloud-hypervisor UEFI firmware..."
curl -sL "https://github.com/cloud-hypervisor/cloud-hypervisor/releases/latest/download/hypervisor-fw" -o "$FW_PATH"
fi
# --- CLOUD-INIT GENERATION ---
echo "[+] Generating cloud-init configuration..."
TEMP_DIR=$(mktemp -d)
# 1. Create user-data (defines users, keys, and packages)
cat << EOF > "${TEMP_DIR}/user-data"
#cloud-config
users:
- name: clouduser
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
ssh_authorized_keys:
- ${SSH_KEY}
package_update: true
packages:
- curl
- htop
EOF
# 2. Create meta-data (defines instance ID and hostname)
INSTANCE_ID=$(uuidgen 2>/dev/null || echo "id-$(date +%s)")
cat << EOF > "${TEMP_DIR}/meta-data"
instance-id: ${INSTANCE_ID}
local-hostname: ${VM_NAME}
EOF
# 3. Bake into a NoCloud ISO
echo "[+] Creating cloud-init seed ISO (cidata.iso)..."
genisoimage -output ./cidata.iso -V cidata -r -J "${TEMP_DIR}/user-data" "${TEMP_DIR}/meta-data" &>/dev/null
# Clean up local raw text files
rm -rf "$TEMP_DIR"
# --- LAUNCH HYPERVISOR ---
echo "[+] Booting VM with cloud-hypervisor..."
echo "[*] Press Ctrl+O to exit the console once inside the VM."
echo "--------------------------------------------------------"
# Note: Accessing /dev/kvm typically requires sudo or membership in the kvm group
sudo cloud-hypervisor \
--kernel "$FW_PATH" \
--disk path="$IMAGE_PATH" path="./cidata.iso" \
--cpus boot="$VM_CPUS" \
--memory size="$VM_MEM" \
--console off \
--serial tty
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment