I used to think that secure boot and tpm are just gimmicky features, that don't really help with security. But if you set up everything correctly, you'll get a somewhat steal proof computer (depenging on the UEFI and linux passwords strength) without having to deal with any inconveniences.

TPM Data-at-rest Encryption

Your computer will boot and decrypt the data on your root volume automatically without asking the decryption password if certain conditions are met. For example:

  • Firmware has not been modified (PCR0)
  • Secure Boot State (PCR7)

I'm not certain about other PCRs. But I use PCRs 0,3,5,7. Read more about PCRs at Archwiki.

First of all, you need to encrypt your root partition with LUKS2.

To do that, you need to boot into archiso, copy all the data from root partition to another drive, encrypt and mount it to restore all data.

Use a strong password for encryption, as it will be used to restore access to your data in case something goes wrong with your TPM.

# rsync -aAXv /mnt/your_root_drive_mount/ /mnt/backup/
# umount /mnt/your_root_drive_mount/
# cryptsetup luksFormat --type luks2 /dev/your_root_device
# cryptsetup open /dev/your_root_device some_name
# mount /dev/mapper/some_name /mnt/your_root_drive_mount/
# rsync -aAXv /mnt/backup/ /mnt/your_root_drive_mount/

Mount your boot partition to /mnt/your_root_drive_mount/boot and chroot into it.

Change your mkinitcpi.conf, so your HOOKS look something like this:

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

And add tpm modules:

MODULES=( tpm tpm_crb tpm_tis tpm_tis_core )

Install tpm2-tss:

pacman -S tpm2-tss

Add the following line to /etc/crypttab.initramfs:

cryptroot /dev/disk/by-uuid/<PUT_UUID_OF_ENCRYPTED_PARTITION_HERE> - tpm2-device=auto,discard

You may want to remove the discard option for additional security.

Generate new iniramfs:

mkinitcpio -P

Change your root device in kernel command line:

root=/dev/mapper/cryptroot ...

If you use sbupdate, change it in /etc/sbupdate.conf

UPDATE 2023: Sbupdate is no longer maintained, use /etc/mkinitcpio.d/linux.preset as described here and put your command line arguments into files in /etc/cmdline.d/ to generate the UKI. Use this initcpio hook to sign it automatically.

And don't forget to run sbupdate to add newly generated initramfs. If you are using mkinitcpio to generate the UKI, use mkinitcpio -P instead.

Exit chroot.

If you haven't enabled Secure boot yet, you can add TPM key now for convenience, with only 0 pcr:

systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0 /dev/your_root_device

Else, just use tpm2-pcrs=0,7

If you want to use PCRs 3 and 5, you'll need to reenroll key when your system booted up.

sudo systemd-cryptenroll /dev/your_root_device --wipe-slot=tpm2
sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0,3,5,7 /dev/your_root_device

Note, that PCRs 3 and 5 will change between your system and archiso, so your root partition won't unlock if enrolled from different boot media.

You can remove the password from your luks encrypted root partition and only leave tpm unlock, but that setup is prone to failure. Updating the bios would stop your system from booting. I strongly recommend leaving the password.

Enabling Secure boot

First of all, you need to generate your own keys to use with secure boot. To do that, I use a script recommended by arch wiki.

# mkdir /etc/efi-keys
# cd !$
# curl -L -O https://www.rodsbooks.com/efi-bootloaders/mkkeys.sh
# chmod +x mkkeys.sh
# ./mkkeys.sh

Now you need to generate and sign a unified kernel image. That can be done manually with objcopy, but I prefer to use mkinitcpio method. It also runs on kernel updates.

There's no need to include initrd= parameter in your cmdline. Microcode loading is also handled automatically.

Run mkinitcpio -P and add generated efi file to boot entries:

sudo mkinitcpio -P
sudo efibootmgr --create --disk /dev/nvme0n1 --part 1 --label "Linux" --loader "EFI\BOOT\linux-signed.efi" --verbose

You might also need to activate the boot entry with -a flag.

That might not be necessary if you place the UKI at /boot/EFI/BOOT/bootx64.efi as most bios'es default to this location.

After that, enroll your keys to secure boot. Some UEFIs provide a menu to add keys from a USB drive. In that case, copy your keys to USB with FAT32 filesystem and add DB, KEK and PK. Use either .esl or .auth.

DON'T REMOVE THE FACTORY KEYS!!! (GPU Firmware is signed by Microsoft's UEFI key. You won't have display output until OS boots up if you remove it. CMOS reset won't help. The only solution when the system doesn't boot is BIOS reflash) You can remove or add the factory keys afterwards. I recommend doing that for additional security.

If you don't have the menu to add keys in UEFI, you need to set secure boot to setup mode and boot to your system. Then the keys can be added with sbkeysync tool.

# mkdir -p /etc/secureboot/keys/{db,dbx,KEK,PK}

Put your keys in these folders and

# sbkeysync --verbose
# sbkeysync --verbose --pk

The PK key should be added last. That will put your secure boot into user mode. If the last command failed to enroll PK key, use efi-updatevar.

# efi-updatevar -e -f PK.auth PK

If that fails, removing the immutable flag from /sys/firmware/efi/efivars/PK-*

If you want to leave the Microsoft UEFI key, install dbxtool and update the DBX database with it.

After enrolling your keys, boot into UEFI and enable secure boot.

Archiso with Secure boot

Extract archiso contents to a USB drive with FAT32 filesystem.

Don't forget to change the filesystem label to ARCH_YYYYMM (e.g. ARCH_202108) of your iso.

Sign BOOTx64.EFI and vmlinuz-linux with your keys:

sudo sbsign --key /etc/efi_keys/DB.key --cert /etc/efi_keys/DB.crt --output EFI/BOOT/BOOTx64.EFI EFI/BOOT/BOOTx64.EFI
sudo sbsign --key /etc/efi_keys/DB.key --cert /etc/efi_keys/DB.crt --output arch/boot/x86_64/vmlinuz-linux arch/boot/x86_64/vmlinuz-linux

Now you can boot with this USB drive without changing secure boot state.

Additional Security

For additional security it's recommended to disable USB boot, lock the boot order, disable boot select menu and enable intrusion detection (if present).


3 Comments latest

  • Ilya_MZP Author

    Do note that MSI motherboards come with misconfigured secure boot. You need to change "Image execution policy" to "Deny execute". Otherwise it will execute any unsigned binary.

  • Ilya_MZP Author

    I recommend adding the fsck.repair=yes kernel cmdline option. If your computer gets improperly shut down, with this option it will try to fix problems that usually require manually answering yes. Without that option you'd have to use live media to restore your system, as systemd-fsck would fail and you'd get an unbootable systyem. With secure boot and encryption that gets annoying really fast. So far I had 0 issues after multiple improper power offs on my laptop.

  • Ilya_MZP Author

    systemd-boot supports UKIs and automatically adds them too boot entries if they are placed in esp/EFI/Linux/ Systemd-boot is also signed. This allows you to have multiple boot options and still have a fully signed boot chain, where no one else is able to modify the cmdline or initrd.