Unlock LUKS with the TPM2 Chip Using systemd-cryptenroll
Typing a LUKS passphrase at every boot is the correct default, but it gets old fast on a machine that never leaves your desk. A TPM2 chip can hold that unlock key instead and release it automatically, on the condition that the machine boots into a state it recognises.
If someone swaps your bootloader, boots a different kernel, or moves the disk into another machine, the TPM refuses to release the key and you fall back to the passphrase. That fallback is the entire point: it's not a way to skip authentication, it's a way to make authentication conditional on the boot environment being unchanged.
This is a companion to a different problem than the one covered in the earlier post on LUKS2 with a detached header on a USB key, which is about hiding the fact that a device is encrypted at all. Here the disk is openly a LUKS volume; we're just outsourcing the "did anything about this boot look wrong" check to hardware that's much harder to lie to than a script.
Check you have a TPM2 chip and a new enough systemd
You need a real TPM2 chip (fTPM/PTT firmware implementations count) and a distribution with a recent enough systemd. systemd-cryptenroll's TPM2 support landed in systemd 248, and the PIN option (--tpm2-with-pin) needs 250 or later.
systemd-cryptenroll --version
ls /dev/tpmrm0
If /dev/tpmrm0 exists, the kernel has a TPM resource manager talking to the chip.
Check the volume itself is LUKS2, not LUKS1, since token-based enrolment is a LUKS2 metadata feature:
sudo cryptsetup luksDump /dev/sdaX | head -n5
If it says version 1, you'll need to convert or recreate the volume before any of this works.
Enrol the TPM alongside your passphrase
The basic command adds a new keyslot sealed to the TPM, in addition to your existing passphrase slot (it does not remove the passphrase, and you should not remove it):
sudo systemd-cryptenroll /dev/sdaX --tpm2-device=auto --tpm2-pcrs=7
What happens next:
- You're prompted for an existing passphrase to authorise the change.
- The tool creates a new key and seals it to the TPM against the given PCR values.
- It stores a LUKS2 token describing how to unseal it.
cryptsetup luksDump afterwards will show a new systemd-tpm2 token and keyslot.
Picking PCRs is the fiddly part
Platform Configuration Registers accumulate measurements of the boot chain: firmware, option ROMs, bootloader, kernel command line, and so on, each extended (never overwritten) as boot progresses. Binding a TPM seal to a PCR means "only release this key if that register has exactly this value right now".
Bind to too few and you get weak protection. Bind to too many and a routine firmware or kernel update locks you out of your own disk, because the update legitimately changed a measurement you were pinning against.
- PCR 7 alone (Secure Boot policy state) is the common, relatively stable choice: it changes only when Secure Boot is toggled or the key database is modified, not on every kernel or firmware patch.
- PCR 0 (firmware) and PCR 2 (option ROMs) are more brittle, since a UEFI firmware update changes them.
Quick detour: unified kernel images measure themselves
Here's the bit worth knowing if you're using Secure Boot with a unified kernel image: a kernel, initramfs and command line combined into one signed EFI binary, which systemd-boot and sd-stub both support. systemd does its own measurement, independent of the standard firmware PCRs. The stub extends PCR 11 with a hash of the UKI itself before handing control to the kernel.
Binding to PCR 11 instead of, or alongside, PCR 7 means the seal tracks the exact kernel and initramfs you booted, which is stronger. But it also means every kernel update changes PCR 11 and invalidates the seal.
If you go this route, re-enrolling the TPM slot needs to happen as part of your kernel upgrade process (a pacman/dnf/apt hook, or systemd-boot-update.service style automation). Not as an afterthought, after you're already locked out at a passphrase prompt wondering why.
For most desktop use, PCR 7 on its own is a reasonable balance. If you want the stronger UKI-measurement guarantee, budget for the re-enrolment automation up front.
Tell crypttab to try the TPM first
Add tpm2-device=auto to the volume's entry in /etc/crypttab so the boot-time unlock generator knows to try the TPM before falling back to a prompt:
luks-root UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx none tpm2-device=auto
The fourth field can carry other options too (discard, nofail, and so on), comma-separated. Leave the key field as none; the key material comes from the TPM-sealed token in the LUKS header, not a file.
Rebuild the initramfs with TPM support baked in
The early-boot environment needs the TPM2 tools and systemd's cryptsetup generator baked in. How you get there depends on the distribution.
On dracut-based distributions (Fedora, RHEL, openSUSE), make sure the systemd and tpm2-tss dracut modules are included, then regenerate:
sudo dracut --regenerate-all --force
On Arch with mkinitcpio, add the sd-encrypt hook (replacing the older plain encrypt hook) to /etc/mkinitcpio.conf, since it's the systemd-based hook that understands crypttab's tpm2-device option, then rebuild:
sudo mkinitcpio -P
Debian/Ubuntu with dracut or systemd-boot follow the dracut path above. If you're still on the classic cryptsetup initramfs hook without systemd in the initramfs, TPM2 unlock won't work until you switch to the systemd-based generator.
Prove both the unlock and the fallback work
Reboot. You should see no passphrase prompt at all if the PCR state matches what you enrolled against. To confirm the TPM path is actually what unlocked it rather than a cached key, check the boot log:
journalctl -b | grep -i tpm2
Then deliberately break the binding to see the fallback work. Change something covered by your chosen PCR (toggle Secure Boot off and back on if you bound to PCR 7, for instance) and reboot.
You should land back at a normal passphrase prompt rather than being locked out silently, which is the behaviour you're relying on.
Add a PIN if the machine alone isn't enough
TPM-only unlock means physical possession of the running, correctly-booted machine is sufficient, since the TPM releases the key without human input. If you want a second factor, enrol with a PIN as well:
sudo systemd-cryptenroll /dev/sdaX --tpm2-device=auto --tpm2-pcrs=7 --tpm2-with-pin=yes
This asks for a short PIN at boot in addition to the TPM check.
Actually, this bit is interesting: the PIN is rate-limited by the TPM's own dictionary-attack lockout counter rather than a software timer. That's a meaningfully stronger guarantee than an application-level retry limit, because there's no software to patch around.
Removing an enrolment, and why the passphrase stays
List enrolled slots and tokens at any time with cryptsetup luksDump. To remove a TPM2 enrolment (say, before selling the machine, or after deciding the PCR policy was wrong):
sudo systemd-cryptenroll /dev/sdaX --wipe-slot=tpm2
Keep at least one passphrase slot enrolled permanently. A TPM binding is a convenience layered on top of the passphrase, not a replacement for it. The passphrase is the only thing that still works if:
- the chip fails,
- the firmware gets reflashed, or
- you migrate the disk to different hardware entirely.