Created
November 8, 2023 08:39
-
-
Save philroche/8242106415ef35b446d7e625b6d60c90 to your computer and use it in GitHub Desktop.
launch-qcow2-image-qemu-40G.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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