Today I’m diving into the world of Secure Boot, TPM2, and all of the complications that come with wanting a high level of security without having to type a disk encryption key all the time. Ultimately, my goal is to come up with a solution that I can roll out in my Linux-based business environment, but today I’m walking you through the basics of how full disk encryption works with LUKS and enrolling your first key into the TPM.

Contents⌗

Video⌗

Video Thumbnail

Basic LUKS Volume⌗

To learn what I’m doing, I’ll create a LUKS-encrypted volume manually. First, though, make sure you have a disk partition to work on:

# If you need to partition your drive, do so with sgdisk
# Remove existing partition table (MBR + GPT)
# sudo sgdisk --zap-all /dev/sdX
# Create new partition table and one partition full size
# sudo sgdisk -n 1:0:0 -t 1:8309 /dev/sdX

# Or, if you already have a partition table, set the type to 8309 (LUKS) instead of 8300 (LINUX)
# This is what I did
# List partition table
sudo sgdisk -p /dev/sdX
# Set partition 3 to type "Linux LUKS" (8309)
sudo sgdisk -t 1:8309 /dev/sdX

After that, we can format the LUKS partition, then format the ext4 filesystem on top of that partition

# Format your drive partition (mine is mmcblk0p3)
sudo cryptsetup luksFormat --type luks2 /dev/sdX1

# Inspect the LUKS header (just for fun, really)
sudo cryptsetup luksDump /dev/sdX1

# Mount the LUKS volume 
# this creates /dev/mapper/vault block device based name we gave it here - vault
sudo cryptsetup open /dev/sdX1 vault

# Create the filesystem on the LUKS block device, named 'vault'
sudo mkfs.ext4 -L vault /dev/mapper/vault

# Create mount point, mount, and test the new device
sudo mkdir -p /mnt/vault
sudo mount /dev/mapper/vault /mnt/vault
echo "hello" | sudo tee /mnt/vault/test.txt


# get status of the volume (for fun)
sudo cryptsetup status vault
sudo ls -l /dev/mapper/

# Unmount ext4 and then close the crypt volume
sudo umount /mnt/vault
sudo cryptsetup close vault

Managing Key Slots⌗

If you want to backup the LUKS header (in case you make a mistake, you can restore the old header with the old keys):

# Backup
sudo cryptsetup luksHeaderBackup /dev/sdX1 --header-backup-file ~/vault-header.img
# Restore
sudo cryptsetup luksHeaderRestore /dev/sdX1 --header-backup-file ~/vault-header.img

Then we have a few options to add keys:

# Add key slot with a passphrase
sudo cryptsetup luksAddKey /dev/sdX1

# You can also force a keyslot if you want
sudo cryptsetup luksAddKey --key-slot 5 /dev/sdX1

# Add key which is defined by a keyfile
# Generate 512 bytes of random as vault.key
# Obviously protect this key better than your home directory
# Pass in --key-file to mount it
sudo dd if=/dev/urandom of=~/vault.key bs=512 count=1
sudo cryptsetup luksAddKey /dev/sdX1 ~/vault.key

# Just a reminder, you can see how many key slots there are
# And you can tell what type of keys they have
sudo cryptsetup luksDump /dev/sdX1

# And you can test your keys using --test-passphrase
sudo cryptsetup open --test-passphrase /dev/sdX1

# Change a passphrase on a key slot
sudo cryptsetup luksChangeKey /dev/sdX1

# Remove a key by supplying the key itself
sudo cryptsetup luksRemoveKey /dev/sdX1

# Remove a key by supplying a different key (specify the slot number)
# Cannoy delete your own key using this command
sudo cryptsetup luksKillSlot /dev/sdX1 1

Enrolling TPM-Bound keys⌗

We’ll use systemd-cryptenroll for this, so make sure it’s working:

# See if we have a working TPM
sudo systemd-cryptenroll --tpm2-device=list

Let’s now use cryptenroll to add a recovery key - this is randomly generated by systemd, gives you a QR code if you want it. It does not delete existing keys - it just adds a new key using randomness. You don’t have to add recovery keys this way, this is just another way to do it.

sudo systemd-cryptenroll --recovery-key /dev/sdX1

And finally, using it to enroll a TPM:

# Bind to TPM PCR 7
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/sdX1

# Bind to PCR 7 + also require a PIN
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 --tpm2-with-pin=yes /dev/sdX1

# Show what we just did
sudo systemd-cryptenroll /dev/sdX1
sudo cryptsetup luksDump /dev/sdX1

# Also, we can mount manually using this command
sudo cryptsetup open --token-only /dev/sdX1 vault

If we are doing this ‘for real’, and want the device auto-unlocked, systemd can manage this for us with the crypttab also:

# Get UUID of vault from luksDump
sudo cryptsetup luksDump /dev/sdX1
# Add vault to crypttab
echo 'vault UUID=<luks-uuid> none tpm2-device=auto,nofail' | sudo tee -a /etc/crypttab

# If you want to mount it immediately without rebooting, do daemon-reload and start
# The service is 'transient' (generated at runtime), so you can't --enable it
sudo systemctl daemon-reload
sudo systemctl start systemd-cryptsetup@vault.service

# If you reboot, the crypto unlock should happen automatically

Fedora Encrypted Root⌗

Fedora’s installer (Anaconda) already sets up the encrypted volume. The passphrase we enter during installation becomes our recovery key. We just need to enroll a new key slot which is TPM bound, optionally using a PIN.

# Bind to PCR 7 + also require a PIN
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 --tpm2-with-pin=yes /dev/sdX1

# Edit the crypttab entry so it checks the TPM for that crypto volume
sudo nano /etc/crypttab
#   luks-<uuid> UUID=<uuid> none discard,tpm2-device=auto
# (keep the existing options and add tpm2-device=auto)

# Rebuild the initramfs, making sure the TPM2 module is included
sudo dracut --force --regenerate-all --add tpm2-tss