TPM2 Autodecrypt on Arch Linux with UKI and Secure Boot

A step-by-step guide to passwordless LUKS2 decryption via TPM2 on Arch Linux using Unified Kernel Images, systemd-boot and sbctl.

Prerequisites

Before we begin, the following conditions must be met:

RequirementCheck command
LUKS2 (not LUKS1)cryptsetup luksDump /dev/nvme1n1p2 | grep "Version:"
TPM2 chip presentsystemd-cryptenroll --tpm2-device=list
Secure Boot active (User Mode)bootctl status | grep "Secure Boot"
systemd-boot as bootloaderbootctl status
UKI-based bootls /boot/EFI/Linux/*.efi

⚠️ Important: This guide is specifically for systems that use Unified Kernel Images (UKI) — i.e. .efi files under /boot/EFI/Linux/ rather than classic loader entries under /boot/loader/entries/. The procedure differs for classic setups with loader entries.

Background: Why UKI + sd-encrypt?

A Unified Kernel Image bundles the kernel, initramfs, microcode and kernel cmdline into a single signed .efi file. Combined with Secure Boot, this creates a complete chain of trust: the firmware verifies the UKI signature before the kernel even starts.

The TPM2 chip uses PCR registers (Platform Configuration Registers) to measure the system state. By binding the LUKS key to PCR 0 (firmware integrity) and PCR 7 (Secure Boot state), the key is only released when the system boots in the expected state — i.e. with active Secure Boot and unchanged firmware.

The classic encrypt hook in mkinitcpio does not support TPM2. The sd-encrypt hook is required for this, which is based on systemd-cryptsetup and reads its configuration from /etc/crypttab.

Step 1: Enroll the TPM2 Key

systemd-cryptenroll writes a TPM2-bound key directly into the LUKS2 header. The existing passphrase is always retained as a fallback.

1
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/nvme1n1p2

Verify the enrollment:

1
sudo systemd-cryptenroll /dev/nvme1n1p2

Expected output:

1
2
3
SLOT  TYPE
   0  password
   2  tpm2

Step 2: Populate /etc/crypttab

This is the most common mistake in failed setups: the sd-encrypt hook reads exclusively from /etc/crypttab — if this file is empty, it cannot find the LUKS partition and the boot will fail.

First, retrieve the UUID of the LUKS partition:

1
sudo blkid -s UUID -o value /dev/nvme1n1p2

Then add it to /etc/crypttab:

1
sudo nano /etc/crypttab
1
2
# <name>   <device>                                      <password>  <options>
root        UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx    -           tpm2-device=auto

⚠️ Choose the name (here root) to exactly match how the LUKS partition is currently mapped — verify with lsblk.

Step 3: Clean Up the Kernel Cmdline

Kernel parameters for UKIs are embedded from /etc/kernel/cmdline. The cryptdevice= parameter belongs to the old encrypt hook and must be removed — sd-encrypt does not recognise it.

1
sudo nano /etc/kernel/cmdline

Before:

1
cryptdevice=PARTUUID=xxxx:root root=/dev/mapper/root rootflags=subvol=@ rw rootfstype=btrfs

After:

1
root=/dev/mapper/root rootflags=subvol=@ rw rootfstype=btrfs

⚠️ Everything must remain on a single line with no trailing newline.

Step 4: Adjust the mkinitcpio Hooks

1
sudo nano /etc/mkinitcpio.conf

Before:

1
HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)

After:

1
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block sd-encrypt filesystems fsck)

Summary of changes:

OldNewReason
udevsystemdRequired base for all sd-* hooks
keymap consolefontsd-vconsolesystemd equivalent, reads from /etc/vconsole.conf
encryptsd-encryptTPM2 support via systemd-cryptsetup

Step 5: Rebuild Only the Main UKI

If an LTS kernel is installed, it is recommended to only rebuild the main UKI and keep the LTS UKI as a fallback. This allows booting with a password using the LTS kernel if something goes wrong.

1
sudo mkinitcpio -p linux

Step 6: Sign the New UKI with sbctl

Since Secure Boot is active, the newly built UKI must be signed before the firmware will accept it:

1
2
sudo sbctl sign /boot/EFI/Linux/arch-linux.efi
sudo sbctl verify

Step 7: Reboot and Test

1
sudo reboot

On success: no password prompt, direct boot via TPM2 unlock.

If a password is still requested: that is the normal fallback — the TPM did not release the key. The most common cause is an unexpected PCR state (e.g. Secure Boot disabled or a firmware update that changed PCR 0).

Step 8 (After Successful Test): Update the LTS UKI as Well

1
2
sudo mkinitcpio -p linux-lts
sudo sbctl sign /boot/EFI/Linux/arch-linux-lts.efi

Troubleshooting

TPM does not release the key

1
2
# Check systemd-cryptsetup log
journalctl -b -u systemd-cryptsetup@root

Common causes:

  • crypttab is empty or misconfigured
  • cryptdevice= is still present in the kernel cmdline
  • A firmware update changed PCR 0 → re-enrollment required

Reset enrollment and re-enroll

1
2
3
4
5
6
7
8
9
# Remove TPM2 slot
sudo systemd-cryptenroll --wipe-slot=tpm2 /dev/nvme1n1p2

# Re-enroll
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/nvme1n1p2

# Rebuild and sign the UKI
sudo mkinitcpio -p linux
sudo sbctl sign /boot/EFI/Linux/arch-linux.efi

That’s it. The system will now boot without a password prompt — as long as Secure Boot is active and the firmware remains unchanged. The LUKS passphrase is always available as a fallback.