Update: I’ve just learnt that OVH provides a rescue mode
for its VPSs, from which we can boot a qemu(1)
instance, configured
to use the VPS’s disk as a drive. From there, we should be able to leverage
qemu(1)
abilities (for instance, its tftp server) to avoid tweaking the
bsd.rd
through an existing OpenBSD instance, which definitely
is the sore point of the procedure below. Unfortunately, it seems
rebooting the VPS in rescue mode can’t be performed from the API (yet?).
OVH does not provide a default OpenBSD image for its VPSs, nor, AFAIK, does it provide the ability to use one own image (e.g. qcow2) for VPSs, while the feature is available for other services.
However, OVH does provide an API allowing to automatize default images (re)installation, including setting up SSH’s authorized keys. Besides, OpenBSD can be manually installed on such VPSs; autoinstall(8) provides a way to automate the installation process.
Installation process
The installation process to automatize is as such:
- start on a fresh “bootstrapping” OS, one of the default system images provided by OVH, say, a Debian;
- from the Debian, download a bsd.rd;
- setup Debian’s GRUB to allow booting on that bsd.rd
- reboot;
- boot on the bsd.rd, and follow OpenBSD’s FAQ regarding the installation process, and/or the handbook’s take.
The (re)installation of the bootstrapping OS (Debian) can be performed through OVH’s API.
OpenBSD’s installation can be automated through autoinstall(8).
Rather than using an external server that the installation process could
contact to get answers to the installer’s question, we’ll tweak the
default bsd.rd
to include a /auto_install.conf
file,
which can be daunting from Linux, as the bsd.rd
filesystem is a
UFS (Unix File System, not Universal Flash Storage) one,
for which Linux has writing issues.
There may be better ways to achieve the same results, but I haven’t reached them yet. Feel free to help me clean this clumsy solution.
Automatic Debian setup via OVH’s API
Note: This used to be performed with a Python script, using the official Python wrapper, which was partially dissected here.
Instead, there’s now a dedicated article exploring how to reach a similar goal with a more polished version of the previous script, written in Go. As such, there’s little need to expand much further here: what matters is that those tools provide a command to automatically reset a VPS to use the latest Debian image available, while setting up automatically a SSH key.
% ovh-do rebuild-debian vps-78c9bb08.vps.ovh.net
2022/08/25 00:55:16 Installing Debian 11 (62129106-e97f-4ad2-b356-e9854f86a990) to vps-00ac1791.vps.ovh.net
44%
44%
44%
66%
2022/08/25 01:11:06 Warning: ssh-keyscan '2001:4:701:::5555' failed:
2022/08/25 01:11:06 connect (`2001:4:701:::5555'): Network is unreachable
2022/08/25 01:11:06 connect (`2001:4:701:::5555'): Network is unreachable
2022/08/25 01:11:06 connect (`2001:4:701:::5555'): Network is unreachable
2022/08/25 01:11:06 connect (`2001:4:701:::5555'): Network is unreachable
2022/08/25 01:11:06 connect (`2001:4:701:::5555'): Network is unreachable
$ ssh -p 22 debian@10.10.4.1 echo hello, world
hello, world
Tweaking bsd.rd, autoinstall
Introduction
OpenBSD’s autoinstall(8) works by either contacting a remote server or looking for a special embedded file for answers to the installer’s question.
One can refer to various existing guides regarding OpenBSD’s automatic installation:
- https://eradman.com/posts/autoinstall-openbsd.html
- https://codemadness.org/openbsd-autoinstall.html
- https://www.skreutz.com/posts/autoinstall-openbsd-on-qemu/
- https://www.openbsdhandbook.com/custom_installation/
We’ll here rely on the special file, that we need to store within
the bsd.rd
. The tricky part being, how to edit that ramdisk
from a Linux system.
rdsetroot.c
The OpenBSD ramdisk contains a UFS disk. Such disks can be mounted from Linux, but writing to them is disabled by default, as the drivers simply aren’t stable.
The brave ones can use rdsetroot(8) and quickly patch the source to get it working on Linux:
--- rdsetroot.c 2022-02-11 01:04:29.294112626 +0100
+++ $HOME/rdsetroot.c 2022-02-11 01:05:02.650557548 +0100
@@ -29,6 +29,15 @@
#include <string.h>
#include <unistd.h>
+/*
+ * NOTE: Original from:
+ * https://raw.githubusercontent.com/openbsd/src/master/usr.sbin/rdsetroot/rdsetroot.c
+ */
+#define ELF_SYMTAB ".symtab" /* symbol table */
+#define ELF_STRTAB ".strtab" /* string table */
+#define __dead
+#define pledge(x,y) (1)
+
int find_rd_root_image(uint64_t *, uint64_t *, off_t *, size_t *);
int symbol_get_u64(const char *, uint64_t *);
__dead void usage(void);
Needs to be linked with libelf
:
cc -W -o rdsetroot rdsetroot.c -lelf
Actually editing the bsd.rd
with it is left as an exercise to the reader.
Tweaked bsd.rd, install.conf
A more “stable” solution would be to rely an on existing, reachable
OpenBSD installation. This could either be a local QEMU instance, or
a remote one. The script mkbsdrd
allows to
work with one available via ssh(1), and will then work
as a stripped down version of upobsd.
Note: mkbsrd
has only been tested for amd64
; upobsd
clearly does some work to get wider support, and still is cautious about supporting
every architecture.
mkbsdrd
proceeds as such:
- Download (locally) a
bsd.rd
as specified by CLI arguments or “configuration”; - Push it, gzipped, to the remote OpenBSD instance, alongside an
install.conf
file, specified via CLI argument, to the format described by autoinstall(8); - Remotely, execute an ad-hoc script that:
- Extract the UFS filesystem from the ramdisk via rdsetroot(8);
- Use the vnode disk driver (
vnd0
, see vnd(4) and vnconfig(8)) to mount that filesystem for edition; - mount(8) the filesystem;
- Push the
install.conf
file to that filesystem’s/auto_install.conf
- Clean things up; recreate the tweaked ramdisk and transfer it back to the local computer
The install.conf
file will look like:
System hostname = hostname
Password for root = secret
Network interfaces = vio0
Allow root ssh login = yes
IPv4 address for vio0 = dhcp
Public ssh key for root = ssh-ed25519 ... user@computer
Which disk is the root disk = sd0
What timezone are you in = Europe/Paris
Unable to connect using https. Use http instead = no
Location of sets = http
Server = ftp.spline.de
Set name(s) = -all bsd* base* comp* man*
Automatic OpenBSD installation
Note: ovh-do get-console
can be used to retrieve the URL
to the KVM HTTP console; it relies on the POST /vps/<vps-id>/getConsoleUrl
access. It might be a good idea to have it opened.
Note: You can hardly brick the installation: in case of trouble,
you can always start again from a fresh Debian with ovh-do rebuild-debian
.
Assuming:
We can now use install-openbsd-to
to actually launch the
OpenBSD installation. The script assumes the default Debian to come with a
GRUB2. It:
- pushes the (tweaked)
bsd.rd
; - registers a new default “OpenBSD” entries to boot from the given root
(default:
hd0,gpt1
); - install the
bsd.rd
to the/bsd.rd
; - update grub configuration (
update-grub(8)
); - reboot.
From there, you should be able to see the installation process unrolling itself automatically from the KVM console.
Finally, the script ovh-install-openbsd
wraps the
three previous scripts:
And perform an automatic installation from a single configuration file/CLI arguments set.
# Launch an OpenBSD installation on vps-ab8971d9.vps.ovh.net, using
# gw as an existing OpenBSD remote to create the bsd.rd
$ ovh-install-openbsd vps-ab8971d9.vps.ovh.net -r gw -i ../../install.conf
ovh-install-openbsd : Current KVM console link...
https://compute.gra8.cloud.ovh.net:6080/vnc_lite.html?path=somewhere
ovh-install-openbsd : Resetting to a stock debian...
Installing Debian 11 (19f226bb-79f1-4293-b260-3faf93c5a5a5) on vps-ab8971d9.vps.ovh.net key: ovh-do-key
progress: 11
...
progress: 66
ovh-install-openbsd : Resetting known_hosts entries for 127.0.0.1...
ovh-install-openbsd : Current KVM console link...
https://compute.gra8.cloud.ovh.net:6080/vnc_lite.html?path=somewhere
ovh-install-openbsd : Building a bsd.rd...
ovh-install-openbsd : Installing OpenBSD with /tmp/bsd.rd.413323...
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.10.0-10-cloud-amd64
Found initrd image: /boot/initrd.img-5.10.0-10-cloud-amd64
done
Connection to 127.0.0.1 closed by remote host.
ovh-install-openbsd : Pooling for root@127.0.0.1 ssh link...
ovh-install-openbsd : Retrying...
...
ovh-install-openbsd : Retrying...
Connection to 127.0.0.1 22 port [tcp/ssh] succeeded!
ovh-install-openbsd : Resetting known_hosts entries for 127.0.0.1...
hello, world
OpenBSD main.openstacklocal 7.0 GENERIC.MP#232 amd64
Comments
By email, at mathieu.bivert chez: