Full disk encryption: How can I automatically unlock via a USB key on Silverblue?

Hello,

I have moved from an Arch Linux setup to Fedora Silverblue. On my previous Arch system, I had it set up so that I could unlock my full disk encryption by booting with a USB stick attached, with the USB stick containing a key file. If the USB stick was not connected, then I would be prompted for the passphrase like normal.

I set this up by following the Arch wiki’s instructions. To summarise, I had to add vfat as an early boot module for the initial ramdisk, and then had to edit my Systemd-boot configuration file to add the following kernel command-line arguments:

cryptdevice=PARTUUID=(DISK_ID):lvm cryptkey=PARTUUID=(USB_ID):vfat:(KEY_FILE_PATH)

Now I am on Fedora Silverblue with GRUB, and have no previous experience with either. I have also not used Fedora Workstation before. I did a default installation via the installer, with full disk encryption and automatic partitioning. I therefore have a very typical install.

Could anyone please tell me what I need to do to set up something similar?

I took a look in my /boot/ directory and found a GRUB configuration file there, but it seems to use different kernel command-line arguments, such as rd.luks.uuid instead of cryptdevice. I’m not sure if this is the right place to touch, as I believe there may be a GRUB configuration file elsewhere in /etc/ from which the /boot/ one gets generated? I’m also not sure exactly what I would need to change.

I can also see that the /etc/crypttab file contains an entry for the full disk encryption, and the crypttab man page contains some information on pointing to a key file, but it sounds like it just takes an absolute path and that there’s no way to specify a USB disk that isn’t already mounted.

Could anyone help me out here? Thanks in advance.

3 Likes

Hey,

A few pointers to help you out, I’m on my phone right now so apologies if I don’t go into depth.

Fedora uses ‘dracut’ rather than ‘mkinitcpio’ to generate the initramfs file. The initramfs file itself on Silverblue is, by default, generated server side. If you require changes to the initramfs the man pages for rpm-ostree tell you how to generate them client side.

Again, on Silverblue the recommended method to change kernel parameter is via rpm-ostree.

Following the guidance in the wiki article you posted for the systemd hook it should work.

2 Likes

Thanks a lot for your help. Unfortunately, I am still having trouble getting it to work.

Following your advice, I read a bit about the systemd hook, rpm-ostree, and dracut. I used rpm-ostree kargs --editor command (pretty cool feature!) to add a new kernel argument:

rd.luks.key=/keys/testkey:UUID=USB_ID_HERE

Obviously, USB_ID_HERE was replaced with the actual UUID, as given by blkid or lsblk.

Unfortunately, after rebooting into the new deployment, I was still asked for my passphrase. Looking at the logs, there was a message saying:

Failed to activate with key file ‘/keys//testkey’. ( Key file missing ?)

This suggests that it was at least looking for the key file, which is progress, but it’s failing to find it. Could this be because it’s using vfat? Or is there some other reason? I’m unsure how to proceed, so I’d appreciate some more assistance. Thanks.

2 Likes

Just gave it a little play and it works for me when I point to the luks partition following the Arch Linux wiki.

rd.luks.key=LUKS_PARTITION_UUID=/keys/testkey:UUID=USB_ID_HERE

Note: This is the UUID encrypted partition itself not the mapped device and without the “UUID=”

Oddly enough, doing what you did and following the Dracut man pages didn’t work for me either.
Let me know how you get on.

3 Likes

It worked! Thanks so much for your help. I really appreciate it.

It seems like there’s a documentation issue on the Dracut man page then, or for some reason it doesn’t apply in this context. I also had to specify rd.luks.options to set a timeout, so that I can enter a passphrase in case the USB key is not available.

This is solved now. Thanks again for your help. The final solution for anyone else coming across this thread:

  1. Format a USB drive with vfat.
  2. Generate a key file on that USB drive: Arch wiki
  3. Open a terminal.
  4. Run lsblk -f to get the UUID of the encrypted partition (look for “crypto”), as well as the UUID of the USB drive’s partition.
  5. Still in the terminal, run: rpm-ostree kargs --editor
  6. Using the editor, add the following kernel arguments:
    rd.luks.key=XXXXX=/path/to/key/file:UUID=ZZZZZ rd.luks.options=XXXXX=keyfile-timeout=5s
    (replace XXXXX with the encrypted partition’s UUID and replace ZZZZZ with the USB drive’s partition.
  7. Save the file and exit, and then wait for rpm-ostree to generate a new deployment.
  8. Reboot into the new deployment. If the USB drive is connected, it should automatically unlock the encrypted drive. If it isn’t connected, then you should be prompted for a passphrase after 5 seconds.
4 Likes

If you have a lot of disks to decrypt; then outright editing the kernel command line becomes a hassle (it doesn’t accept line breaks).

A better solution would be to use the rpm-ostree kargs --append option:

[ebeale@koi ~]$ ro kargs --help
Usage:
  rpm-ostree kargs [OPTION…]

...

  --append=KEY=VALUE                Append kernel argument; useful with e.g. console= that can be used multiple times. empty value for an argument is allowed

This can be done directly into the rpm-ostree kargs command, by adding multiple --append options; or you could add all your --append options in a file; then do something like rpm-ostree kargs $(< kargs.txt).

While indirectly editing the kernel command line to add disks / keys is a better idea, it doesn’t save you from a possibly very long command line if you need to edit it during boot. The grub editor isn’t very forgiving…

IMO, the best way to auto decrypt disks with a key-file is to edit /etc/crypttab, because is’t much saner to edit due to having a structure, where each line represents one container to decrypt:

${DISK_NAME} UUID=${LUKS_UUID} ${KEY_FILE}:UUID=${USB_UUID} keyfile-timeout=5                                        

Systemd generates a systemd-cryptsetup@${DISK_NAME}.service for each line in /etc/crypttab, which are then executed early in boot.

It’s an analogue to using the kernel command line. See man crypttab, and man systemd-cryptsetup-generator