From e358bc131f405868c97f417d3c339dd0fb796050 Mon Sep 17 00:00:00 2001 From: Stefan Kreutz Date: Fri, 11 Sep 2020 10:27:34 +0200 Subject: Accept changes from blog post --- README.md | 88 +---------------- autoinstall-openbsd-on-qemu | 225 ++++++++++++++++++++++++++++++++++++++++++++ run | 180 ----------------------------------- 3 files changed, 226 insertions(+), 267 deletions(-) create mode 100755 autoinstall-openbsd-on-qemu delete mode 100755 run diff --git a/README.md b/README.md index 50f9687..4bf93b5 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,3 @@ # Auto-install OpenBSD on QEMU -This repository hosts a POSIX shell script to auto-install OpenBSD/amd64 6.7 to -copy-on-write disk image using QEMU. The script is intended to run on Linux. If -you already have a running OpenBSD installation, you should consider to use -OpenBSD's own hypervisor [vmm(4)](https://man.openbsd.org/vmm) instead of QEMU -as described in the [OpenBSD FAQ](https://www.openbsd.org/faq/faq16.html) and -in this [blog post](https://eradman.com/posts/autoinstall-openbsd.html). - -The script will: - -* Download and verify the official installation image and file sets. -* Create and serve a TFTP boot environment. -* Create an [autoinstall(8)](https://man.openbsd.org/autoinstall) configuration file including your public ssh key. -* Create and boot a copy-on-write disk image. - -## Prerequisites - -The script depends on the following tools: - -* [QEMU](https://www.qemu.org/) -* [curl](https://curl.haxx.se/) -* Portable [signify](https://github.com/aperezdc/signify) -* [rsync](https://rsync.samba.org/) -* Portable [OpenSSH](https://www.openssh.com/portable.html) -* [socat](http://www.dest-unreach.org/socat/) - -The following command installs these dependencies on Arch Linux: - - sudo pacman -S qemu curl signify rsync openssh socat - -## Usage - -Execute the following command to auto-install OpenBSD/amd64 6.7 to a new disk -image `disk.qcow2` in the current directory. - - ./run - -When prompted, run the following command to serve `./mirror/` at -http://127.0.0.1:8080/: - - python -m http.server --directory ./mirror --bind 127.0.0.1 8080 - -You can override the following environment variable defaults if necessary: - -* `DISK_FILE=disk.qcow2` -* `DISK_SIZE=160G` -* `CPU_COUNT=6` -* `MEMORY_SIZE=4G` - -For example: - - CPU_COUNT=1 ./run - -## Virtual network - -The script creates a virtual network, `10.0.2.0/24`, with the following -addresses: - -* Host at `10.0.2.2` -* Nameserver at `10.0.2.3` -* Guest at `10.0.2.15` - -The script also redirects host host port `2222` to guest port `22` (ssh) and -host port `80` (actually `10.0.2.1` port `80`) to host port `8080`. - -## Secure shell - -Pass the following options to ssh or scp to connect to the guest machine: - - ssh \ - -o "StrictHostKeyChecking no" \ - -o "UserKnownHostsFile /dev/null" \ - -o "Port 2222" \ - puffy@127.0.0.1 - -For example, the following command forwards port `3000` on the host to port -`80` on the guest: - - ssh \ - -o "StrictHostKeyChecking no" \ - -o "UserKnownHostsFile /dev/null" \ - -o "Port 2222" \ - -N \ - -L 127.0.0.1:3000:127.0.0.1:80 \ - puffy@127.0.0.1 - -Press `C-a x` to stop the guest machine. -Press `C-a h` to show other options. +See [blog post](https://www.skreutz.com/posts/autoinstall-openbsd-on-qemu/). diff --git a/autoinstall-openbsd-on-qemu b/autoinstall-openbsd-on-qemu new file mode 100755 index 0000000..d71a3dc --- /dev/null +++ b/autoinstall-openbsd-on-qemu @@ -0,0 +1,225 @@ +#! /bin/sh + +# Auto-install OpenBSD/amd64 6.7 on QEMU. +# +# First published at https://www.skreutz.com/posts/autoinstall-openbsd-on-qemu/ +# on 22 July 2020. +# +# Copyright (c) 2020 Stefan Kreutz +# +# Permission to use, copy, modify, and distribute this software for any purpose +# with or without fee is hereby granted, provided that the above copyright +# notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +# PERFORMANCE OF THIS SOFTWARE. + +set -o errexit +set -o nounset + +# Trusted HTTPS OpenBSD mirror to fetch the base public key from. +HTTPS_MIRROR="${HTTPS_MIRROR-https://ftp.openbsd.org/pub/OpenBSD/}" + +# Untrusted rsync OpenBSD mirror. +RSYNC_MIRROR="${RSYNC_MIRROR-rsync://ftp.halifax.rwth-aachen.de/openbsd/}" + +# File name of the disk image. +DISK_FILE="${DISK_FILE-disk.qcow2}" + +# Size of the disk image. +DISK_SIZE="${DISK_SIZE-24G}" + +# Number of virtual CPUs. +CPU_COUNT="${CPU_COUNT-4}" + +# Size of virtual memory. +MEMORY_SIZE="${MEMORY_SIZE-4G}" + +# File name of the public SSH key to authorize. +SSH_KEY="${SSH_KEY-${HOME}/.ssh/id_rsa.pub}" + +# Check required commands. +for cmd in curl qemu-img qemu-system-x86_64 rsync signify socat ssh +do + if ! command -v "${cmd}" >/dev/null + then + ( >&2 printf "command not found: %s\\n" "${cmd}" ) + exit 1 + fi +done + +# Fetch base public key from trusted HTTPS mirror. +mkdir -p mirror/pub/OpenBSD/6.7 +if [ ! -e mirror/pub/OpenBSD/6.7/openbsd-67-base.pub ] +then + curl \ + --silent \ + --output mirror/pub/OpenBSD/6.7/openbsd-67-base.pub \ + "${HTTPS_MIRROR}6.7/openbsd-67-base.pub" + printf "Fetched base public key from %s\\n" "${HTTPS_MIRROR}" +fi + +# Fetch kernel, PXE bootstrap program, and file sets from untrusted rsync +# mirror. +if [ ! -d mirror/pub/OpenBSD/6.7/amd64 ] +then + mkdir -p tmp + printf "Fetching installation files ...\\n" + rsync --archive --files-from=- --quiet \ + "${RSYNC_MIRROR}6.7/amd64/" \ + tmp/ \ + << EOF +SHA256.sig +base67.tgz +bsd +bsd.mp +bsd.rd +comp67.tgz +game67.tgz +man67.tgz +pxeboot +xbase67.tgz +xfont67.tgz +xserv67.tgz +xshare67.tgz +EOF + ( cd tmp && signify -C -q \ + -p ../mirror/pub/OpenBSD/6.7/openbsd-67-base.pub \ + -x SHA256.sig \ + -- bsd bsd.* pxeboot *67.tgz ) + mv tmp mirror/pub/OpenBSD/6.7/amd64 + printf "Fetched kernel, PXE bootstrap program, and file sets from %s\\n" "${RSYNC_MIRROR}" +fi + +# Create autoinstall(8) configuration if not exists. +if [ ! -e mirror/install.conf ] +then + cat << EOF > mirror/install.conf +Change the default console to com0 = yes +Which speed should com0 use = 115200 +System hostname = openbsd +Password for root = ************* +Allow root ssh login = no +Setup a user = puffy +Password for user = ************* +Public ssh key for user = $( cat "${SSH_KEY}" ) +What timezone are you in = UTC +Location of sets = http +HTTP Server = 10.0.2.1 +Unable to connect using https. Use http instead = yes +URL to autopartitioning template for disklabel = http://10.0.2.1/disklabel +Set name(s) = site67.tgz +Checksum test for site67.tgz failed. Continue anyway = yes +Unverified sets: site67.tgz. Continue without verification = yes +EOF + printf "Created example response file for autoinstall(8) at ./mirror/install.conf\\n" +fi + +# Create disklabel(8) configuration if not exists. +if [ ! -e mirror/disklabel ] +then + cat << EOF > mirror/disklabel +/ 2G +swap 8G +/tmp 1G +/var 1G +/usr 2G +/usr/X11R6 500M +/usr/local 4G +/usr/src 1M +/usr/obj 1M +/home 4G +EOF + printf "Created example disklabel(8) template at ./mirror/disklabel.conf\\n" +fi + +# Create site-specific file set if not exists. +if [ ! -d site ] +then + mkdir site + cat << EOF > site/install.site +#! /bin/ksh + +set -o errexit + +# Reset OpenBSD mirror server used by pkg_add(1) and other commands. +echo "https://cdn.openbsd.org/pub/OpenBSD" > /etc/installurl + +# Permit user group wheel to run any command as root without entering their +# password using doas(1). +echo "permit nopass keepenv :wheel" > /etc/doas.conf + +# Patch the base system on the first boot. +#echo "syspatch && shutdown -r now" >> /etc/rc.firsttime +EOF + chmod +x site/install.site + printf "Created example site-specific file set at ./site\\n" +fi + +# Package site-specific file set if not exists or changed. +site_dir_changed="$( find site -exec stat -c %Y {} \; | sort -r | head -n 1 )" +if [ ! -e mirror/pub/OpenBSD/6.7/amd64/site67.tgz ] || [ "$( stat -c %Y mirror/pub/OpenBSD/6.7/amd64/site67.tgz )" -lt "${site_dir_changed}" ] +then + rm -f mirror/pub/OpenBSD/6.7/amd64/site67.tgz + ( cd site && tar -czf ../mirror/pub/OpenBSD/6.7/amd64/site67.tgz . ) + ( cd mirror/pub/OpenBSD/6.7/amd64 && ls -l > index.txt ) +fi + +# Create TFTP directory if not exists. +if [ ! -d tftp ] +then + mkdir tftp + ln -s ../mirror/pub/OpenBSD/6.7/amd64/pxeboot tftp/auto_install + ln -s ../mirror/pub/OpenBSD/6.7/amd64/bsd.rd tftp/bsd.rd + mkdir tftp/etc + cat << EOF > tftp/etc/boot.conf +stty com0 115200 +set tty com0 +boot tftp:/bsd.rd +EOF + printf "Created example boot(8) configuration at ./tftp/etc/boot.conf\\n" +fi + +# Remove existing disk image if configuration changed. +if [ -e "${DISK_FILE}" ] +then + vm_created="$( stat -c %W "${DISK_FILE}" )" + for f in mirror/install.conf mirror/disklabel mirror/pub/OpenBSD/6.7/amd64/site67.tgz tftp/etc/boot.conf + do + if [ "${vm_created}" -lt "$( stat -c %Y "$f" )" ] + then + printf "Re-creating virtual machine due to changed configuration: %s\\n" "$f" + rm "${DISK_FILE}" + fi + done +fi + +# Create disk image if not exists. +if [ ! -e "${DISK_FILE}" ] +then + qemu-img create -q -f qcow2 "${DISK_FILE}" "${DISK_SIZE}" + printf "Created %s copy-on-write disk image at %s\\n" "${DISK_SIZE}" "${DISK_FILE}" +fi + +# Wait until ./mirror is served at http://127.0.0.1:8080/. +while [ ! "$( curl --silent --location --write-out '%{http_code}\n' --output /dev/null http://127.0.0.1:8080/install.conf )" = 200 ] +do + ( >&2 printf "Please serve the directory ./mirror at http://127.0.0.1:8080/\n" ) + sleep 5 +done + +# Auto-install OpenBSD. +printf "Starting virtual machine ...\\n" +qemu-system-x86_64 \ + -enable-kvm \ + -smp "cpus=${CPU_COUNT}" \ + -m "${MEMORY_SIZE}" \ + -drive "file=${DISK_FILE},media=disk,if=virtio" \ + -device e1000,netdev=n1 \ + -netdev "user,id=n1,hostname=openbsd-vm,tftp-server-name=10.0.2.1,tftp=tftp,bootfile=auto_install,hostfwd=tcp::2222-:22,guestfwd=tcp:10.0.2.1:80-cmd:socat STDIO TCP4:127.0.0.1:8080" \ + -nographic diff --git a/run b/run deleted file mode 100755 index 9a0a3b8..0000000 --- a/run +++ /dev/null @@ -1,180 +0,0 @@ -#! /bin/sh - -# Auto-install OpenBSD/amd64 6.7 on QEMU. -# -# Copyright (c) 2020 Stefan Kreutz - -set -o errexit -set -o nounset - -# Accept parameters from environment. -SSH_KEY="${SSH_KEY-${HOME}/.ssh/id_rsa.pub}" -HTTPS_MIRROR="${HTTPS_MIRROR-https://ftp.openbsd.org/pub/OpenBSD/}" -RSYNC_MIRROR="${RSYNC_MIRROR-rsync://ftp.halifax.rwth-aachen.de/openbsd/}" -DISK_FILE="${DISK_FILE-disk.qcow2}" -DISK_SIZE="${DISK_SIZE-24G}" -CPU_COUNT="${CPU_COUNT-4}" -MEMORY_SIZE="${MEMORY_SIZE-4G}" - -# Fail early on missing dependencies. -for cmd in qemu-img qemu-system-x86_64 curl signify rsync ssh socat -do - if ! command -v "${cmd}" >/dev/null - then - ( >&2 printf "command not found: %s\\n" "${cmd}" ) - exit 1 - fi -done - -# Fetch base public key from trusted HTTPS mirror. -mkdir -p mirror/pub/OpenBSD/6.7 -if [ ! -e mirror/pub/OpenBSD/6.7/openbsd-67-base.pub ] -then - curl \ - --silent \ - --output mirror/pub/OpenBSD/6.7/openbsd-67-base.pub \ - "${HTTPS_MIRROR}6.7/openbsd-67-base.pub" - printf "Fetched base public key from %s\\n" "${HTTPS_MIRROR}" -fi - -# Fetch kernel, PXE bootstrap program, and file sets from untrusted rsync -# mirror. -if [ ! -d mirror/pub/OpenBSD/6.7/amd64 ] -then - mkdir -p tmp - printf "Fetching installation files ...\\n" - rsync --recursive --delete --quiet \ - "${RSYNC_MIRROR}6.7/amd64/SHA256" \ - "${RSYNC_MIRROR}6.7/amd64/SHA256.sig" \ - "${RSYNC_MIRROR}6.7/amd64/bsd" \ - "${RSYNC_MIRROR}6.7/amd64/bsd.*" \ - "${RSYNC_MIRROR}6.7/amd64/pxeboot" \ - "${RSYNC_MIRROR}6.7/amd64/*67.tgz" \ - tmp/ - ( cd tmp && signify -C -q \ - -p ../mirror/pub/OpenBSD/6.7/openbsd-67-base.pub \ - -x SHA256.sig \ - -- bsd bsd.* pxeboot *67.tgz ) - mv tmp mirror/pub/OpenBSD/6.7/amd64 - printf "Fetched kernel, PXE bootstrap program, and file sets from %s\\n" "${RSYNC_MIRROR}" -fi - -# Create autoinstall configuration if not exists. -if [ ! -e mirror/install.conf ] -then - cat << EOF > mirror/install.conf -Change the default console to com0 = yes -Which speed should com0 use = 115200 -System hostname = openbsd -Password for root = ************* -Allow root ssh login = no -Setup a user = puffy -Password for user = ************* -Public ssh key for user = $( cat "${SSH_KEY}" ) -What timezone are you in = UTC -Location of sets = http -HTTP Server = 10.0.2.1 -Unable to connect using https. Use http instead = yes -URL to autopartitioning template for disklabel = http://10.0.2.1/disklabel -Set name(s) = site67.tgz -Checksum test for site67.tgz failed. Continue anyway = yes -Unverified sets: site67.tgz. Continue without verification = yes -EOF - printf "Created example response file for autoinstall(8) at ./mirror/install.conf\\n" -fi - -# Create disklabel configuration if not exists. -if [ ! -e mirror/disklabel ] -then - cat << EOF > mirror/disklabel -/ 2G -swap 8G -/tmp 1G -/var 1G -/usr 2G -/usr/X11R6 500M -/usr/local 4G -/usr/src 1M -/usr/obj 1M -/home 4G -EOF - printf "Created example disklabel(8) template at ./mirror/disklabel.conf\\n" -fi - -# Create site-specific file set if not exists. -if [ ! -d site ] -then - mkdir site - cat << EOF > site/install.site -#! /bin/ksh -set -o errexit -echo "https://cdn.openbsd.org/pub/OpenBSD" > /etc/installurl -echo "permit nopass keepenv :wheel" > /etc/doas.conf -#echo "syspatch && shutdown -r now" >> /etc/rc.firsttime -EOF - chmod +x site/install.site - printf "Created example site-specific file set at ./site\\n" -fi - -# Package site-specific file set if not exists or changed. -site_dir_changed="$( find site -exec stat -c %Y {} \; | sort -r | head -n 1 )" -if [ ! -e mirror/pub/OpenBSD/6.7/amd64/site67.tgz ] || [ "$( stat -c %Y mirror/pub/OpenBSD/6.7/amd64/site67.tgz )" -lt "${site_dir_changed}" ] -then - rm -f mirror/pub/OpenBSD/6.7/amd64/site67.tgz - ( cd site && tar -czf ../mirror/pub/OpenBSD/6.7/amd64/site67.tgz . ) - ( cd mirror/pub/OpenBSD/6.7/amd64 && ls -l > index.txt ) -fi - -# Create TFTP directory if not exists. -if [ ! -d tftp ] -then - mkdir tftp - ln -s ../mirror/pub/OpenBSD/6.7/amd64/pxeboot tftp/auto_install - ln -s ../mirror/pub/OpenBSD/6.7/amd64/bsd.rd tftp/bsd.rd - mkdir tftp/etc - cat << EOF > tftp/etc/boot.conf -stty com0 115200 -set tty com0 -boot tftp:/bsd.rd -EOF - printf "Created example boot(8) configuration at ./tftp/etc/boot.conf\\n" -fi - -# Remove existing disk image if configuration changed. -if [ -e "${DISK_FILE}" ] -then - vm_created="$( stat -c %W "${DISK_FILE}" )" - for f in mirror/install.conf mirror/disklabel mirror/pub/OpenBSD/6.7/amd64/site67.tgz tftp/etc/boot.conf - do - if [ "${vm_created}" -lt "$( stat -c %Y "$f" )" ] - then - printf "Re-creating virtual machine due to changed configuration: %s\\n" "$f" - rm "${DISK_FILE}" - fi - done -fi - -# Create disk image if not exists. -if [ ! -e "${DISK_FILE}" ] -then - qemu-img create -q -f qcow2 "${DISK_FILE}" "${DISK_SIZE}" - printf "Created %s copy-on-write disk image at %s\\n" "${DISK_SIZE}" "${DISK_FILE}" -fi - -# Wait until ./mirror is served at http://127.0.0.1:8080/. -while [ ! "$( curl --silent --location --write-out '%{http_code}\n' --output /dev/null http://127.0.0.1:8080/install.conf )" = 200 ] -do - ( >&2 printf "Please serve the directory ./mirror at http://127.0.0.1:8080/\n" ) - sleep 5 -done - -# Auto-install OpenBSD. -printf "Starting virtual machine ...\\n" -qemu-system-x86_64 \ - -enable-kvm \ - -m "${MEMORY_SIZE}" \ - -smp "cpus=${CPU_COUNT}" \ - -device e1000,netdev=n1 \ - -netdev "user,id=n1,hostname=openbsd-vm,tftp-server-name=10.0.2.1,tftp=tftp,bootfile=auto_install,hostfwd=tcp::2222-:22,guestfwd=tcp:10.0.2.1:80-cmd:socat STDIO TCP4:127.0.0.1:8080" \ - -drive "file=${DISK_FILE},media=disk,if=virtio" \ - -nographic -- cgit v1.2.3