Skip to content

Instantly share code, notes, and snippets.

@lancechentw
Created August 13, 2026 17:43
Show Gist options
  • Select an option

  • Save lancechentw/f55ba6f6da014d09bfecd0c6f3e80f8e to your computer and use it in GitHub Desktop.

Select an option

Save lancechentw/f55ba6f6da014d09bfecd0c6f3e80f8e to your computer and use it in GitHub Desktop.
TPM2 LUKS Auto-Unlock — Ubuntu 24.04 on MSI Cubi

TPM2 LUKS Auto-Unlock — Ubuntu 24.04 on MSI Cubi

Uses Clevis, not systemd-cryptenroll: Ubuntu's initramfs is initramfs-tools, which has no systemd-cryptsetup, so tpm2-device=auto in /etc/crypttab is silently ignored.

Machine facts

Item Value
LUKS partition /dev/nvme0n1p3
LUKS UUID be0ce340-cee1-47bd-aa84-c0d630f56569
Mapper name cryptroot
Layout LUKS → LVM (ubuntu--vg-ubuntu--lv = /, ubuntu--vg-swap)
TPM Discrete Infineon (IFX) 2.0, firmware 15.23
Kernel 6.8.0-137-generic

Discrete TPM, so sealed keys survive BIOS updates, CMOS clear, and battery removal. Only an explicit "Clear TPM" in BIOS or a PCR 7 change breaks unlock.


1. Verify the TPM

cat /sys/class/tpm/tpm0/tpm_version_major        # 2
ls -l /dev/tpm*                                  # tpm0, tpmrm0
mokutil --sb-state                               # Secure Boot state
sudo tpm2_getcap properties-fixed | grep -A2 TPM2_PT_MANUFACTURER

2. Fix /etc/crypttab first

Subiquity writes the target as dm_crypt-0, but the device is actually opened as cryptroot. Left unfixed, any update-initramfs run produces an initramfs with no root unlock config and the next boot drops to busybox.

sudo dmsetup ls --target crypt        # authoritative name
cat -A /etc/crypttab                  # -A exposes stray whitespace/CRs

If they disagree:

sudo sed -i 's/^dm_crypt-0\b/cryptroot/' /etc/crypttab

Target line should read:

cryptroot UUID=be0ce340-cee1-47bd-aa84-c0d630f56569 none luks

Optionally append ,discard for SSD TRIM (minor information leak — reveals which blocks are unused; generally acceptable on NVMe).

3. Install Clevis and bind to the TPM

sudo apt install -y clevis clevis-luks clevis-tpm2 clevis-initramfs tpm2-tools

sudo clevis luks bind -d /dev/nvme0n1p3 tpm2 '{"pcr_ids":"7","pcr_bank":"sha256"}'

Prompts for the existing passphrase. Adds a new keyslot; passphrase slots stay intact.

Run this exactly once. Each repeat adds another duplicate keyslot.

PCR 7 measures Secure Boot policy — stable across kernel updates and initramfs rebuilds. Don't add PCR 0 or 1; they pick up firmware measurements and break on every BIOS update.

4. Add the tss user hook

clevis-initramfs does not copy the tss user/group into the initramfs, so the TPM2 tools fail at early boot and the passphrase prompt appears anyway. This is the step most guides omit.

sudo tee /etc/initramfs-tools/hooks/tss-user >/dev/null <<'EOF'
#!/bin/sh
PREREQ=""
prereqs() { echo "$PREREQ"; }
case "$1" in prereqs) prereqs; exit 0;; esac
. /usr/share/initramfs-tools/hook-functions
grep '^tss:' /etc/passwd >> "$DESTDIR/etc/passwd"
grep '^tss:' /etc/group  >> "$DESTDIR/etc/group"
EOF
sudo chmod +x /etc/initramfs-tools/hooks/tss-user

5. Rebuild the initramfs

sudo update-initramfs -u -k all

Must complete without cryptsetup: WARNING: target 'cryptroot' not found in /etc/crypttab. If that warning appears, go back to step 2 — do not reboot.

The I: The initramfs will attempt to resume from /dev/dm-2 line is unrelated and harmless (swap on LVM inside the container).

6. Verify before rebooting

cd /tmp && rm -rf ird && mkdir ird && cd ird
unmkinitramfs /boot/initrd.img-$(uname -r) .

cat main/cryptroot/crypttab                      # cryptroot UUID=be0ce340-...
grep '^tss:' main/etc/passwd main/etc/group      # tss present in both
lsinitramfs /boot/initrd.img-$(uname -r) | grep -E 'tpm2_(unseal|load|createprimary)'
sudo clevis luks list -d /dev/nvme0n1p3          # one tpm2 slot, pcr_ids 7

Note: on cryptsetup 2.7 (24.04) the config lives at main/cryptroot/crypttab, not the older main/conf/conf.d/cryptroot.

7. Clean up duplicate bindings

If clevis luks list shows more than one TPM2 slot, confirm a passphrase slot works before removing anything:

sudo cryptsetup luksDump /dev/nvme0n1p3 | grep -E '^  [0-9]+: luks2|^Tokens:|^  [0-9]+: clevis'
sudo cryptsetup luksOpen --test-passphrase --key-slot 0 /dev/nvme0n1p3 && echo "slot 0 OK"

Then unbind the extras (-s is the keyslot number; tokens follow automatically):

sudo clevis luks unbind -d /dev/nvme0n1p3 -s 3
sudo clevis luks unbind -d /dev/nvme0n1p3 -s 5
sudo clevis luks list -d /dev/nvme0n1p3

No initramfs rebuild needed — clevis reads tokens off the disk at boot.

8. Reboot

Keep the passphrase to hand. If it still prompts:

journalctl -b | grep -iE 'clevis|tpm|cryptroot'

Maintenance

Event Action
Kernel update None. Hook and clevis are re-included automatically.
BIOS/UEFI update Usually fine (PCR 7). If it prompts for the passphrase, re-seal.
Secure Boot key change Re-seal.
TPM firmware update Re-seal — field upgrades invalidate sealed data.
BIOS "Clear TPM" Re-seal.

Re-seal:

sudo clevis luks regen -d /dev/nvme0n1p3 -s <slot>

Do not flip the BIOS fTPM switch to "AMD CPU fTPM". The platform has both; switching to the Ryzen firmware TPM presents a different TPM with different keys, and unlock fails until re-bound.

Removal

sudo clevis luks unbind -d /dev/nvme0n1p3 -s <slot>
sudo rm /etc/initramfs-tools/hooks/tss-user
sudo update-initramfs -u -k all

Recovery — busybox at boot

cryptsetup open /dev/nvme0n1p3 cryptroot
exit

Boot continues; fix /etc/crypttab from the running system.


Security caveats

Understand what this does and doesn't buy:

  • Ubuntu's initramfs is neither signed nor measured. Someone with physical access can modify it, boot, and the TPM releases the key — PCR 7 is unchanged. This is exactly why Ubuntu hasn't shipped TPM auto-unlock natively.
  • With PCR 7 alone under stock Microsoft-signed Secure Boot, any other MS-signed bootloader (a stock Ubuntu live USB) yields the same PCR 7 value.

Net: this protects a stolen drive, not a machine an attacker has hands on. For a demo box that's a reasonable trade. For anything holding customer data on a factory floor, the harder path is dracut + systemd-cryptenroll --tpm2-with-pin=yes, or enrolling your own Secure Boot keys and signing a UKI.

Always keep a passphrase keyslot, and store the passphrase somewhere reachable by whoever might have to stand in front of this machine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment