From fc15f9e66f790137e0c2e9c1ab1c759d10d12d44 Mon Sep 17 00:00:00 2001 From: Stefan Kreutz Date: Sun, 31 May 2020 18:11:30 +0200 Subject: Review --- .gitignore | 6 +- README.md | 89 ++++++++++++++++++++++ boot.conf | 3 - disklabel | 11 --- install.conf | 15 ---- install.site | 5 -- run | 235 +++++++++++++++++++++++++++++++---------------------------- 7 files changed, 217 insertions(+), 147 deletions(-) create mode 100644 README.md delete mode 100644 boot.conf delete mode 100644 disklabel delete mode 100644 install.conf delete mode 100755 install.site diff --git a/.gitignore b/.gitignore index c5110f7..872a24b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -.openbsd-vm -openbsd-vm.qcow2 +mirror +tftp +site +disk.qcow2 diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4b40bc --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# Auto-install OpenBSD on QEMU + +This repository hosts a POSIX shell script to auto-install OpenBSD/amd64 6.6 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.6 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. diff --git a/boot.conf b/boot.conf deleted file mode 100644 index b7daacc..0000000 --- a/boot.conf +++ /dev/null @@ -1,3 +0,0 @@ -stty com0 115200 -set tty com0 -boot tftp:/bsd.rd diff --git a/disklabel b/disklabel deleted file mode 100644 index eb4c5ea..0000000 --- a/disklabel +++ /dev/null @@ -1,11 +0,0 @@ -/ 2G -swap 8G -/tmp 1G -/var 1G -/var/www 100G -/usr 2G -/usr/X11R6 500M -/usr/local 4G -/usr/src 1M -/usr/obj 1M -/home 4G diff --git a/install.conf b/install.conf deleted file mode 100644 index a417f93..0000000 --- a/install.conf +++ /dev/null @@ -1,15 +0,0 @@ -Change the default console to com0 = yes -Which speed should com0 use = 115200 -System hostname = openbsd-vm -Password for root = ************* -Allow root ssh login = no -Setup a user = puffy -Password for user = ************* -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) = site66.tgz -Checksum test for site66.tgz failed. Continue anyway = yes -Unverified sets: site66.tgz. Continue without verification = yes diff --git a/install.site b/install.site deleted file mode 100755 index 512974f..0000000 --- a/install.site +++ /dev/null @@ -1,5 +0,0 @@ -#! /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 diff --git a/run b/run index 55ea44f..a4400af 100755 --- a/run +++ b/run @@ -1,46 +1,6 @@ #! /bin/sh -# Auto-install OpenBSD/amd64 6.6 to a QEMU guest machine. -# -# Run the following command to serve the OpenBSD mirror at -# http://127.0.0.1:8080: -# -# python3 -m http.server \ -# --directory ./openbsd-vm/mirror \ -# --bind 127.0.0.1 8080 -# -# 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 8080 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:8080: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. -# -# The virtual network: -# -# network = 10.0.2.0/24 -# host = 10.0.2.2 -# nameserver = 10.0.2.3 -# guest = 10.0.2.15-31 -# -# Port forwardings: -# -# 10.0.2.1:80 -> host:8080 -# host:2222 -> guest:22 +# Auto-install OpenBSD/amd64 6.6 to a copy-on-write disk image using QEMU. # # Copyright (c) 2020 Stefan Kreutz @@ -48,97 +8,150 @@ set -o errexit set -o nounset set -o xtrace -# Set parameters. -VM_FILE="${VM_FILE-openbsd-vm.qcow2}" +# Set default parameters. +DISK_FILE="${DISK_FILE-disk.qcow2}" DISK_SIZE="${DISK_SIZE-160G}" CPU_COUNT="${CPU_COUNT-6}" MEMORY_SIZE="${MEMORY_SIZE-4G}" -# Remove existing virtual machine if configuration changed. -if [ -e "${VM_FILE}" ] ; +# Check dependencies. +for cmd in qemu-img qemu-system-x86_64 curl signify rsync ssh socat ; +do + command -v "${cmd}" +done + +# Download and verify official installation image and file sets. +mkdir -p mirror/pub/OpenBSD/6.6 +if [ ! -e mirror/pub/OpenBSD/6.6/openbsd-66-base.pub ] ; then - vm_created="$( stat -c %W "${VM_FILE}" )" - for f in boot.conf disklabel install.conf install.site - do - if [ "${vm_created}" -lt "$( stat -c %Y "$f" )" ] ; - then - ( >&2 printf "%s changed. Recreating virtual machine." "$f" ) - rm "${VM_FILE}" - fi - done + curl \ + --output mirror/pub/OpenBSD/6.6/openbsd-66-base.pub \ + --silent \ + https://ftp.openbsd.org/pub/OpenBSD/6.6/openbsd-66-base.pub +fi +if [ ! -d mirror/pub/OpenBSD/6.6/amd64 ] ; +then + mkdir -p tmp + rsync --recursive --delete --quiet \ + rsync://ftp.halifax.rwth-aachen.de/openbsd/6.6/amd64/ \ + tmp/ + ( cd tmp && \ + signify -C -q -p ../mirror/pub/OpenBSD/6.6/openbsd-66-base.pub -x SHA256.sig ) + mv tmp mirror/pub/OpenBSD/6.6/amd64 fi -if [ ! -e "${VM_FILE}" ] ; +# Create autoinstall configuration if not exists. +if [ ! -e mirror/install.conf ] ; then + ssh_pub_key="$( cat ~/.ssh/id_rsa.pub )" + 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 = ${ssh_pub_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) = site66.tgz +Checksum test for site66.tgz failed. Continue anyway = yes +Unverified sets: site66.tgz. Continue without verification = yes +EOF +fi - # Download and verify OpenBSD/amd64 6.6 installation images and file sets. - mkdir -p .openbsd-vm/mirror/pub/OpenBSD/6.6 - if [ ! -e .openbsd-vm/mirror/pub/OpenBSD/6.6/openbsd-66-base.pub ] ; - then - curl \ - --output .openbsd-vm/mirror/pub/OpenBSD/6.6/openbsd-66-base.pub \ - --silent \ - https://ftp.openbsd.org/pub/OpenBSD/6.6/openbsd-66-base.pub - fi - if [ ! -d .openbsd-vm/mirror/pub/OpenBSD/6.6/amd64 ] ; - then - mkdir -p .openbsd-vm/tmp - rsync --recursive --delete --quiet \ - rsync://ftp.halifax.rwth-aachen.de/openbsd/6.6/amd64/ \ - .openbsd-vm/tmp/ - ( cd .openbsd-vm/tmp && \ - signify -C -q -p ../mirror/pub/OpenBSD/6.6/openbsd-66-base.pub -x SHA256.sig ) - mv .openbsd-vm/tmp .openbsd-vm/mirror/pub/OpenBSD/6.6/amd64 - fi +# Create disklabel configuration if not exists. +if [ ! -e mirror/disklabel ] ; +then + cat << EOF > mirror/disklabel +/ 2G +swap 8G +/tmp 1G +/var 1G +/var/www 100G +/usr 2G +/usr/X11R6 500M +/usr/local 4G +/usr/src 1M +/usr/obj 1M +/home 4G +EOF +fi - # Create site-specific file set. - if [ ! -x install.site ] ; - then - chmod +x install.site - fi - rm -f .openbsd-vm/mirror/pub/OpenBSD/6.6/amd64/site66.tgz - tar -czf .openbsd-vm/mirror/pub/OpenBSD/6.6/amd64/site66.tgz install.site - ( cd .openbsd-vm/mirror/pub/OpenBSD/6.6/amd64 && ls -l > index.txt ) +# 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 +fi - # Add public ssh key to install.conf. - cp install.conf .openbsd-vm/mirror/ - if ! grep -q -e "^Public ssh key for user" install.conf ; - then - ssh_pub_key="$( cat ~/.ssh/id_rsa.pub )" - echo "Public ssh key for user = ${ssh_pub_key}" \ - >> .openbsd-vm/mirror/install.conf - 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.6/amd64/site66.tgz ] || [ "$( stat -c %Y mirror/pub/OpenBSD/6.6/amd64/site66.tgz )" -lt "${site_dir_changed}" ] ; +then + rm -f mirror/pub/OpenBSD/6.6/amd64/site66.tgz + ( cd site && tar -czf ../mirror/pub/OpenBSD/6.6/amd64/site66.tgz . ) + ( cd mirror/pub/OpenBSD/6.6/amd64 && ls -l > index.txt ) +fi - # Copy disklabel template. - cp disklabel .openbsd-vm/mirror/ +# Create TFTP directory if not exists. +if [ ! -d tftp ] ; +then + mkdir tftp + ln -s ../mirror/pub/OpenBSD/6.6/amd64/pxeboot tftp/auto_install + ln -s ../mirror/pub/OpenBSD/6.6/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 +fi - # Wait until the HTTP server is online. - # - while [ ! "$( curl --silent --location --write-out '%{http_code}\n' --output /dev/null http://127.0.0.1:8080/install.conf )" = 200 ] ; +# 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.6/amd64/site66.tgz tftp/etc/boot.conf do - ( >&2 printf "Please serve the directory ./openbsd-vm/mirror at http://127.0.0.1:8080.\n" ) - sleep 5 + if [ "${vm_created}" -lt "$( stat -c %Y "$f" )" ] ; + then + ( >&2 printf "%s changed. Recreating virtual machine." "$f" ) + rm "${DISK_FILE}" + fi done +fi - # Collect files to be served over TFTP. - rm -rf .openbsd-vm/tftp - mkdir .openbsd-vm/tftp - ln -s ../mirror/pub/OpenBSD/6.6/amd64/pxeboot .openbsd-vm/tftp/auto_install - ln -s ../mirror/pub/OpenBSD/6.6/amd64/bsd.rd .openbsd-vm/tftp/bsd.rd - mkdir .openbsd-vm/tftp/etc - cp boot.conf .openbsd-vm/tftp/etc/ - - # Create copy-on-write disk image. - qemu-img create -f qcow2 "${VM_FILE}" "${DISK_SIZE}" - +# Create disk image if not exists. +if [ ! -e "${DISK_FILE}" ] ; +then + qemu-img create -f qcow2 "${DISK_FILE}" "${DISK_SIZE}" fi -# Auto-install guest machine. +# 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. 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=.openbsd-vm/tftp,bootfile=auto_install,hostfwd=tcp::2222-:22,guestfwd=tcp:10.0.2.1:80-cmd:socat - tcp:127.0.0.1:8080" \ - -drive "file=${VM_FILE},media=disk,if=virtio" \ + -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 - tcp:127.0.0.1:8080" \ + -drive "file=${DISK_FILE},media=disk,if=virtio" \ -nographic -- cgit v1.2.3