Unlocking LUKS2 with X509 Nitrokey during boot
Published on
A continuation of previous post with the instruction to unlock encrypted root partition during boot.
Intro #
We will be setting up and installing a few components that will be run at a specific point during Linux boot, allowing systemd-cryptsetup
to prompt for the hardware token passphrase to unlock the LUKS2-encrypted partition. This procedure assumes that the partition is already configured to be unlocked using X509 certificate.
If you would like to use Nitrokey Storage to unlock LUKS2-encrypted device with the X509 certificate using systemd-cryptsetup, I recommend reading the previous post for configuration instructions.
I tried to write the instructions in this post in a generic way so they could be applicable regardless of the token device, Linux distribution or initramfs generation method.
In my configuration I use:
- Linux distribution: Gentoo
- Initramfs generation method: distribution kernel calling installkernel that uses dracut
- Token: Nitrokey Storage v2
If you use a similar setup – I have packaged my dracut module as a package in my overlay. Just install sys-kernel/dracut-pcscd-cryptsetup
and rebuild initramfs.
Disclaimer/warning #
Please implement the following procedure with extreme caution. If something goes wrong – the partition will not be unlocked during the boot process. Make sure you have access to a rescue shell in your initramfs or have a backup way to boot your machine (like a live USB with chroot).
Also, using the language from the GPL license: this post is written in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Overview #
It is possible to fully rely on systemd
to manage the init process. If /etc/crypttab
is included in the initramfs, systemd
will try to start cryptsetup.target
. This target contains a set of automatically generated services that unlock devices specified in crypttab
. In version 248, systemd added support for pkcs#11 certificates into systemd-cryptsetup
, the binary that those services run to actually unlock the device and that can query the user for a passphrase.
When the system is fully booted, systemd-cryptsetup
uses pcscd
and a set of other tools to communicate with the smartcard devices.
So, in order to use systemd-cryptsetup
to unlock our drive during boot, we will need to install everything it needs to talk to a card into initramfs.
Setup #
Installing dependencies #
During my experiments I have found that the following packages are required, at least for Nitrokey Storage:
If you are using a different token, you may need some other drivers, or adjust opensc configuration.
On Gentoo, these packages need to be installed with specific use flags, see the ebuild for details.
Configuring initramfs creation #
As mentioned in the overview, we will need to include systemd-cryptsetup
and /etc/crypttab
in the initramfs. On dracut it can be done through the following configuration:
~# cat /etc/dracut.conf.d/cryptsetup.conf
add_dracut_modules+=" crypt "
install_items+=" /etc/crypttab "
(note the spaces before and after quotation marks)
See man dracut.conf
for more info on those configuration files.
This instructs dracut to include /etc/crypttab
as a file in the initramfs and triggers module-install.sh
from dracut crypt module. The crypt module (/usr/lib/dracut/modules.d/90crypt
) examines the system and includes systemd-cryptsetup
and related generators in the initramfs.
If using the dracut module created for this article, the add_dracut_modules
line would look like so:
add_dracut_modules+=" crypt pcscd-cryptsetup "
Including dependencies in initramfs #
In order to function properly, certain files provided by packages from “Installing dependencies” section need to be present in initramfs. This list is maintained in the dracut module, the files are installed by calls to inst_multiple
, inst_rules
, inst
and inst_libdir_file
.
Allowing pcscd to start when requested by cryptsetup #
By default pcscd is socket-activated. Pcscd socket is wanted by sockets.target
, which causes it to start after cryptsetup.target
. When installing the pcscd.service
and pcscd.socket
into initramfs, we need to configure these units to allow starting without waiting sockets.target
, otherwise they will be put into systemd job queue and not start when systemd-cryptsetup
requests them.
To do that, we can leverage systemd’s drop-in files support.
For both socket and service, we will need to override the DefaultDependencies
setting and declare that the socket and service are wanted by cryptsetup-pre.target
. cryptsetup-pre.target
is a special target that can be used to launch services before cryptsetup will need them.
The configuration drop-ins look like this:
[Unit]
DefaultDependencies=no
[Install]
WantedBy=cryptsetup-pre.target
Final step #
The only remaining thing is to rebuild initramfs. After that is done, reboot, insert the token and wait for the prompt from cryptsetup. The message “Started PC/SC Smart Card Daemon” should appear right prior to the passphrase prompt.
Troubleshooting #
This is a collection of notes and hints that I wrote down when configuring this setup. The most common error is that systemd-cryptsetup does not prompt for the passphrase. If using dracut it will result in emergency shell being offered after initqueue times out.
- If you want to continue the boot, you can unlock the encrypted device by hand. To do that, run
systemctl status
and check whatsystemd-cryptsetup@
service is trying to execute. You can manually call/lib/systemd/systemd-cryptsetup attach $name /dev/disk/by-uuid/$UUID
to unlock the device - You can try starting pcscd manually by calling
systemctl start pcscd
. If this command hangs – probably something is wrong with the drop-in files. Check the systemd job queue to see what pcscd is waiting for (systemctl list-jobs --after
). - If pcscd is running, you can use
systemd-cryptenroll
andopensc-tool
to check if the token is visible at all. Both of these can be installed by_debug
function in the dracut module.opensc-tool -l
will show if the system can see the tokensystemd-cryptenroll --pkcs11-token=list
will tell ifsystemd
is capable of seeing the token
- Dracut has a module called
rescue
which includes some extremely useful tools such as a text editor