[LXD] Support for AMD SEV in VM

,
Project LXD
Status Implemented
Author(s) @gabrielmougard
Approver(s) @stgraber
Release 5.13

Abstract

We’d like to add support for enabling AMD SEV (SEV stands for Secure Encrypted Virtualization ; it is an extension of SME (Secure Memory Encryption) for virtual machines; SME is an x86 instruction set introduced by AMD for page-granular memory encryption support using a single ephemeral key) on LXD VMs.
This will have LXD instruct QEMU to encrypt guest memory as well as restrict some features.

Rationale

Enabling AMD SEV for a LXD VM would allow a user to get work done in a virtual machine in a context of Zero-Trust computing (you don’t necessarily trust your cloud provider for keeping your data safe). Also, this new feature allows a user to resist a “cold boot attack” : with the advent of persistent memory like NVDIMM, it is now possible to literally yank a memory module out and plug it somewhere else in order to analyse it. With AMD SEV, the memory is encrypted and the attacker would need the certificate’s key to decipher it.

Specification

Design

  1. Detecting if the host supports SEV
    First, we want to validate the presence of SME and SEV in the CPU flags. Also, we want to check if SEV-ES (ES stands for Encrypted State and it allows the encryption of the CPU register state as well as the memory) is supported, again reading the CPU flag. Once the CPU flags are validated, we need to validate QEMU’s support for SEV through QMP’s query-sev-capabilities command

  2. We need a new set of user config keys to specify is SEV is enabled or not
    A not-too-complex proposal could look like this :

- security.sev (bool) // is SEV enabled for this VM
- security.sev.policy.es (bool) // is SEV-ES enabled for this VM
- security.sev.session.dh (string) // guest owner\'s base64-encoded Diffie-Hellman key 
- security.sev.session.data (string) // guest owner\'s base64-encoded session blob
  1. Launch SEV/SEV-ES guest VM
    Given a successful harware validation (1) and a proper user config (2), we launch the SEV/SEV-ES guest VM through QEMU’s command line. Here is an example of a QEMU command :
qemu-system-x86_64 \
  -enable-kvm \
  -cpu EPYC-Milan-v2,stepping=0 \
  -smp 4,maxcpus=64 \
  -m 2048M,slots=5,maxmem=100G \
  -no-reboot \
  -drive if=pflash,format=raw,unit=0,file=/home/amd/sev-release-2022-02-10/usr/local/share/qemu/OVMF_CODE.fd,readonly \
  -drive if=pflash,format=raw,unit=1,file=/home/amd/sev-release-2022-02-10/ubuntu-18.04.fd \
  -device virtio-net-pci,disable-legacy=on,iommu_platform=true,netdev=netdev0,romfile= \
  -netdev tap,script=/home/amd/qemu-ifup,id=netdev0 \
  -drive file=/home/amd/sev-release-2022-02-10/ubuntu-18.04.qcow2,if=none,id=disk0,format=qcow2 \
  -device virtio-scsi-pci,id=scsi0,disable-legacy=on,iommu_platform=true \
  -device scsi-hd,drive=disk0 \
  -object memory-backend-memfd-private,id=ram1,size=2G,share=true \
  -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1 \
  -machine q35,confidential-guest-support=sev0,memory-backend=ram1,kvm-type=protected \
  -nographic -monitor pty -monitor unix:monitor,server,nowait \
  -qmp unix:./qmp_sock-exp,server
  1. Through QEMU’s QMP, query that the launched VM has SEV enabled and running and get some information
    With query-sev and query-sev-capabilities, we’re able to fetch the some information on the SEV/SEV-ES running guest like CBitPos (if it is of any interest for us) so that maybe we’d want to store it somewhere.

API changes

The following keys

- security.sev (bool) // is SEV enabled for this VM
- security.sev.policy.es (bool) // is SEV-ES enabled for this VM
- security.sev.session.dh (string) // guest owner\'s base64-encoded Diffie-Hellman key 
- security.sev.session.data (string) // guest owner\'s base64-encoded session blob

will be added to the Config map :

type InstancePut struct {
	...
    // Instance configuration (see doc/instances.md)
	Config map[string]string `json:"config" yaml:"config"`
    ...
}

CLI changes

No CLI changes. First, I think that we could simply add the config keys listed above through the lxc config edit <instance> command.

Database changes

No database change.

Upgrade handling

No data migration required a priori.

Could you define SEV and SNP in this context please?
Its usual to define acronyms the first time you use them in a document.

Thanks

Because you’re adding a feature and new config keys you should at least add a new API extension, so worth specifying what it will be called here for readers to be able to check if their LXD supports this feature.

As discussed, we’ll only do SEV and SEV-ES at this point, so can drop SNP from the spec.