Automated OpenBSD Installation
OpenBSD has a very good story for automated installations, which includes features such as:
- Boot parameters set on boot (example: switch to serial port)
- Configuration of network interfaces
- Partitioning & adaptive disklabels
- Selection and installation of base sets
- Custom site package that can contain arbitrary content
- Installation of non-root user with SSH public key
- Applying patches on first boot
Mirroring Sets
OpenBSD project kindly makes rsync mirrors available aid in mainting a local mirror
#!/bin/sh cd /var/www/htdocs/pub/OpenBSD mkdir -p 7.4/amd64 syspatch/7.4/amd64 cd /var/www/htdocs/pub/OpenBSD openrsync -rv rsync://ftp4.usa.openbsd.org/sevenone/amd64 7.4/ openrsync -rv rsync://ftp4.usa.openbsd.org/ftp/syspatch/7.4/amd64 syspatch/7.4/
TFTP Boot
The first task of booting via PXE is to hand out an address and filename to fetch over TFTP
# /etc/dhcpd.conf option domain-name "eradman.com"; option domain-name-servers 172.16.0.1; subnet 172.16.0.1 netmask 255.255.255.0 { option routers 172.16.0.1; host db1 { hardware ethernet fe:e1:bb:d1:cd:29; filename "auto_install"; next-server 172.16.0.1; option host-name "db1"; fixed-address 172.16.0.2; } host t460s { hardware ethernet c8:5b:76:0d:1c:f3; filename "efi/auto_install"; next-server 172.16.0.1; option host-name "t460s"; fixed-address 172.16.0.10; } }
A basic layout for
/tftpboot
may look like this:
|-- auto_install -> pxeboot |-- bsd -> bsd.rd |-- bsd.rd |-- efi | |-- BOOTX64.EFI | |-- auto_install -> BOOTX64.EFI `-- pxeboot
Where
pxeboot
is used for a BIOS boot, and
BOOTX64.EFI
is used for UEFI.
auto_install
is not an arbitrary filename: this triggers to the install in
bsd.rd
to start the automated install by pulling configuration over HTTP.
If the system is headless, console parameters may be provided in
/tftpboot/etc/boot.conf
stty com0 115200 set tty com0
Per-Host Install Options
The
next-server
entry specified by the DHCP server points to the path where answers file can
be found. This file contains strings which match the questions from the
installer
# /var/www/htdocs/fe:e1:bb:d1:cd:29-install.conf System hostname = db1 Password for root = 123456 Network interfaces = run0 IPv4 address for run0 = dhcp Setup a user = eradman Password for user eradman = 123456 Public ssh key for user = ssh-ed25519 XYZ123... eradman@t430s.eradman.com Which disk is the root disk = sd0 What timezone are you in = US/Eastern Unable to connect using https. Use http instead = yes Location of sets = http Server = 172.16.0.1 Set name(s) = -all bsd* base* etc* man* site* comp*
Plain text passwords are accepted, or generate encrypted passwords using
printf "123456" | encrypt
Partitioning
Custom partition layouts are documented under the disklabel(8) man page. This is all we need to add to the autoinstall script:
URL to autopartitioning template for disklabel = http://172.16.0.1/openbsd-pgdb.disklabel
Disklabel slices are calculated based on a minimum size within each range, then remaining space is split between the partitions based on a percentage:
/ 250M swap 80M-256M 10% /tmp 120M-4G 8% /var 80M-4G 13% /usr 900M-2G 5% /usr/local 2G-10G 10% /pg_data 1G-* 45%
Hotplug
To make this mechanism portable I run these services from my laptop. First I enable the hotplug daemon
# rcctl enable hotplugd
Next create
/etc/hotplug/attach
to add any USB-to-Ethernet adapter to a local bridge that is serving DHCP
requests
#!/bin/sh DEVCLASS=$1 DEVNAME=$2 case $DEVCLASS in 3) ifconfig $DEVNAME up ifconfig bridge0 add $DEVNAME ;; esac
Where
DEVCLASS 3
is a network interface. Similarly,
/etc/hotplug/detach
disables these services using the opposite actions.
Custom Sets
OpenBSD allows for custom software to be installed by adding a
site-specific tgz file.
If
index.txt
includs the new file it will appear in the menu.
To make this easy, verification for
siteNN.tgz
may be skipped
Checksum test for site71.tgz failed. Continue anyway = yes Unverified sets: site71.tgz. Continue without verification = yes
One of the most interesting files that can be installed with
siteNN.tgz
is
/etc/rc.firsttime
.
This is executed the first time a system boots up in multi-user mode, and is a
very convenient way to make sure some bits of essential post-install
configuration occur.
Autoinstalling OpenBSD on VMM
In addition to PXE-booting a bare-metal system we can install local VMs in almost the exact same manner. The first step is to define the VMs.
#/etc/vm.conf
switch "local" {
add vether0
up
}
vm "db1" {
disable
memory 512M
boot "/bsd.db1"
disk "/vm/db1.img"
interface {
switch "local"
lladdr fe:e1:bb:d1:cd:29
}
}
vm "db2" {
disable
memory 512M
boot "/bsd.db2"
disk "/vm/db2.img"
interface {
switch "local"
lladdr fe:e1:bb:d1:cd:30
}
}
VMM's
boot
option can be a BIOS or a kernel image. The trick to auto-installing a VM is
to temporarily swap in
bsd.rd
to get to the installer. Now use
vmctl start db1 -c
and press
A
.
We can have tmux automate this for us
#!/bin/sh -ex # reinstall-all.sh # - Reset all VMs # - Start each VM and select Autoinstall # - Set the boot kernel to bsd.sp for vm in $*; do ln -f /bsd.rd /bsd.$vm done rcctl restart vmd for vm in $*; do tmux new-session -s autoinstall -d tmux send-keys -t autoinstall:0 "doas vmctl start $vm -c" C-m sleep 10 tmux send-keys -t autoinstall:0 "A" C-m sleep 2 tmux kill-session -t autoinstall ln -f /bsd.sp /bsd.$vm done doas vmctl status
Signing Custom Packages
Once we can spin up fresh VMs or bare-metal installations we can build custom
packages without having to run
pkg_add
with
-Dunsigned
.
To do this we need to generate a signing key
signify -G -n -s /etc/signify/custombuild-pkg.sec -p /etc/signify/custombuild-pkg.pub
After building our custom packages sign each of them
pkg_sign -C -v \ -s signify2 -s /etc/signify/custombuild-pkg.sec \ -S /usr/ports/packages/amd64/all \ -o /var/www/htdocs/pub/OpenBSD/7.4/packages/amd64
Adding
-C
to
pkg_sign
will take care of updating the checksum file (SHA256) in the target directory.