Friday, February 17, 2012

Encrypted disk images in NetBSD

When I joined the NetBSD Board of Directors, I was trusted with access to private information and one of the prerequisites for downloading such data was to be able to store it safely: i.e. inside an encrypted volume. I initially went the easy route by putting the data in my laptop, which already uses FileVault 2 to encrypt the whole disk. But soon after, I decided that it would be nicer to put this data in my NetBSD home server, which is the machine that is perpetually connected to IRC and thus the one I use to log into the weekly meetings.

At that point, I was faced with the "challenge" to set up an encrypted volume under NetBSD. I knew of the existence of cgd(4): cryptographic disk driver but had never used it. It really is not that hard, but there are a bunch of manual steps involved so I've been meaning to document them for almost a year already.

Because my home server is a NetBSD/macppc and reinstalling the system is quite a nightmare, I did not want to go through the hassle of repartitioning the disk just to have an encrypted partition of 1GB. The choice was to create a disk image instead, store it in /secure.img and mount it on /secure. Let's see how to do this.

The first step is to create the disk image itself and "loop-mount" it (in Linux terms). We do this the traditional way, by creating an empty file and setting up a vnd(4): vnode disk driver device to access it:
# dd if=/dev/zero of=/secure.img bs=1m count=1024
# vnconfig -c /dev/vnd2 /secure.img
The next step is to configure a new cgd(4) device. This block-level device is a layer placed on top of a regular storage device, and is in charge of encrypting the data to the lower-level device transparently. cgdconfig(8), the tool used to configure cgd(4) devices, stores control information on a device basis under /etc/cgd/. The control information can be generated as follows:
# cgdconfig -g -o /etc/cgd/vnd2c aes-cbc 192
This creates the /etc/cgd/vnd2c configuration file, which you can choose to inspect now. With the file in place, configuring the cryptographic device for the first time is easy:
# cgdconfig cgd0 /dev/vnd2c
This command will inspect the underlying /dev/vnd2c device looking for a signature indicating that the volume is valid and already encrypted. Because the volume is still empty, the tool will proceed to ask us for an encryption key to initialize the volume. We enter our key, wait a couple of seconds, and /dev/cgd0 will be ready to be used as a regular disk device. With that in mind, we can proceed to create a new file system and mount it on the desired location:
# newfs -O 2 /dev/rcgd0c
# mkdir /secure
# mount /dev/cgd0c /secure
To simplify access to the device for your users, I did something like this:
# user=your-user-name
# mkdir /secure/${user}
# chown ${user}:users /secure/${user}
# chmod 700 /secure/${user}
# ln -s /home/${user}/secure /secure/${user}
And we are done. Now, depending on the situation, we could choose to get /secure automatically mounted during boot, but that would involve having to type the decryption key. This is OK for a laptop, but not for a headless home server. Because I don't really need to have this secure device mounted all the time, I have the following script in /root/secure.sh that I can use to mount and unmount the device at will:
#! /bin/sh

set -e -x

case "${1:-mount}" in
mount)
    vnconfig -c /dev/vnd2 /secure.img
    cgdconfig cgd0 /dev/vnd2c
    fsck -y /dev/cgd0c
    mount /dev/cgd0c /secure
    ;;
unmount)
    umount /secure
    cgdconfig -u cgd0
    vnconfig -u /dev/vnd2
    ;;
esac
Be aware that cgdconfig(1) has many more options! Take a look at the manual page and choose the ones that best suit your use case.

Random idea: instead of using a vnd(4) device, plug in a USB stick and use that instead for your secure data!  (I actually do this too to back up sensitive information like private keys.)