From a8228df780af6f803da1a95e22ddea912b9f36ae Mon Sep 17 00:00:00 2001 From: Lukas Greve Date: Tue, 15 Sep 2026 11:04:19 +0200 Subject: [PATCH] feat: add TPM2 auto-unlock support to encrypted storage ingredient Add cryptsetup, tpm2-tools and tpm2-tss to every encrypted dish so the initrd can be rebuilt with TPM2 support. A guarded %pre stashes a preseeded LUKS passphrase from the kickstart, and a guarded %post enrolls PCR 7-bound auto-unlock via systemd-cryptenroll, switches crypttab to tpm2-device=auto and regenerates the initrd. Without a preseeded passphrase or a TPM device the enrollment is skipped and the system keeps the regular passphrase prompt. --- cook/ingredients/storage/encrypted.ks | 67 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/cook/ingredients/storage/encrypted.ks b/cook/ingredients/storage/encrypted.ks index 20a6abc..019671c 100644 --- a/cook/ingredients/storage/encrypted.ks +++ b/cook/ingredients/storage/encrypted.ks @@ -6,3 +6,70 @@ clearpart --all --initlabel # Erase all partitions and Initializes the disk labe part /boot/efi --fstype="efi" --size=512 --fsoptions="umask=0077,shortname=winnt" --label=efi # Creates a 512 MiB EFI system partition part /boot --fstype="ext4" --size=2048 --label=boot # Creates a 2048 MiB ext4 boot partition part / --fstype="ext4" --grow --label=root --mkfsoptions="-O encrypt,fast_commit" --encrypted --passphrase= # Create a single encrypted root partition with the remaining space. + +# Tools for LUKS management and TPM2-based auto-unlock +%packages --exclude-weakdeps + +cryptsetup # Userspace tool for dm-crypt, required to open and manage the LUKS root device +tpm2-tools # TPM2 tools, provides the dracut tpm2-tss module needed to rebuild the initrd for TPM2 auto-unlock +tpm2-tss # TPM2 TSS libraries, runtime dependency of tpm2-tools and systemd-cryptenroll + +%end # End of the packages section + +# Stash a preseeded LUKS passphrase so the %post below can enroll TPM2-based +# auto-unlock. Only acts when `--passphrase=` was preseeded on the encrypted +# `part /` line; with the interactive default (empty passphrase) nothing is +# stashed and the %post enrollment is skipped cleanly. +%pre --logfile=/tmp/luks-tpm-pre.log + +KS_FILE="" +for candidate in /run/install/ks.cfg /tmp/ks.cfg; do + if [ -f "$candidate" ]; then + KS_FILE="$candidate" + break + fi +done + +if [ -n "$KS_FILE" ]; then + LINE=$(grep -E '^[[:space:]]*part[[:space:]]+/[[:space:]].*--encrypted' "$KS_FILE" | grep -- '--passphrase=' | head -n 1) + if [ -n "$LINE" ]; then + PW=${LINE#*--passphrase=} + case "$PW" in + \"*) PW=${PW#\"}; PW=${PW%%\"*} ;; + *) PW=${PW%%[[:space:]]*} ;; + esac + if [ -n "$PW" ]; then + printf '%s' "$PW" > /tmp/.luks-passphrase + chmod 600 /tmp/.luks-passphrase + fi + fi +fi + +%end + +# Enroll TPM2-based LUKS auto-unlock (PCR 7-bound) when both guards hold: a +# TPM2 device is available at install time and a passphrase was preseeded in +# the kickstart (stashed by the %pre above). Otherwise the system keeps the +# regular passphrase prompt at boot. On any failure the LUKS configuration is +# left untouched, so the worst case is a passphrase prompt on every boot. +%post --logfile=/root/luks-tpm-post.log + +if [ -e /dev/tpmrm0 ] && [ -s /tmp/.luks-passphrase ]; then + set -x + LUKSUUID=$(awk '$2 ~ /^UUID=/ {sub(/^UUID=/, "", $2); print $2}' /etc/crypttab) + LUKSDEV="/dev/disk/by-uuid/$LUKSUUID" + if systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 --unlock-key-file=/tmp/.luks-passphrase "$LUKSDEV"; then + sed -i 's| none discard,x-initrd.attach| tpm2-device=auto,discard,x-initrd.attach|' /etc/crypttab + if ! grep -q 'tpm2-device=auto' /etc/crypttab; then + sed -i -E 's|[[:space:]]none([[:space:]]|$)| tpm2-device=auto,discard\1|' /etc/crypttab + fi + if grep -q 'tpm2-device=auto' /etc/crypttab; then + MID=$(cat /etc/machine-id) + KVER=$(ls /usr/lib/modules | head -n 1) + dracut -f --kver "$KVER" "/boot/efi/$MID/$KVER/initrd" + fi + fi + shred -u /tmp/.luks-passphrase 2>/dev/null || true +fi + +%end