Computer Science
Algorithm
Data Processing
Digital Life
Distributed System
Distributed System Infrastructure
Machine Learning
Machine Learning Application
Operating System
Android
Linux
Linux Full Disk Encryption with Yubikey (2023)
MacOS
Tizen
Windows
iOS
Programming Language
C++
Erlang
Go
Scala
Scheme
Type System
Software Engineering
Storage
UI
Flutter
Javascript
Virtualization
Life
Life in Guangzhou (2013)
Recent Works (2013)
东京之旅 (2014)
My 2017 Year in Review (2018)
My 2020 in Review (2021)
十三年前被隔离的经历 (2022)
A Travel to Montreal (2022)
My 2022 in Review (2023)
Travel Back to China (2024)
A 2-Year Reflection for 2023 and 2024 (2025)
Travel Back To China: 2025 Edition (2025)
Projects
Bard
Blog
RSS Brain
Scala2grpc
Comment Everywhere (2013)
Fetch Popular Erlang Modules by Coffee Script (2013)
Psychology
耶鲁大学心理学导论 (2012)
Thoughts
Chinese
English

Linux Full Disk Encryption with Yubikey

Posted on 22 Oct 2023, tagged YubikeyLinuxEncryption

Updated at 2025-02-01: update the method to include using dracut.

Background

As mentioned in a previous blog Infrastructure Setup for High Availability, I’ve set up a high availability cluster that has 3 machines. But one of them is on my laptop. I feel like I need a dedicated machine for my personal usage, especially since I’m planning some travels. So I need to remove the laptop from the cluster. Its disk space is also very limited. With migrating Gluster to Ceph (more blogs to come on that) and not being able to use a disk partition with Ceph’s encryption, I need another machine with more disks. So I repurposed another small form factor machine to join the cluster.

I want full disk encryption on it but I don’t want to input a password every time it boots: this machine is put into a closet and it’s very inconvenient to plug/unplug keyboard and monitor. In another blog Personal ZFS Offsite Backup Solution, I talked about a solution to boot encrypted Linux without inputting a password by setting up TPM. However, old machines only have TPM 1.x chips instead of newer TPM 2.0 chips, which is very tricky to set up and with very limited support from Linux distros. I don’t want to do it again if not necessary. The threat model is also different since this machine is supposed to be at my home all the time. So this time, I found a new solution to use Yubikey to decrypt disks: I just need to keep the Yubikey plugged in during the boot process and press it at the proper time. I can also fall back to the password method if there is anything wrong with Yubikey decryption.

There are some great tutorials and wiki pages that describe how to do it. I must give credit to this article that helped me a lot. But all of them are missing some details so I thought it would be great to write down my setup so that it may help someone else. My setup is on Arch Linux but the steps should be portable to other Linux distros.

Warning: the steps may make your system unable to boot if not set up properly. Make sure to back it up or have a recovery CD available to fix it if things go south.

Install Linux with LUKS2

First we need to install Linux with our root partition encrypted. If you are using an installer, most likely there is an option to encrypt the disk. If so, select that option and input a passphrase for it. Even though we are using Yubikey to decrypt the disks, it’s always good to have a passphrase to decrypt it in case something goes wrong. However, if your threat model needs a solution that doesn’t involve a passphrase, I believe you can remove it later after setting up Yubikey, though I’ve never tried it myself.

Some installers will use LUKS1 instead of LUKS2 to encrypt the disk. Don’t worry, use cryptsetup convert --type=LUKS2 <device> to convert it to a LUKS2 setup after the OS is installed.

Note: do not encrypt the boot partition. It usually doesn’t have sensitive information and encrypting it doesn’t prevent evil maid attacks anyway. If you want it to be more secure, consider setting up secure boot, which is also mentioned in my previous blog Personal ZFS Offsite Backup Solution.

Enroll Yubikey to Key Slot

We can enroll a FIDO2 (which is a protocol Yubikey supports) device by using systemd-cryptenroll.

Plug in the Yubikey. You can use this command first to list all the FIDO2 devices to make sure the Yubikey is recognized:

systemd-cryptenroll --fido2-device=list

Note: You may need to install libfido2.

After confirming the Yubikey is recognized, use this command to enroll it:

systemd-cryptenroll --fido2-device=auto <disk-device>

It will show a hint that you may need to press the Yubikey during the process. So watch the Yubikey: when its LED flashes, press it to continue.

Setup crypttab with mkinitcpio

Put a line like this into /etc/crypttab.initramfs. It will be copied to initramfs by mkinitcpio as /etc/crypttab so that your root partition can be decrypted before it is mounted:

myvolume <disk-device> - fido2-device=auto

<disk-device> can be something like /dev/sda1 or using UUID format UUID=<disk-uuid>.

If it’s not the root partition, you can put it in /etc/crypttab so it will be used after the root partition is mounted.

mkinitcpio is a tool to generate initramfs. /etc/crypttab.initramfs only works with it.

Once making sure mkinitcpio is installed, we need to configure the hooks to make it read crypttab to decrypt the disks. We also need to make sure we are using systemd init instead of busybox init.

Open /etc/mkinitcpio.conf, and find the line with HOOKS=(...). Refer to this wiki page about the common hooks and replace busybox hooks with systemd ones. For example, in my setup, I replaced udev with systemd and keymap with sd-vconsole. Then add sd-encrypt to the hooks. The order matters: usually it comes after sd-vconsole.

Then use mkinitcpio -P to regenerate initramfs images.

Setup crypttab with dracut

If the system comes with dracut instead of mkinitcpio by default, you can add this line in /etc/crypttab directly to support both password and Yubikey:

myvolume UUID=... none luks,fido2-device=auto

Then regenerate the initramfs using:

sudo dracut --force

Test and Finish!

Okay, now we have already set up everything. We can boot the system and test. Make sure the Yubikey is plugged in before the boot. And watch for its LED light to flash and press it when it does! This little detail spent me lots of time to figure out.

You can also use a password to decrypt the disk without the Yubikey plugged in. Wait for 30 seconds and it will prompt you to input the password. The time can be configured in /etc/crypttab (or /etc/crypttab.initramfs) by setting up token-timeout=.