Figure out your LUKS device

Firstly identify your LUKS device. You can find it using:

sudo blkid

Search for device with crypt in its name. In my case it was /dev/nvme0n1p3

Now verify that it is in real a LUKS device by checking its LUKS Header:

sudo cryptsetup luksDump /dev/nvme0n1p3

Seeing header information means that you have correctly identified the LUKS device. Seeing something like device /dev/XXXX is not a valid LUKS device. means you have identified it incorrectly.

Register FIDO2

Your LUKS volume can be decrypted using different ways and each uses one “slots”. One of the slots can be used for FIDO2. Check the currently enrolled slots by invoking:

sudo systemd-cryptenroll /dev/nvme0n1p3

You should see something like:

SLOT TYPE
0 password

So you’re using one slot with your main password. Now let’s add a new slot for FIDO2:

sudo systemd-cryptenroll /dev/nvme0n1p3 --fido2-device=auto

Follow the instructions on the screen - you might be asked to confirm the action on your Yubikey.

Now verify that the new slot has been added:

sudo systemd-cryptenroll /dev/nvme0n1p3

You should see something like:

SLOT TYPE
0 password
1 fido2

Looks good so far.

Create recovery key

As you’re adding a new slot for FIDO2 you might want to create a recovery key. It’s a good idea to have a backup in case you lose your Yubikey or forget (?!) the password.

sudo systemd-cryptenroll --recovery-key /dev/nvme0n1p3

Write down the recovery key and/or the QR code that will be displayed on the screen. Keep it secret, keep it safe.

By the way - the recovery key is just like a password, however being generated by the software it uses most likely higher entropy than a regular password you create on your own.

Instruct cryptsetup to use FIDO2

Let’s stop for a second. You have your YubiKey enrolled as a way to unlock your LUKS volume. Now you need to configure cryptsetup to allow it to use FIDO2.

What didn’t work for me

I’ve tried to do it on my Kubuntu 24.04 by adding an option fido2-device=auto to /etc/crypttab file like this:

YOUR_DEVICE_NAME   UUID=UUID_OF_THE_LUKS_DEVICE   none    fido2-device=auto

Then I’ve recreated the initramfs (that’s the filesystem that is loaded during the boot - unencrypted - that allows you to load required libraries, decrypt the disk and then pass the control to the userspace):

sudo update-initramfs -u

And saw message like:

cryptsetup: WARNING: nvme0n1p3_crypt: ignoring unknown option ‘fido2-device’

Ok, not great. Goggling it I’ve found that it can be solved by moving from initramfs-tools to dracut - the latter is more modern and supports more features (e.g. can load bluetooth drivers to initramfs if you have bluetooth only keyboard and wants to type the password).

However, following the tutorials I’ve found I’ve ended up with a system that was not booting at all. It ended up in dracut rescue shell saying that it cannot find the root partition like /dev/mapper/device-root.

Of course, it couldn’t because /dev/mapper/device-root in my case exists only after decryption of the volume! It was not decrypted yet! It looks like the initramfs created by dracut was not aware of the encrypted volume.

So I’ve tried adding a GRUB command line param to let him know about the encrypted volume:

GRUB_CMDLINE_LINUX="rd.luks.uuid=UUID_OF_THE_LUKS_DEVICE" 

That was something!

Now I was asked once for the LUKS password and… afterward again.
So I needed to type the password twice.

If the YubiKey was inserted I needed only to type the password once (the “first-stage” - result of adding the command line param to GRUB).

Not great, right? Moreover, If I have removed the entry in /etc/crypttab I was only asked for password once and then the OS booted.

So it was clear to me that the GRUB command line param and /etc/crypttab were redundant to each other.

I’ve tried multiple other configurations and finally dropped the idea to move to dracut as it already consumed too much of my time. It was simply not able to tell dracut to generate initramfs that is able to detect my LUKS volume on its own.

So if not dracut then what?

Good guy bertogg shared his project fido2luks that uses fido2-tools to achieve very similar result but using good ol’ initramfs-tools.

Follow his README to create the *.deb package containing a keyscript.sh script that will be called when device attempts to be unlocked.

This script will wait for your FIDO2 key to be present and if it’s not, or you will not touch the key in a given time it will fall back to the password routine.

You reference the script from /etc/crypttab like this:

YOUR_DEVICE_NAME   UUID=UUID_OF_THE_LUKS_DEVICE   none    keyscript=/lib/fido2luks/keyscript.sh

This worked like a charm and although I feel that moving to dracut is a better move in a long-term, I just simply didn’t have much time and knowledge to invest in following this path.

Useful resources