Skip to content

Instantly share code, notes, and snippets.

@philroche
Created November 8, 2023 08:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philroche/8242106415ef35b446d7e625b6d60c90 to your computer and use it in GitHub Desktop.
Save philroche/8242106415ef35b446d7e625b6d60c90 to your computer and use it in GitHub Desktop.
launch-qcow2-image-qemu-40G.sh
#!/bin/bash -eu
LAUNCHPAD_USER=""
LAUNCHPAD_USER_STRING=""
GIT_HUB_USER=""
GIT_HUB_USER_STRING=""
SSH_KEY=""
SSH_KEY_STRING=""
CREATE_BACKDOOR_USER="false"
PLAIN_TEXT_PASSWORD=""
IMAGE_TO_LAUNCH=""
usage()
{
echo "Launch qcow2 image locally using qemu and kvm with secureboot enabled. "
echo " "
echo "packages required: ovmf, petname, cloud-image-utils, whois, qemu-utils, qemu-system-x86 "
echo " "
echo "Use 'Ctrl-a x' key combination to exit emulator "
echo " "
echo "Once the VM is running you can ssh to the VM using port 2222 on localhost using either password or SSH key specified in the options below. "
echo " "
echo "Usage: launch-qcow2-image-qemu.sh [OPTIONS] "
echo " "
echo "OPTIONS: "
echo " "
echo " --help Print this message and exit. "
echo " "
echo " --launchpad-user Optional launchpad.net username you wish to import public SSH keys from. "
echo " --github-user Optional github.com username you wish to import public SSH keys from. "
echo " --ssh-public-key Optional Path to SSH key file for SSH public key to import. "
echo " --password Required - Plain text password to be configured for 'ubuntu' user. "
echo " --create-backdoor-user Optional - Create additional user 'backdoor' in VM prior to launch. Password specified with --password will also be used for this user. "
echo " --image Required - .img file to launch. "
}
if [[ $# = 0 ]]
then
usage
exit 1
else
while test $# -gt 0
do
case "$1" in
--launchpad-user)
LAUNCHPAD_USER=$2
LAUNCHPAD_USER_STRING=" - lp:${LAUNCHPAD_USER}"
echo "LAUNCHPAD_USER: ${LAUNCHPAD_USER}"
shift
shift
;;
--github-user)
GIT_HUB_USER=$2
GIT_HUB_USER_STRING=" - gh:${GIT_HUB_USER}"
echo "GIT_HUB_USER: ${GIT_HUB_USER}"
shift
shift
;;
--ssh-public-key)
SSH_KEY=$2
echo "SSH_KEY: ${SSH_KEY}"
shift
shift
;;
--create-backdoor-user)
CREATE_BACKDOOR_USER="true"
echo "CREATE_BACKDOOR_USER: ${CREATE_BACKDOOR_USER}"
shift
;;
--password)
PLAIN_TEXT_PASSWORD=$2
echo "PLAIN_TEXT_PASSWORD: ${PLAIN_TEXT_PASSWORD}"
shift
shift
;;
--image)
IMAGE_TO_LAUNCH=$2
echo "IMAGE_TO_LAUNCH: ${IMAGE_TO_LAUNCH}"
shift
shift
;;
--help|-h)
usage
exit 0
;;
*)
echo "argument $1 is not a valid argument"
exit 1
;;
esac
done
fi
if [ -z "${PLAIN_TEXT_PASSWORD}" ] ; then
echo "ERROR: You must specify a password to be configured for the 'ubuntu' user with --password"
exit 1
fi
if [ ! -f "${IMAGE_TO_LAUNCH}" ] ; then
echo "ERROR: You must specify a valid image to launch with --image"
exit 1
fi
# If the SSH_KEY variable is set and file path does not exist, then exit 1
if [ "${SSH_KEY}" != "" ]; then
if [ ! -f "${SSH_KEY}" ] ; then
echo "ERROR: You must specify a valid SSH public key file to import with --ssh-public-key"
exit 1
else
SSH_KEY_STRING=" - $(cat ${SSH_KEY})"
fi
fi
# Check to see if the package dependencies (ovmf, petname, cloud-image-utils, whois, qemu-utils, qemu-system-x86) are installed
# If not, then exit 1 with instructions on how to install them
if ! dpkg -s ovmf petname cloud-image-utils whois qemu-utils qemu-system-x86 > /dev/null 2>&1 ; then
echo "ERROR: You must install the following packages to use this script: "
echo " ovmf petname cloud-image-utils whois qemu-utils qemu-system-x86 "
echo "Use the following command to install them: "
echo " sudo apt-get install --assume-yes ovmf petname cloud-image-utils whois qemu-utils qemu-system-x86"
exit 1
fi
echo "Deleting any previous boot or seed images..."
rm --force --verbose boot-disk*.img seed-*.img
echo "Launching ${IMAGE_TO_LAUNCH}"
RANDOMSEED=$(petname)
echo ${RANDOMSEED}
cat <<EOF > meta-data-${RANDOMSEED}
instance-id: iid-local01
local-hostname: cloudimg
EOF
echo "Creating encrypted password..."
ENCRYPTED_PASSWORD=$(mkpasswd --method=SHA-512 --rounds=4096 "${PLAIN_TEXT_PASSWORD}")
cat <<EOF > user-data-${RANDOMSEED}
#cloud-config
ssh_import_id:
${LAUNCHPAD_USER_STRING}
${GIT_HUB_USER_STRING}
ssh_authorized_keys:
${SSH_KEY_STRING}
system_info:
default_user:
lock_passwd: false
passwd: ${ENCRYPTED_PASSWORD}
ssh_pwauth: true
users:
- default
EOF
cloud-localds seed-${RANDOMSEED}.img user-data-${RANDOMSEED} meta-data-${RANDOMSEED}
echo "Removing the metadata and userdata..."
rm --force --verbose user-data-${RANDOMSEED} meta-data-${RANDOMSEED}
echo "Creating a disk backed by the image..."
qemu-img create -f qcow2 -F qcow2 -b $IMAGE_TO_LAUNCH boot-disk-${RANDOMSEED}.img 40G
echo "Allow password authentication"
sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- sh -c 'mkdir --parents --verbose ${MOUNTPOINT}/etc/ssh/sshd_config.d'
sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- sh -c 'echo "PasswordAuthentication yes" > ${MOUNTPOINT}/etc/ssh/sshd_config.d/50-cloudimg-settings.conf'
# Create a backdoor user if requested
if [ "${CREATE_BACKDOOR_USER}" == "true" ]; then
echo "Customise the boot image should cloud-init provisioning not succeed by adding a new user backdoor with password 'passw0rd'"
sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- mchroot useradd --create-home --password "${ENCRYPTED_PASSWORD}" --shell /bin/bash backdoor
sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- sh -c 'mkdir --parents --verbose ${MOUNTPOINT}/etc/sudoers.d'
sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- sh -c 'echo "backdoor ALL=(ALL) NOPASSWD:ALL" > ${MOUNTPOINT}/etc/sudoers.d/backdoor'
fi
# Configure cloud-init to use NoCloud as the datasource - this means it will read the attached user-data
sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- sh -c 'echo "datasource_list: [ NoCloud ]" > ${MOUNTPOINT}/etc/cloud/cloud.cfg.d/99-cloudimg-settings.cfg; cat ${MOUNTPOINT}/etc/cloud/cloud.cfg.d/99-cloudimg-settings.cfg'
# sudo mount-image-callback boot-disk-${RANDOMSEED}.img -- sh -c 'rm --verbose --force ${MOUNTPOINT}/mount/etc/cloud/cloud.cfg.d/99-disable-network-activation.cfg'
echo "Launching the instance with secure boot enabled..."
qemu-system-x86_64 \
-cpu host -machine type=q35,accel=kvm -m 8192 \
-global ICH9-LPC.disable_s3=1 \
-nographic \
-snapshot \
-netdev id=net00,type=user,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=net00 \
-device virtio-scsi-pci,id=scsi \
-device scsi-hd,drive=boot-disk \
-device scsi-hd,drive=seed-disk \
-drive if=none,id=boot-disk,format=qcow2,file=boot-disk-${RANDOMSEED}.img \
-drive if=none,id=seed-disk,format=raw,file=seed-${RANDOMSEED}.img \
-drive if=pflash,format=raw,readonly=on,unit=0,file=/usr/share/OVMF/OVMF_CODE.secboot.fd \
-drive if=pflash,format=raw,readonly=on,unit=1,file=/usr/share/OVMF/OVMF_VARS.ms.fd
echo "Boot Disk boot-disk-${RANDOMSEED}.img"
echo "Seed Disk seed-${RANDOMSEED}.img"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment