Fedora Encrypted Root With Automatic Key Unlocking
Fedora’s installer will happily set up an encrypted install with root-on-lvm-on-luks (/boot is still unencrypted. Secure Boot might be handy here still). This is supported and works out of the box.
However, while I’m present when I reboot this machine, it is also headless (no keyboard or monitor), so typing a passphrase at boot is problematic. But no problem, you can have up-to ten key slots for a LUKS partition, right? And you can use a keyfile for one of those slots, right? So it should just be a matter of updating the crypttab, right?
While crypttab does allow you to set a keyfile, and it does indeed work for all other filesystems, it doesn’t work for /. It expects a (mounted) path to the keyfile, and the USB token won’t be mounted until after /. So there’s a bit of a chicken and egg situation: You can’t mount the keys to decrypt root until after root is decrypted.
But luckily we’re using systemd, and it actually does handle this scenario. It allows us to say which device contains the key, without having to expect it to be mounted. We just can’t use crypttab to do this. The documentation exists (and is generally well written), but it still took a lot of fiddling to get this to work correctly.
Use man systemd-cryptsetup-generator
for the details.
Note: the crypttab(8)
manpage appears to indicate crypttab supports this as well, but I just couldn’t get it to work. That said, I also had issues with a too-short timeout that caused a lot of headaches…
Set up Kernel Command Line
Have keys working
Before we begin, you should have your keys created and added to your LUKS partition. Create your key file the “normal” way (random data into text file with no newline at the end). There’s plenty of articles and howtos about this part, so I won’t get into this here.
Add parameters to grub’s configuration
We’ll need to edit the GRUB_CMDLINE_LINUX in /etc/default/grub to add all the decryption instructions for systemd to process at boot time:
$ cat /etc/default/grub | grep GRUB_CMDLINE_LINUX
GRUB_CMDLINE_LINUX="resume=/dev/mapper/vgsystem-swap rd.luks.uuid=luks-926ee4d1-4cd8-43d7-97a3-07d41ed2a742 rd.lvm.lv=vgsystem/root rd.lvm.lv=vgsystem/swap rd.luks.key=926ee4d1-4cd8-43d7-97a3-07d41ed2a742=/my.luks.key:LABEL=keys rd.luks.options=926ee4d1-4cd8-43d7-97a3-07d41ed2a742=keyfile-timeout=30s rhgb quiet"
Here’s the luks-specific details I needed to have:
rd.luks.uuid
rd.luks.uuid=luks-926ee4d1-4cd8-43d7-97a3-07d41ed2a742
This tells systemd to open this container. The format is luks
+ crypt uuid
, and it seems to have special hardcoding for that format. It probably works with just the bare UUID. Alternatively, you can probably try using rd.luks.name to set a different name once it’s opened. This line was actually here from the installer, so I left it alone.
You can figure out your UUID from either the command line (it may already be here), /etc/crypttab, or cryptsetup luksDump /dev/sdXX | grep UUID
rd.luks.key
rd.luks.key=926ee4d1-4cd8-43d7-97a3-07d41ed2a742=/my.luks.key:LABEL=keys
This is the magic bit, which tells systemd where the key is. The key parts (aside from the UUID again):
-
/my.luks.key
This is the path to the key file relative to the USB stick, not the full path when mounted. So
/my.luks.key
instead of/mnt/keys/my.luks.key
. -
LABEL=keys
This is an identifier for the filesystem that contains the keys. I labelled the filesystem on my drive as “keys”.
Be careful of the changing delimiters. It changes from =
to :
toward the end.
rd.luks.options
rd.luks.options=926ee4d1-4cd8-43d7-97a3-07d41ed2a742=keyfile-timeout=30s
This simply lengthens the timeout to probe the keyfile. This is fairly important, as the default timeout seems fairly short, and there’s a 75% chance that my USB device will not be probed yet. I really expected early boot to be far more deterministic, and this caused a lot of problems while troubleshooting. 30 seconds is far more time than needed (occasionally 10s was not enough).
Update Grub:
$ sudo grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg
Remove from crypttab
At this point, you’d expect it to work, but it doesn’t. You’ll still get prompted for a passphrase. The manpage for systemd-cryptsetup-generator actually tells us why in the rd.luks.uuid description:
If /etc/crypttab contains entries with the same UUID, then the name, keyfile and options specified there will be used. Otherwise, the device will have the name “luks-UUID”.
You could also set rd.luks.crypttab=no
on the command line, but I still want to use crypttab for my non-root filesystems. So comment out the entry for this device in /etc/crypttab, and rebuild your initrd…
$ sudo dracut -f
Now you should be able to boot and have your disk unlocked automagically at boot.
Future investigation
It would be nicer to have this configured in /etc/crypttab. Perhaps it does work, and it was merely my USB timeout issues that prevented it.