Ubuntu Secure Boot, take 2
The first Ubuntu Secure Boot article didn’t
really suggested a viable solution for fully secure boot, but there is a surprisingly
easy way to do this: by using systemd-cryptenroll.
The idea is to use the TPM feature called TPM Platform Configuration Registers (PCRs). PCRs are TPM registers that accumulate hashes (essentially checksums) of boot components measured during the boot process—such as firmware code (PCR 0), boot loader code (PCR 4), Secure Boot policy and certificates (PCR 7), kernel/initrd (PCR 9 or 11), or shim policy (PCR 14). systemd-cryptenroll does not alter PCR values or EFI variables; it only binds to expected PCR hash states for unlocking.
systemd-cryptenroll takes the values of PCRs and uses them to create a LUKS unlock key.
This method is therefore way less invasive than the UKI method since you don’t modify any keys in the TPM chip; this method for example doesn’t prevent Windows from booting in dual-boot setup.
This setup uses two unlock keys in LUKS:
- A traditional password entered via keyboard. You’ll use this as a fallback if you manage to lock yourself out.
- A TPM2 key derived from a signature of kernel and initrd, protected by a PIN.
- The PIN can be simple since it resists dictionary attacks: TPM2 locks if invalid PIN is entered three times.
- If “evil maid” spoofs kernel/initrd, the signature will change which will make the key invalid.
When all is good and the kernel/initrd signatures are valid, Plymouth will ask for a LUKS TPM2 PIN code. Once it does, you can be sure that the kernel/initrd hasn’t been tampered with.
If the signature changes, the key is invalid and Plymouth will fall back to the password key. Once that happens:
- Either you updated kernel/initrd (via
update-initramfs) and you forgot about this, OR - You are a victim of the evil maid attack. Do NOT type in any passwords and do not trust your OS; wipe the disks clean.
Prerequisites
This can be set up on an already installed Linux. You’ll need:
- Secure Boot enabled in BIOS
- EFI partition since you must boot Linux in UEFI mode
/bootmay be unencrypted/encrypted via LUKS
We will use the systemd-cryptenroll tool. We will NOT use the Clevis tool
which does the same thing but in a more complicated way.
Setting up
First, edit your crypttab and add the option
tpm2-device=auto:
dm_crypt-0 /dev/XYZ none luks,discard,tpm2-device=auto
This option is what tells Plymouth/systemd-cryptsetup to use the TPM2 metadata from the LUKS2 header and to wait for the TPM2 device to show up.
To install tpm2 support to Plymouth, you must install sudo apt install tpm2-tools
otherwise your system won’t be able to unlock LUKS and won’t boot.
You’ll need to rebuild initrd, in order for this change to take effect:
sudo update-initramfs -u -k all. Maybe reboot, to check that LUKS+Plymouth
still works.
If update-initramfs fails with cryptsetup: WARNING: nvme0n1p3_crypt: ignoring unknown option 'tpm2-device', scroll down for more info.
Next, figure out the device which hosts the LUKS. It won’t most probably be a mapper device;
instead it will be /dev/XYZ. Run lsblk to find out the device easily.
$ sudo systemd-cryptenroll /dev/XYZ --tpm2-device=auto --tpm2-pcrs=7+9+11+12 --tpm2-with-pin=true
This will add a new TPM2 unlock key to your LUKS. It will now be used by default by Plymouth. Reboot and test out: you should be asked for a PIN instead.
Testing tampering
Simply rebuild initrd via update-initramfs: this should invalidate the TPM2 LUKS key.
Now when you reboot, you’ll be prompted for a password - a clear sign of
tampering.
PCR
The PCR 7 guards against tampering with the Secure Boot state (PK/KEK/DB keys, enabled/disabled) and should always be enabled. The PCR 9, 11 and 12 guard against changes in kernel, initrd and/or kernel args and should be present at all times too.
If you want to be super-secure, use 0+2+4+7+9+11+12: 0 guards against BIOS change itself etc.
Ideally you want to use PCR 8 as well which guards against changes in “Boot loader policy / GRUB commands / measured boot loader extensions”, but for some reason adding this will always invalidate the TPM2 key, forcing Plymouth to always fall back and prompt for password.
To see which PCRs are active:
systemd-analyze pcrs
On my system, I can see the keys ‘11’ and ‘12’ unpopulated (zeroed out), so there’s no point in including those. The most important key is 9 - kernel initrd, since that’s the single unprotected thing in Ubuntu’s Secure Boot security chain.
After you update BIOS or kernel or rebuild initrd
Run the following command first, to remove any existing TPM2 LUKS:
$ systemd-cryptenroll /dev/XYZ --wipe-slot=tpm2
Then, simply run the setting-up command again.
After you lock yourself out
If you type in PIN incorrectly and TPM enters “dictionary attack lockout mode”, you can’t simply fall back and type in the password.
One way is to boot off an USB stick and remove the TPM2 LUKS key.
Use lsblk to discover the device hosting LUKS; then run
$ systemd-cryptenroll /dev/XYZ --wipe-slot=tpm2
This removes the TPM2 key from LUKS, leaving only the password key. Reboot - you should now be asked for the password.
Another way is to boot off an USB stick and run
sudo tpm2_dictionarylockout --clear-lockout.
Another way is to add the rd.luks.options=timeout=0 kernel parameter to GRUB
boot entry. This should cause Plymouth to skip waiting for TPM and fall back to password.
update-initramfs fails with cryptsetup: WARNING: nvme0n1p3_crypt: ignoring unknown option 'tpm2-device'
This happens when you’re using initramfs-tools to generate initramfs (verify: check that initramfs-tools package is installed). Fresh installs of Ubuntu 25.10
moved to dracut but Ubuntu 25.10 upgraded from earlier stayed with initramfs-tools.
More info in the tpm2-luks-systemd blogpost.
You’ll need to migrate to dracut in order to use tpm2.
More Info
- Unlocking LUKS2 volumes with TPM2, FIDO2, PKCS#11 Security Hardware on systemd 248 - Lennart Poettering’s (author of systemd) blog.
- ArchLinux systemd-cryptenroll docs