Unlocking a LUKS-encrypted partition on boot with an USB drive
Posted on 2019-10-13 in Software
The use case I wanted to solve was this: I have a headless server with a LUKS software-encrypted hard drive, and I want to be able to reboot it without having to input the password on a keyboard. The solution I implemented is to create a LUKS keyfile on a USB drive, so if it is plugged on boot the keyfile will be used instead of the password.
Before we begin, a few words on the security of this approach:
-
Whoever gets access to the USB drive will be able to decrypt the target device. Consider the security requirements of the USB drive: could be put on a safe box, hidden away or you could always carry it with you.
-
It's best if the USB drive is only used for this purpose, as any other system where the drive is plugged in can potentially read and leak the encryption key.
-
This is clearly reducing security to gain in usability. Sometimes that is the balance that we are looking for, but oftentimes it's not. It's up to you to decide the value of what you are protecting, potential attack scenarios and how much security it needs.
OK, I'm assumming you have a formatted USB drive that you have mounted
on the computer with the LUKS device you want to unlock on boot,
e.g. on /mnt
. Then create a key file with random information:
# dd if=/dev/urandom of=/mnt/key bs=4096 count=1
Add the generated key to LUKS, so it can be used to decrypt the root device:
# cryptsetup luksAddKey /dev/sda3 /mnt/key
/dev/sda3
should be the encrypted partition that holds your root
filesystem.
Next we will update /etc/crypttab
, which defines encrypted volumes
that can be handled by LUKS. Your crypttab
file should have an entry
similar to this one:
cryptroot UUID=452ac6ac-8bbb-484f-b508-a11a5585e031 none luks
We need to update this line to use the passdev
script provided by
cryptsetup
. This script handles waiting for a device to become
available, then mounting it and reading the key from a file. It's a
good idea to refer to the USB drive using a device that won't change
unexpectedly. I'm using /dev/disk/by-label/<LABEL>
, which is a
symlink to the device based on the partition label. After updating
/etc/crypttab
it should look like this:
cryptroot UUID=452ac6ac-8bbb-484f-b508-a11a5585e031 /dev/disk/by-label/FIDELRAMOS.NET:/key:20 luks,keyscript=/lib/cryptsetup/scripts/passdev
Leave the original mapper name (cryptroot
in this example) and UUID
of your encrypted root, otherwise things will break as the mapper name
is referenced in /etc/fstab
. Just change the none
and add the
keyscript to the options.
Last step is to regenerate the initramfs image so that it includes the
passdev
script, otherwise the boot process would fail:
# update-initramfs -k all -u
And that's it! When rebooting the system it should mount the USB drive automatically and decrypt the root partition using the created key file. If the USB drive is not present it should fall back to reading the passphrase from keyboard in 20 seconds.