1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
---
title: "First release of installiso"
description: "A utility to customize OpenBSD installation images for unattended installation."
published: 2021-07-24
---
One year ago I [posted](/posts/autoinstall-openbsd-on-qemu/) how to script an unattended installation of OpenBSD on the QEMU virtual machine monitor on Linux.
The script involved setting up a complicated network boot environment because I treated the installation image as a black box.
Of course, I could have mounted the ISO 9660 image and created a modified image using [`mkisofs(8)`](http://cdrtools.sourceforge.net/private/man/cdrecord/mkisofs.8.html).
But I didn't know how to insert the [`autoinstall(8)`](https://man.openbsd.org/OpenBSD-6.9/autoinstall) response file into the RAMDISK kernel in the ISO 9660 image.
That was no surprise -- why would anyone need to change an OpenBSD kernel on Linux.
OpenBSD, on the other hand, includes adequate utilities.
Thanks to [`vmctl(8)`](https://man.openbsd.org/OpenBSD-6.9/vmctl), [`rdsetroot(8)`](https://man.openbsd.org/OpenBSD-6.9/rdsetroot), and [`mkhybrid(8)`](https://man.openbsd.org/OpenBSD-6.9/mkhybrid), we can modify the ISO 9660 image _and_ the contained RAMDISK kernel.
The exact process is a bit tedious so I decided to automate it.
The resulting script is more hacky than pretty but it gets the job done and I found it useful enough to give it a name, `installiso`, and release it today.
Currently, it's limited to the _amd64_ architecture, though it should work on other architectures alike.
You can download the very first release [here](/files/installiso-0.1.0.tar.gz).
The man page is also viewable [here](/files/installiso.8-0.1.0.html).
Feedback appreciated!
In the remainder of this post I'll show how to use `installiso` to create custom OpenBSD installation images for unattended -- and possibly offline -- installation.
As an example, I'll show how to create virtual machines on OpenBSD's own virtual machine monitor, [`vmm(4)`](https://man.openbsd.org/OpenBSD-6.9/vmm).
Finally, I'll list the concrete commands necessary to patch an installation image without `installiso` because I would want to know how it works.
## Installation
You can install the `installiso` utility as follows.
$ ftp https://www.skreutz.com/files/installiso-0.1.0.tar.gz
$ tar -xzf installiso-0.1.0.tar.gz
$ cd installiso-0.1.0/
$ doas make install
$ man 8 installiso
Alternatively, you can run `./installiso.ksh` without installation.
## Usage
Given a response file `install.conf`, and a file-specific file set `site/`, you can download, verify, and customize an official installation image as follows.
$ installiso -v fetch -r 6.9
$ doas installiso -v \
patch -i install.conf -s site/ install69.iso custom.iso
You can also specify a mirror, another release or the latest development snapshot, and a [`signify(1)`](https://man.openbsd.org/OpenBSD-6.9/signify) public key if you like.
See the [man page](/files/installiso.8-0.1.0.html).
## Example
You can create a virtual machine on OpenBSD's own virtual machine monitor, [`vmm(4)`](https://man.openbsd.org/OpenBSD-6.9/vmm), as follows.
First, we create an [`autoinstall(8)`](https://man.openbsd.org/OpenBSD-6.9/autoinstall) response file.
Here, we'll setup a regular user and authorize an [`ssh(1)`](https://man.openbsd.org/OpenBSD-6.9/ssh) public key.
Of course, you can skip this step and have the installer mail you the responses recorded during an interactive installation instead.
$ cat >install.conf <<EOF
Change the default console to com0 = yes
Which speed should com0 use = 115200
System hostname = openbsd-vm
DNS domain name = example.com
Password for root = *************
Start sshd(8) by default = yes
Allow root ssh login = no
Setup a user = $USER
Full name for user $USER = $( userinfo "$USER" | sed -n 's/^gecos[[:space:]]*\(.*\)$/\1/p' )
Password for user = *************
Public ssh key for user = $( cat "$HOME/.ssh/id_rsa.pub" )
What timezone are you in = UTC
Location of sets = cd0
Set name(s) = site*.tgz
Directory does not contain SHA256.sig. Continue without verification = yes
EOF
Second, we create a site-specific file set.
$ mkdir site
$ cat >site/install.site <<EOF
#! /bin/ksh
set -o errexit
# Set OpenBSD mirror server used by pkg_add(1) and other commands.
echo "$( grep -v -e '^#' -e '^[:space:]*$' /etc/installurl )" > /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
# Install packages on the first boot.
echo "pkg_add sqlite3" >> /etc/rc.firsttime
EOF
$ chmod +x site/install.site
Third, fetch and patch an installation image as above.
$ installiso -v fetch -r 6.9
$ doas installiso -v \
patch -i install.conf -s site/ install69.iso custom.iso
Forth, we start a virtual machine off a new disk image and the custom installation image.
The OpenBSD FAQ contains a good [introduction](https://www.openbsd.org/faq/faq16.html) to [`vmm(4)`](https://man.openbsd.org/OpenBSD-6.9/vmm).
I assume you've setup the network option 2.
$ vmctl create -s 10G disk.qcow2
$ doas vmctl start -c -i 1 -L -m 512M -d disk.qcow2 \
-r custom.iso tmp
Finally, we can log into the new virtual machine once the unattended installation has completed.
$ ssh \
-o "StrictHostKeyChecking no" \
-o "UserKnownHostsFile /dev/null" \
100.64.1.3
## Disklabel template
In the above example, the OpenBSD installer allocates all disk space automatically, see [`disklabel(8)`](https://man.openbsd.org/OpenBSD-6.9/disklabel).
You can supply a custom disklabel template instead if you need more control.
First, create a disklabel template.
$ cat >disklabel_template <<EOF
/ 5G
swap 1G
/home 2G
EOF
Second, add a corresponding URL to the response file.
$ echo "URL to autopartitioning template for disklabel = http://100.64.1.2:8080/disklabel_template" >> install.conf
Finally, serve the file during the unattended installation.
$ printf 'HTTP/1.0 200 OK\n\n' |
cat - disklabel_template |
nc -lN 8080
## Inner workings
The `installiso patch` command used above
$ doas installiso -v \
patch -i install.conf -s site/ install69.iso custom.iso
boils down to the following commands -- excluding error handling, temporary files, command-line options, etc.
First, we extract the ISO 9660 image.
# vnconfig vnd0 install69.iso
# mount -t cd9660 /dev/vnd0c /mnt
# mkdir cd
# tar -C /mnt -c -f - . | tar -C cd -x -p -f -
# umount /mnt
# vnconfig -u vnd0
Second, we patch the RAMDISK kernel.
# gzip -d -o bsd.rd cd/6.9/amd64/bsd.rd
# rdsetroot -x bsd.rd disk.fs
# vnconfig vnd0 disk.fs
# mount /dev/vnd0a /mnt
# install -o root -g wheel -m 0644 -C \
install.conf /mnt/auto_install.conf
# umount /mnt
# vnconfig -u vnd0
# rdsetroot bsd.rd disk.fs
# gzip -9fnq bsd.rd
Third, we insert the patched kernel and the site-specific file set into the extracted ISO 9660 image.
# install -o root -g 2000 -m 0755 -C \
bsd.rd.gz cd/6.9/amd64/bsd.rd
# ( cd site/ && tar -c -z -f ../cd/6.9/amd64/site69.tgz . )
# ( cd cd/6.9/amd64/ && ls -l > index.txt )
Finally, we create the bootable ISO 9660 image.
# mkhybrid -a -R -T -L -l -d -D -N -o custom.iso \
-A "Custom OpenBSD 6.9 amd64 Install CD" \
-b 6.9/amd64/cdbr -c 6.9/amd64/boot.catalog \
cd
|