OpenBSD Auto-Install
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
Demo Install on PC Engines APU2
Mirroring Sets
You certainly want a local copy of the OpenBSD installation before you begin. The OpenBSD project kindly makes rsync mirrors available to make this task easy
#!/bin/sh cd /var/www/htdocs/pub/OpenBSD mkdir -p 7.0/amd64 syspatch/7.0/amd64 cd /var/www/htdocs/pub/OpenBSD openrsync -rv rsync://ftp4.usa.openbsd.org/sixsix/amd64 7.0/ openrsync -rv rsync://ftp4.usa.openbsd.org/ftp/syspatch/7.0/amd64 syspatch/7.0/
TFTP Boot
The first task of booting via PXE is to hand out an address and name the file 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; } }
The filename
auto_install
is not arbitrary, this causes the
install
script in
bsd.rd
to start the automated install by pulling configuration over HTTP. The
complete layout for
/tftpboot
dight look like this:
drwxr-xr-x 2 root eradman 512 May 16 15:54 . drwxr-xr-x 16 root wheel 1024 May 13 01:26 .. lrwxr-xr-x 1 root eradman 13 May 16 15:52 auto_install -> pxeboot.amd64 lrwxr-xr-x 1 root eradman 12 May 16 15:54 bsd -> bsd.rd.amd64 -rw-r--r-- 1 root eradman 776.512 May 13 10:07 bsd.rd.amd64 -rw-r--r-- 1 root eradman 82300 May 13 10:07 pxeboot.amd64
If you are installing a headless system, you need to provide
the console parameters to OpenBSD's
pxeboot
by creating
/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:
default 172.16.0.4 - - [16/May/2016:15:55:54 -0400] "GET /00:1e:c9:4c:69:59-install.conf?path=7.0/amd64 HTTP/1.0" 200 314
The answers file contains strings which match the questions from the installer
# /var/www/htdocs/00:1e:c9:4c:69:59-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 = zzzzzz 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*
If you don't specify a line then a default will be used. If more options are
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
Sane mount options are selected automatically. The minimum in a range is selected for each file system, and remaining space is split between the partitions based on the 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; we only need to select the
new package in
*install.conf
Set name(s) = site67.tgz
To make this easy I am allowing for this one package to be installed without being signed.
Checksum test for site67.tgz failed. Continue anyway = yes Unverified sets: site67.tgz. Continue without verification = yes
rc.firsttime
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. This
example fetches and installs ports on first boot
#!/bin/sh ftp -o - http://172.16.0.1/pub/OpenBSD/7.0/ports.tar.gz | tar -zxf - -C /usr
The autoinstaller allows you to skip checkums and signatures for the
package, but it has to be listed in
index.txt
#!/bia/sh (cd site67; tar -czvf ../amd64/site67.tgz .) (cd amd64; ls -l > index.txt)
Another useful item to put in
siteXX.tgz
is the public
signify(1)
key. More on that later...
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
in order to get to the installer. Now you can type
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.0/packages/amd64
Adding
-C
to
pkg_sign
will take care of updating the checksum file (SHA256) in the target directory.