image: light show

Having installed OpenBSD, one has to do a few more things to make a machine manageable by Ansible.

The one unavoidable task is to install python3. I also add a dedicated user for Ansible, hook into a local OpenBsd mirror, and patch.

To do this, I’ve written a set of scripts. The first script runs on the Ansible host. It collects any necessary configuration files, then runs the second script on the target.

That first script expects to find a directory called prep, which contains:

  • a file with the current user name, the new desired user name, and root, each of which contain the corresponding user password. Rather obviously, these files are protected.
  • A directory called init, containing the second script and some of the files that script requires. The first script will create more.

The script makes presumptions about directory locations. It requires the package sshpass to be installed on the Ansible server, which can be added using pkg_add.


set -e

if [[ "$6" == "" ]] ; then
  /bin/echo "IP machine ip address"
  /bin/echo "USER init file named for new user account containing password"
  /bin/echo "IF interface name for /etc/hostname.IF"
  /bin/echo "FILE file containing contents of new /etc/hostname.IF"
  /bin/echo "HOSTNAME new hostname"
  /bin/echo "COUNTRY two letter code for host country"
  return 3

if [[ ! -f "$4" ]] ; then
  /bin/echo cannot find $4.

if [[ ! -f "~/ansible/prep/init/profile.$6" ]] ; then
  /bin/echo cannot find ~/ansible/prep/init/profile.$6.

cd ~/ansible/prep

if [[ -f init.tgz ]] ; then
  rm -f init.tgz

/bin/cp -f "$4" init/hostname.$3
/bin/echo $6 >init/country
/bin/echo $5 >init/hn
/bin/echo $3 >init/if
/bin/echo $2 >init/user
#/bin/echo python-3.6.8p0 >init/package
/bin/echo python-3.7.4 >init/package
/bin/tar czf init.tgz init
/bin/rm -f init/hostname.$3 init/if init/user init/package

/bin/cat $USER | /usr/local/bin/sshpass /usr/bin/ssh -o StrictHostKeyChecking=accept-new $USER@$1 "/bin/rm -rf init init.tgz"
/bin/cat $USER | /usr/local/bin/sshpass /usr/bin/scp init.tgz "$USER@$1:."
/bin/rm init.tgz
/bin/cat $USER | /usr/local/bin/sshpass /usr/bin/ssh $USER@$1 "/bin/tar xzf init.tgz"
/bin/cat $USER | /usr/local/bin/sshpass /usr/bin/ssh $USER@$1 "/bin/cat init/authorized_keys.$USER >> .ssh/authorized_keys"
/bin/cat root | /usr/bin/ssh $USER@$1 /usr/bin/su root -c /home/$USER/init/

It’s fairly simple to use. Supply no parameters to see what it wants, and then use it, for example, as follows:

./ ansible em0 hostname.em0 lu

To be clear:

  1. The first parameter is the current IP address of the machine to be configured.
  2. The second is the name of the user to be created for use by ansible.
  3. The third is the network interface type and number which has to be configured before ansible can access the machine. This is often em0, but may be vio0, or sis0: there are many possibilities. It’s normally the extension of the HOSTNAME.IF file, which is described next.
  4. The fourth parameter is the full path, on the ansible server, of the HOSTNAME.IF file to be installed on the target server. The filename must be name of the HOSTNAME.IF to be installed in the /etc folder on the target machine, normally that created when OpenBSD was installed on that machine. As per my folder structure, it’ll probably be in the ansible/files/… folder. This file sets up the machine’s destination network address as used by ansible.
  5. The fifth parameter is the full domain name of the target machine.
  6. Finally, the sixth parameter is the country code of the target machine. The country code corresponds to a file called PROFILE.code, which contains any extra data to go in the new user’s .profile, such as exporting PKG_PATH to point to a local mirror. In fact, the parameter doesn’t have to be a country code, that’s just how I use it.

As you’ll see from the code above, this script prepares a package, puts it on the target machine, installs an SSH key, the runs a second script on the target machine.

Note that it assumes a specific version of python. That’s the standard version associated with my preferred version of OpenBSD (at the time of writing, 6.6).

Anyway, it runs a second script, which activates doas, configures the machine to use a nearby OpenBSD mirror, adds the Ansible account, adds authorised ssh keys to various accounts, patches OpenBSD, installs Python 3, sets up networking, and reboots the machine.

Once it has run, Ansible can carry out any additional configuration. Indeed, some of the tasks carried out by the script could be done by Ansible itself, such as patching, but I prefer to patch it as soon as I can. It’s not like it’s difficult!


RELEASE=`uname -r`
ARCH=`uname -m`

H=`cat init/hn`
I=`cat init/if`
U=`cat init/user`
A=`cat init/package`
L=`cat init/country`

/bin/echo $I $U $A $H

cp /etc/examples/doas.conf /etc
cat /home/$USER/init/authorized_keys.root >> /root/.ssh/authorized_keys
hostname $H
cat /home/$USER/init/profile.$L >> /home/$USER/.profile

if [[ "$U" != "" ]] ; then
  useradd -G wheel -m -c "additional user $U" -d /home/$U -p `cat /home/$USER/init/passwd.$U | encrypt` $U
  cat /home/$USER/init/authorized_keys.$U >> /home/$U/.ssh/authorized_keys
  cat /home/$USER/init/profile.$L >> /home/$U/.profile

pkg_add $A

if [[ -f "/home/$USER/init/hostname.$I" ]] ; then
  cp -f /home/$USER/init/hostname.$I /etc

rm -rf /home/$USER/init

/bin/echo "rebooting..."
/bin/sleep 1

Note that this script presumes to use the OpenBSD mirror hosted by the university in Aix–la–Chapelle, in Germany.

It would probably make more sense if I were set up automatic configuration when installing OpenBSD, rather than using these scripts, but I’ve yet to explore those features.

Finally, remember, copying and pasting code found on the interwebs is a surefire way to introduce errors. I make no promises about this code, and strongly advise you, if you use it, to check it thoroughly and ensure you adapt it carefully to your environment.