Preloading disk encryption keys
I run a small home server, which - among other things - has backups of data from cloud providers, in case I lose access to them; this data is sensitive and should therefore be encrypted. However, disk encryption requires a secret, and there are - generally speaking - four ways to go about that:
- Store the key on the same server as the encrypted disk
- Store the key on detachable media, attached to the same server as the encrypted disk
- Store the key on a different server
- Store the key in your brain (this is known as a “passphrase” or “password”)
Using a separate server is a bit more complicated than I’d like to go (and is not always supported, e.g. in the free version of TrueNAS Core), and storing the key on the same server won’t protect me in case the server is stolen. For my usecase, it’s an easily burgler-accessible NUC. Detchable media will have to remain attached, as I want to be able to reboot remotely (I’ve heard some interesting suggestions, e.g. “store the key in a USB key glued to your desk so the burgler will probably just disconnect it from the server”). The last option is the simplest and most convenient, except when rebooting.
When rebooting an encrypted system that uses a passphrase, you essentially have to do the following:
- Learn that a reboot is required (about once every 12 days on my server, for a kernel security update)
- Connect to the server to reboot it
- Wait for it to reboot
- Connect to the server again to input the passphrases
I always hate actions with a “wait” part to them, so I figured - wouldn’t it be nice to input the passphrases as part of the reboot process? That way I essentially shave off steps 3 and 4. The idea is to allow just the next boot to load the encrypted bits without entering any passwords, authorized by, well, someone who knows the relevant passwords. Hopefully burglars aren’t sophisticated enough to target my machine on kernel patch days.
My particular system uses ZFS-on-linux with a couple of encrypted filesystems, and the following is an implementation using systemd and Go. I do think the idea is useful enough for other passphrase-encrypted systems (e.g. LUKS).
The overall design is:
- Before rebooting, you run the go binary on the server as root. It will:
- Figure out which ZFS filesystems currently have a loaded key
- Ask for the password for those (and check that it’s correct)
/zfs-reboot-passphrase.shwith the passphrases embedded
shellescapeturns out to be useful, as
fmt.Sprintf("%q", password)insists on using double quotes, which doesn’t prevent bash from interpreting strings.
- On boot, the
zfs-reboot-passphrasesystemd service will check if
/zfs-reboot-passphrase.shexists and run it. It will:
- Load the embedded passphrases and mount the relevant filesystems
shred -uitself - rewrite itself with random data to prevent undeletion, and then delete itself.
The specific implementation isn’t super-clean nor important, but I’m attaching it as-is (buyer beware) for completeness. Hopefully it serves as inspiration for something useful.