Using sev and sev.es in Incus

We use Incus to deploy VMs with SEV support, and I finally found the time to document the issues I’ve encountered regarding this functionality in Incus.

SEV

The main issue lies in the OVMF files and the selection logic used when launching a VM with SEV enabled.

Currently, the OVMF file is selected solely based on the presence of the security.secureboot or security.csm options, and the lookup is performed by filename. However, SEV requires an OVMF build with the following features:

  • amd-sev
  • verbose-dynamic

and, importantly, without the requires-smm feature.

In most distributions, this is provided as a dedicated OVMF image intended specifically for SEV. For example, on Ubuntu 24.04, the ovmf package installs:

/usr/share/ovmf/OVMF.amdsev.fd

Unfortunately, using this file directly is inconvenient because Incus expects separate OVMF_CODE* and OVMF_VARS* files, whereas OVMF.amdsev.fd is effectively a combined image containing both.

As a workaround, the VM can be started with a configuration similar to:

config:
  limits.memory.hotplug: 64GiB
  raw.apparmor: |
    /usr/share/ovmf/OVMF.amdsev.fd
  raw.qemu: |
    -bios /usr/share/ovmf/OVMF.amdsev.fd
  raw.qemu.conf: |
    [drive][0]

    [drive][1]

    [device "qemu_vmcoreinfo"]
  security.secureboot: "false"
  security.sev: "true"

There may be some unnecessary steps in this configuration, but the key point is that only a single pflash device should remain. Alternatively, it is possible to build OVMF_CODE and OVMF_VARS images with the required features and replace the originals located under /opt/incus/share/qemu.

After that, the VM starts successfully and runs with SEV enabled, which can be verified via dmesg inside the guest. Otherwise, the VM fails to boot and consumes 100% CPU indefinitely.

It would be very helpful if Incus automatically selected the appropriate OVMF image whenever security.sev: true is enabled.

SEV-ES

This case is more complicated.

The required OVMF image should include the following features:

  • amd-sev
  • amd-sev-es
  • verbose-dynamic

However, even with such an OVMF build, I have not been able to successfully start a VM using both:

security.sev: "true"
security.sev.policy.es: "true"

The furthest I have managed to get is the following error:

Log (qemu.log):

qemu-system-x86_64: info: virtual machine state has been rebuilt with new guest file handle.
qemu-system-x86_64: sev_launch_finish: LAUNCH_FINISH ret=-5 fw_error=2 'Guest state is invalid'

So far, I have not been able to make any further progress beyond this point.

I would appreciate any feedback on whether there is a simpler way to achieve this, or if there are flaws in my understanding of the process.

Also, has anyone been able to successfully run a VM with SEV-ES enabled?

Thanks for this tutorial, I moved it into the Tutorials section and added a howto tag.

EDIT: Removed the category and tag again, as this is more a question and a feature request.

The question about SEV-ES remains open.

About AMD SEV - for anyone like me not knowing it yet

SEV is a virtual machine-based confidential computing solution; it protects data-in-use by creating a Trusted Execution Environment, that is defined by the boundaries of the confidential VM. SEV uses one key per virtual machine to isolate guests and the hypervisor from one another. The keys are managed by the AMD Secure Processor. SEV requires enablement in the guest operating system and hypervisor. The guest changes allow the VM to indicate which pages in memory should be encrypted. The hypervisor changes use hardware virtualization instructions and communication with the AMD Secure processor to manage the appropriate keys in the memory controller. AMD has evolved SEV to add new features and new capabilities with each generation of AMD EPYC server CPUs to help address the evolving security landscape. These enhancements are described below.

https://www.amd.com/en/developer/sev.html

Can I add this to the issue so that, in the future, there will be a mechanism for SEV to work out of the box, similar to how it currently works for security.secureboot?

Is this information sufficient? I have the resources available, if needed, to verify that everything works correctly and as expected.