dracut configuration has been updated and now
udev consistently recognizes the YubiKey in the
Unlocking LUKS encrypted drives with a YubiKey has been supported since systemd 248. In Debian, systemd>=250 is required, as the feature has not been enabled in prior versions. This tutorial is geared towards Yubikeys, but it should work with slight modifications with any other FIDO2 token.
YubiKey series 5 and later should support the
hmac-secret extension. You can make sure your Yubikey supports the needed
hmac-secret extension by querying it with
$ ykman --diagnose 2>&1 | grep hmac-secret
Backup your LUKS header
In case you mess anything up, you would need a backup of your LUKS header. Remember to save your backup to some external storage, so you can actually access it if anything goes sideways.
# cryptsetup luksHeaderBackup /dev/nvme0n1p3 --header-backup-file /media/guyru/E474-2D80/luks_backup.bin
Set FIDO2 PIN
We would like to set a FIDO2 PIN for the Yubikey, so unlocking the encrypted drive would require both the physical Yubikey and the PIN. You can set the PIN using:
$ ykman fido access change-pin
Enroll the Yubikey
Start by verifying that
systemd-cryptenroll can see and can use your YubiKey:
$ systemd-cryptenroll --fido2-device=list
PATH MANUFACTURER PRODUCT
/dev/hidraw0 Yubico YubiKey FIDO+CCID
Now, enroll the Yubikey, replacing
/dev/nvme0n1p3 with the block device of the LUKS encrypted drive.
$ sudo systemd-cryptenroll /dev/nvme0n1p3 --fido2-device=auto --fido2-with-client-pin=yes
🔐 Please enter current passphrase for disk /dev/nvme0n1p3: (no echo)
Initializing FIDO2 credential on security token.
👆 (Hint: This might require confirmation of user presence on security token.)
🔐 Please enter security token PIN: (no echo)
Generating secret key on FIDO2 security token.
👆 In order to allow secret key generation, please confirm presence on security token.
New FIDO2 token enrolled as key slot 0.
We need to modify
/etc/crypttab in order to tell
cryptsetup to unlock the device using the YubiKey. Add
fido2-device=auto in the options field of the
crypttab entry for your device. For example:
nvme0n1p3_crypt UUID=307a6bef-5599-4963-8ce0-d9e999026c1a none luks,discard,fido2-device=auto
Switch to dracut
Debian’s default initramfs generator,
update-initramfs of the
initramfs-tools is using the old
cryptsetup for mounting encrypted drives. However,
cryptsetup doesn’t recognize the
fido2-device option. Running
update-initramfs will fail with the following error:
$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-5.15.0-3-amd64
cryptsetup: WARNING: nvme0n1p3_crypt: ignoring unknown option 'fido2-device'
This is unfortunate. The simplest solution is to switch to dracut, a more modern initramfs generator, which among other things relies on systemd to activate encrypted volumes. This solves the issue of the unknown
Before installing dracut, I would highly recommend creating a copy of the existing initramfs in the boot partition in case something goes wrong.
$ sudo apt install dracut
systemd-cryptsetup by default.
systemd-cryptsetup depends on
libfido for unlocking devices using FIDO2 tokens. At least in Debian,
systemd-cryptsetup dynamically loads
libfido2.so (as opposed to being dynamically linked), which causes dracut not to have
libfido2.so in the initramfs. This causes
systemd-cryptsetup to issue the following error upon boot:
FIDO2 tokens not supported on this build.
We fix it by manually adding
libfido2.so to the initramfs. Of course, we also need to include libfido2’s dependencies as well. Dracut has a mechanism for automatically adding dependencies for executables, but it doesn’t work on libraries. As a workaround, instead of adding libfido2 directly, we will add an executable that depends on libfido2, which will add libfido2 and its dependencies to the initramfs. We will use
fido2-token from the
fido2-tools package for this trick.
$ sudo apt install fido2-tools
$ cat << EOF | sudo tee /etc/dracut.conf.d/11-fido2.conf
## Spaces in the quotes are critical.
# install_optional_items+=" /usr/lib/x86_64-linux-gnu/libfido2.so.* "
## Ugly workround because the line above doesn't fetch
## dependencies of libfido2.so
install_items+=" /usr/bin/fido2-token "
# Required detecting the fido2 key
install_items+=" /usr/lib/udev/rules.d/60-fido-id.rules /usr/lib/udev/fido_id "
Now, recreate the initramfs images:
$ sudo dracut -f
At this point, we are done. Reboot you’re machine and it will prompt you for your YubiKey and allow you to unlock your LUKS encrypted root patition with it. If you don’t have your YubiKey, it will give the following prompt:
Security token not present for unlocking volume root (nvme0n1p3_crypt), please plug it in.
After around 30 seconds, it would time out and display the following message:
Timed out waiting for security device, aborting security device based authentication attempt.
Afterwards, it would allow you to unlock the partition using a password (or a recovery key).
In case you run into any trouble, append
rd.break=initqueue to the kernel command line, and dracut will enter a shell before attempting to mount the partitions. You can manually mount the drive using the following command:
# /usr/lib/systemd/systemd-cryptsetup attach root /dev/nvme0n1p3
Exit the emergency shell, and the system will continue its normal boot.