Skip to content

Instantly share code, notes, and snippets.

@crobinso
Last active January 23, 2024 13:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crobinso/830512728bf707a35e73755ed65988c4 to your computer and use it in GitHub Desktop.
Save crobinso/830512728bf707a35e73755ed65988c4 to your computer and use it in GitHub Desktop.
SEV-ES with LUKS

Kickstart file to install Fedora 37 with luks encrypted root

  • login is root:root
  • luks passphrase is MY-LUKS-PASSPHRASE
  • /etc/crypttab setup to autounlock LUKS when we inject SEV secret

luks.ks:

rootpw --plaintext root
firstboot --disable
timezone America/New_York --utc
keyboard --vckeymap=us --xlayouts='us'
lang en_US.UTF-8
reboot
text
skipx

ignoredisk --only-use=vda
clearpart --all --initlabel --disklabel=gpt --drives=vda
part /boot/efi --size=512 --fstype=efi
part /boot --size=512 --fstype=xfs --label=boot
part / --fstype="xfs" --ondisk=vda --encrypted --label=root --luks-version=luks2 --grow --passphrase MY-LUKS-PASSPHRASE

%packages
@^server-product-environment
%end

%post
# Set the secret path as a crypttab keyfile
# Append `keyfile-erase` option to unlink it after unlock
cat /etc/crypttab | awk '{print $1" "$2" /sys/kernel/security/secrets/coco/736869e5-84f0-4973-92ec-06879ce3da0b "$4",keyfile-erase"}' | tee /etc/crypttab
# Put `efi_secret` driver in the initrd
echo 'add_drivers+=" efi_secret "' > /etc/dracut.conf.d/99-efi_secret.conf
# Trigger initrd rebuild
dnf reinstall -y kernel\*
%end

Install the VM on f36 host with the following differences:

  • latest libvirt-daemon-kvm, qemu-system-x86, edk2-ovmf from virt-preview repo
  • cargo install sevctl
  • virt-manager/virt-install from git as of Nov 27 2022
  • libvirt.git as of Nov 27 2022
# virt-preview packages on f36 host:
# $ rpm -q libvirt-daemon qemu-system-x86 edk2-ovmf
# libvirt-daemon-8.8.0-1.fc36.x86_64
# qemu-system-x86-7.1.0-3.fc36.x86_64
# edk2-ovmf-20220826gitba0e0e4c6a17-1.fc36.noarch

# libvirt.git as of Nov 27 2022
VALIDATE="$HOME/src/libvirt/tools/virt-qemu-sev-validate"

# From virt-manager.git
VIRTXML="$HOME/src/virt-manager/virt-xml"
VIRTINSTALL="$HOME/src/virt-manager/virt-install"

VMNAME=lukstest

# Install the VM, full automated
# SEV is not enabled at this point
sudo $VIRTINSTALL \
    --name $VMNAME --ram 8096 --disk size=20 \
    --nographics \
    --location https://dl.fedoraproject.org/pub/fedora/linux/development/37/Server/x86_64/os/ \
    --noreboot \
    --initrd-inject luks.ks \
    --extra-args "inst.ks=file:/luks.ks console=ttyS0" \
    --tpm none \
    --boot firmware=efi,loader.stateless=yes \
    --memorybacking locked=on \
    --launchSecurity sev,policy=$POLICY,kernelHashes=on,session=$SESSION,dhCert=$DHCERT \
    --debug

Now we extract the kernel + initrd + cmdline. This needs to be done every time the kernel is updated inside the VM. You should be prompted for the LUKS password.

sudo virt-get-kernel -d $VMNAME --prefix $VMNAME > get-kernel.txt
KERNEL=$(basename $(cat get-kernel.txt | grep vmlin | cut -f4 -d ' '))
INITRD=$(basename $(cat get-kernel.txt | grep initr | cut -f4 -d ' '))
sudo mv $KERNEL $INITRD /var/lib/libvirt/images

# Pull kernel cmdline out of /boot/loader/entries
sudo virt-copy-out -d $VMNAME /boot/loader/entries .
sudo chown $UID entries
CMDLINE=$(sudo cat entries/* | grep options | tail -1 | cut -f 2- -d ' ')

# Update VM config to boot off external kernel+initrd
sudo $VIRTXML $VMNAME --edit \
    --boot kernel=/var/lib/libvirt/images/$KERNEL,initrd=/var/lib/libvirt/images/$INITRD,cmdline="$CMDLINE"

The following is the validation process.

  • Session blob must be regenerated for every VM run
  • Ensure SEV is enabled in the VM config and appropriate firmware config is used
  • Use virt-qemu-sev-validate to inject the LUKS key
POLICY=5
CERTDIR=$HOME/src/sevcerts/$VMNAME
SEVCTL=$HOME/.cargo/bin/sevctl

# Generate SEV VM config. Must be run on SEV host
rm -rf $CERTDIR; mkdir -p $CERTDIR
sudo $SEVCTL export -f $CERTDIR/sevctl-export.chain
sudo $SEVCTL session $CERTDIR/sevctl-export.chain $POLICY --name $CERTDIR/$VMNAME
DHCERT=`cat $CERTDIR/${VMNAME}_godh.b64`
SESSION=`cat $CERTDIR/${VMNAME}_session.b64`

# Enable SEV and insert session info into the XML
sudo $VIRTXML $VMNAME --edit \
    --launchSecurity sev,policy=$POLICY,kernelHashes=on,session=$SESSION,dhCert=$DHCERT

# Switch to OVMF.amdsev.fd firmware
sudo rm -rf /var/lib/libvirt/qemu/nvram/${VMNAME}_VARS.fd
sudo $VIRTXML $VMNAME --edit \
    --boot firmware=efi,loader.stateless=yes

# Validate the VM
echo -n MY-LUKS-PASSPHRASE > $HOME/secret.txt
sudo virsh start --paused $VMNAME

sudo $VALIDATE \
--domain $VMNAME \
--tek $CERTDIR/${VMNAME}_tek.bin \
--tik $CERTDIR/${VMNAME}_tik.bin \
--inject-secret 736869e5-84f0-4973-92ec-06879ce3da0b:$HOME/secret.txt \
--insecure \
--debug

# Should go to login prompt, no LUKS passphrase needed
sudo virsh console $VMNAME
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment