Skip to content

pccr10001/pve-trusted-boot

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PVE Trusted Boot with TPM and LUKS

Goal

  • Install Proxmov VE
  • Enforce Secure boot
  • Keep kernel and initramfs update automatically
  • Seal with TPM to protect kernel, initramfs and kernel cmdline.

My Environment

  • Intel N100
  • 8G DDR4
  • 128G NVMe SSD
  • BIOS Supports TPM 2.0 and Secure Boot

Boot with Debian Live CD

Partition

  • My SSD is 128G NVMe, locate at /dev/nvme0n1
  • Partition Table
    • 500M EFI /boot/efi
    • 500M Boot /boot
    • 4G Swap
    • 114G LVM for root and VMs
  • Using fdisk to part the disk.
root@debian:~# fdisk /dev/nvme0n1

Welcome to fdisk (util-linux 2.38.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-250069646, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-250069646, default 250068991): +500M

Created a new partition 1 of type 'Linux filesystem' and of size 500 MiB.

Command (m for help): n
Partition number (2-128, default 2):
First sector (1026048-250069646, default 1026048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (1026048-250069646, default 250068991): +500M

Created a new partition 2 of type 'Linux filesystem' and of size 500 MiB.

Command (m for help): n
Partition number (3-128, default 3):
First sector (2050048-250069646, default 2050048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2050048-250069646, default 250068991): +4G

Created a new partition 3 of type 'Linux filesystem' and of size 4 GiB.

Command (m for help): n
Partition number (4-128, default 4):
First sector (10438656-250069646, default 10438656):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (10438656-250069646, default 250068991):

Created a new partition 4 of type 'Linux filesystem' and of size 114.3 GiB.
  • Then set labels and type for each partitions
Command (m for help): t
Partition number (1-4, default 4): 1
Partition type or alias (type L to list all): 1

Changed type of partition 'Linux filesystem' to 'EFI System'.

Command (m for help): t
Partition number (1-4, default 4): 2
Partition type or alias (type L to list all): 4

Changed type of partition 'Linux filesystem' to 'BIOS boot'.

Command (m for help): t
Partition number (1-4, default 4): 3
Partition type or alias (type L to list all): swap

Changed type of partition 'Linux filesystem' to 'Linux swap'.

Command (m for help): t
Partition number (1-4, default 4): 4
Partition type or alias (type L to list all): lvm

Changed type of partition 'Linux filesystem' to 'Linux LVM'.

Command (m for help):
  • Save changes to disk.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.

root@debian:~#

Format partitions

  • Install FAT32 tools
    • apt install dosfstools
root@debian:~# apt install dosfstools
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  dosfstools
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 142 kB of archives.
After this operation, 323 kB of additional disk space will be used.
Get:1 http://deb.debian.org/debian bookworm/main amd64 dosfstools amd64 4.2-1 [142 kB]
Fetched 142 kB in 0s (723 kB/s)
Selecting previously unselected package dosfstools.
(Reading database ... 83280 files and directories currently installed.)
Preparing to unpack .../dosfstools_4.2-1_amd64.deb ...
Unpacking dosfstools (4.2-1) ...
Setting up dosfstools (4.2-1) ...
Processing triggers for man-db (2.11.2-2) ...
  • Format partitions
root@debian:~# mkfs.fat -F32 /dev/nvme0n1p1
mkfs.fat 4.2 (2021-01-31)

root@debian:~# mkfs.ext4 /dev/nvme0n1p2
mke2fs 1.47.0 (5-Feb-2023)
Discarding device blocks: done
Creating filesystem with 512000 1k blocks and 128016 inodes
Filesystem UUID: f9abf8f0-5925-4a6d-8e5e-7d0e1aee40a8
Superblock backups stored on blocks:
        8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

root@debian:~# mkswap /dev/nvme0n1p3
Setting up swapspace version 1, size = 4 GiB (4294963200 bytes)
no label, UUID=69b75414-231a-471c-a6fe-8b948d51ffcd

root@debian:~#

Setup LUKS

  • Install related tools

    • apt install clevis clevis-tpm2 clevis-luks cryptsetup tpm2-tools
  • Create LUKS on /dev/nvme0n1p4

    • Please define a password to unlock the partition.
    • cryptsetup luksFormat /dev/nvme0n1p4
root@debian:~# cryptsetup luksFormat /dev/nvme0n1p4

WARNING!
========
This will overwrite data on /dev/nvme0n1p4 irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/nvme0n1p4:
Verify passphrase:
root@debian:~#
  • Open encrypted partition and mount it on cryptroot
    • cryptsetup open /dev/nvme0n1p4 cryptroot
root@debian:~# cryptsetup open /dev/nvme0n1p4 cryptroot
Enter passphrase for /dev/nvme0n1p4:
root@debian:~#

Setup LVM

  • Install LVM tools
    • apt -y install lvm2
  • Create PV
    • pvcreate /dev/mapper/cryptroot
root@debian:~# pvcreate /dev/mapper/cryptroot
  Physical volume "/dev/mapper/cryptroot" successfully created.
  • Create VG
    • vgcreate pve /dev/mapper/cryptroot
root@debian:~# vgcreate pve /dev/mapper/cryptroot
  Volume group "pve" successfully created
  • Create LV
    • I chosed 40G as root for PVE
root@debian:~# lvcreate -L 40G -n root pve
  Logical volume "root" created.
root@debian:~# lvcreate -l 100%FREE --thinpool data pve
  Thin pool volume with chunk size 64.00 KiB can address at most <15.88 TiB of data.
  Logical volume "data" created.
  • Format PVE root
root@debian:~# mkfs.ext4 /dev/pve/root
mke2fs 1.47.0 (5-Feb-2023)
Creating filesystem with 10485760 4k blocks and 2621440 inodes
Filesystem UUID: 6d9ec1fc-8743-4748-ba20-766541debbbb
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624

Allocating group tables: done
Writing inode tables: done
Creating journal (65536 blocks): done
Writing superblocks and filesystem accounting information: done
root@debian:~#

Install Debian

  • Mount root for PVE
    • mount /dev/pve/root /mnt
  • Install debootstrap
    • apt install -y debootstrap
  • Install Debian with debootstrap
    • You can also change mirror for APT.
    • debootstrap --arch amd64 stable /mnt http://free.nchc.org.tw/debian
  • Mount system directory for chroot
mount --make-rslave --rbind /proc /mnt/proc
mount --make-rslave --rbind /sys /mnt/sys
mount --make-rslave --rbind /dev /mnt/dev
mount --make-rslave --rbind /run /mnt/run
  • Chroot to Debian
    • chroot /mnt
  • Mount /boot
    • mount /dev/nvme0n1p2 /boot
    • mkdir /boot/efi
    • mount /dev/nvme0n1p1 /boot/efi
  • Update APT sources
root@debian:~# cat > /etc/apt/sources.list << EOF
deb http://free.nchc.org.tw/debian/ bookworm main contrib non-free non-free-firmware
deb-src http://free.nchc.org.tw/debian/ bookworm main contrib non-free non-free-firmware

deb http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
deb-src http://security.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware

deb http://free.nchc.org.tw/debian/ bookworm-updates main contrib non-free non-free-firmware
deb-src http://free.nchc.org.tw/debian/ bookworm-updates main contrib non-free non-free-firmware
EOF

root@debian:~# apt update
  • Update /etc/fstab
/dev/nvme0n1p2          /boot          ext4    defaults    0      2
/dev/nvme0n1p1          /boot/efi      vfat    defaults    0      1
/dev/mapper/pve-root    /              ext4    defaults    0      1
  • Add /etc/crypttab
    • echo "cryptroot UUID=$(blkid -o value -s UUID /dev/nvme0n1p4) none luks,discard" > /etc/crypttab
  • Configute timezone
    • dpkg-reconfigure tzdata
  • Configure Locales
    • apt install -y locales
    • `dpkg-reconfigure locales
  • Set password for root
    • passwd root
  • Install Kernel
    • Remove Realtek firmware if you don't need it.
    • apt install -y linux-image-amd64 firmware-linux firmware-realtek
  • Setup Hostname
    • echo "pvebox2" > /etc/hostname
  • Setup /etc/hosts
    • PVE needs to resolve IP with full FQDN hostname, replace following entries and save to /etc/hosts
127.0.0.1 localhost
{LAN_IP_ADDRESS} {HOSTNAME} {HOSTNAME}.{FQDN}

::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# Example

127.0.0.1 localhost
192.168.2.1 pvebox2 pvebox2.example.tld

::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
  • Install Grub2
    • apt install -y grub-efi-amd64-signed grub2
    • grub-install --target=x86_64-efi --uefi-secure-boot --efi-directory=/boot/efi /dev/nvme0n1
    • update-grub
  • Configure network
    • Set DNS server in /etc/ressolv.conf
    • Configure network setting in /etc/network/interfaces
allow-hotplug enp1s0
iface enp1s0 inet static
    address 192.168.2.2
    netmask 255.255.255.0
    gateway 192.168.2.1

Configure LUKS

  • Install related tools
    • apt install clevis-tpm2 clevis-luks clevis cryptsetup clevis-initramfs cryptsetup-initramfs lvm2
  • Bind LUKS to TPM without checking PCR
    • clevis luks bind -d /dev/nvme0n1p4 tpm2 '{}'
  • Reboot
    • You will see following output in boot logs, LUKS unlock with TPM2 and boot successfully

Install Proxmox

  • Following instruction from Proxmox Wiki
  • Enable Proxmox APT source
    • echo "deb [arch=amd64] http://download.proxmox.com/debian/pve bookworm pve-no-subscription" > /etc/apt/sources.list.d/pve-install-repo.list
    • apt install -y wget
    • wget https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg
    • apt update && apt full-upgrade -y
  • Install Proxmox kernel
    • apt install proxmox-default-kernel -y
    • reboot
  • Install Proxmox
    • apt install proxmox-ve postfix open-iscsi chrony -y
  • Remove Debian kernel image
    • apt remove linux-image-amd64 'linux-image-6.1*'
    • update-grub
    • reboot
  • Add local-lvm storage
    • pvesm add lvmthin local-lvm --thinpool data --vgname pve
  • Enable Secure boot in BIOS
  • Now your system will boot with

Enable Trusted Boot for PVE

  • Check TPM hash algorithm
    • tpm2_pcrread
    • Please check banks in TPM, make sure ID 7,8,9 have values.
    • Check hash algorithm that contains ID 7,8,9, eg. SHA256
  • Unbind LUKS with TPM
root@pvebox2:~# clevis luks unbind -d /dev/nvme0n1p4 -s 1
The unbind operation will wipe a slot. This operation is unrecoverable.
Do you wish to erase LUKS slot 1 on /dev/nvme0n1p4? [ynYN] y
Enter any remaining passphrase:
  • Bind LUKS with TPM PCR ID 7,8,9
    • clevis luks bind -d /dev/nvme0n1p4 tpm2 '{"pcr_ids":"7,8,9"}'
    • You need to input password during boot if you update kernel and initramfs.

Enable auto-sealing during updating kernel and initramfs

  • Root access will BREAK this mechanism, don't setup up this if you want to share root access to others.
  • To make LUKS unlock automatically, we need to unbind and re-bind LUKS with PCR ID 7,8,9
  • Create a unlock key in /root
    • dd if=/dev/urandom of=/root/.luks_unlock_key bs=1 count=32
    • chmod 400 /root/.luks_unlock_key
  • Add key to LUKS
    • cryptsetup luksAddKey /dev/nvme0n1p4 /root/.luks_unlock_key
  • Create /etc/systemd/system/tpm-full-reseal.service to bind LUKS with TPM during boot
  • Create re-bind script /usr/local/sbin/tpm-full-reseal-post-boot.sh
  • Enable reseal service
    • chmod 700 /usr/local/sbin/tpm-full-reseal-post-boot.sh
    • systemctl enable tpm-full-reseal.service
  • Create initramfs hook /etc/initramfs/post-update.d/99-tpm-auto-reseal
  • Enable initramfs hook
    • chmod 700 /etc/initramfs/post-update.d/99-tpm-auto-reseal

Testing

  • Check LUKS is binded with TPM PCR ID 7,8,9
root@pvebox2:~# clevis luks list -d /dev/nvme0n1p4
2: tpm2 '{"hash":"sha256","key":"ecc","pcr_bank":"sha256","pcr_ids":"7,8,9"}'
  • Update initramfs to check unseal is working
root@pvebox2:~# update-initramfs -k all -u
update-initramfs: Generating /boot/initrd.img-6.8.12-11-pve
TPM Hook: initramfs for kernel 6.8.12-11-pve has been updated at /boot/initrd.img-6.8.12-11-pve.
Starting TPM auto-reseal process.
Unbinding existing TPM token from slot 2...
Binding temporary token using PCR 7...
Creating trigger file for post-reboot finalization...
TPM Hook: Successfully prepared system for reboot. A reboot is required to finalize TPM configuration.
Running hook script 'zz-proxmox-boot'..
Re-executing '/etc/kernel/postinst.d/zz-proxmox-boot' in new private mount namespace..
No /etc/kernel/proxmox-boot-uuids found, skipping ESP sync.
System booted in EFI-mode but 'grub-efi-amd64' meta-package not installed!
Install 'grub-efi-amd64' to get updates.

About

Enable trusted boot with LUKS and TPM to protect root partition and VM storage.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages