libvirt: Secure Boot
Description: libvirt, virtualization, virtualization API

# Secure Boot

## Quick configuration

If you have libvirt 8.6.0 or newer, when creating a new VM you can ask for Secure Boot to be enabled with

    <os firmware='efi'>
      <firmware>
        <feature enabled='yes' name='secure-boot'/>
        <feature enabled='yes' name='enrolled-keys'/>
      </firmware>
    </os>

and for it to be disabled with either

    <os firmware='efi'>
      <firmware>
        <feature enabled='no' name='secure-boot'/>
      </firmware>
    </os>

or

    <os firmware='efi'>
      <firmware>
        <feature enabled='yes' name='secure-boot'/>
        <feature enabled='no' name='enrolled-keys'/>
      </firmware>
    </os>

The first configuration will cause unsigned guest operating systems to be rejected, while the remaining two will allow running them. See below for a more detailed explanation of how each knob affects the firmware selection process.

## Older libvirt versions

If your libvirt version is older than 8.6.0 but newer than 7.2.0, then enabling Secure Boot requires a slightly more verbose XML snippet:

    <os firmware='efi'>
      <loader secure='yes'/>
      <firmware>
        <feature enabled='yes' name='secure-boot'/>
        <feature enabled='yes' name='enrolled-keys'/>
      </firmware>
    </os>

Versions older than 7.2.0 require manually providing all information about the firmware and are not covered here. Please refer to the relevant documentation for details.

## Changing an existing VM

When a VM is defined, libvirt will pick the firmware that best satisfies the provided criteria and record this information for use on subsequent boots. The resulting XML configuration will look either like this:

    <os firmware='efi'>
      <firmware>
        <feature enabled='yes' name='enrolled-keys'/>
        <feature enabled='yes' name='secure-boot'/>
      </firmware>
      <loader readonly='yes' secure='yes' type='pflash'>/usr/share/edk2/ovmf/OVMF_CODE.secboot.fd</loader>
      <nvram template='/usr/share/edk2/ovmf/OVMF_VARS.secboot.fd'>/var/lib/libvirt/qemu/nvram/vm_VARS.fd</nvram>
    </os>

or like this:

    <os firmware='efi'>
      <firmware>
        <feature enabled='yes' name='enrolled-keys'/>
        <feature enabled='yes' name='secure-boot'/>
      </firmware>
      <loader type='rom' format='raw'>/usr/share/edk2/aarch64/QEMU_EFI.qemuvars.fd</loader>
      <varstore template='/usr/share/edk2/aarch64/vars.secboot.json' path='/var/lib/libvirt/qemu/varstore/vm.json'/>
    </os>

In order to force libvirt to repeat the firmware autoselection process, it's necessary to remove the <loader> as well as the <nvram> or <varstore> elements, depending on what's applicable. Failure to do so will likely result in an error.

Note that updating the XML configuration as described above is not enough to change the Secure Boot status: the NVRAM/varstore file associated with the VM has to be regenerated from its template as well.

In order to do that, update the XML and then start the VM with

    $ virsh start vm --reset-nvram

This option is only available starting with libvirt 8.1.0, so if your version of libvirt is older than that you will have to delete the NVRAM file manually before starting the VM.

Most guest operating systems will be able to cope with the NVRAM/varstore file being reinitialized, but in some cases the VM will be unable to boot after the change.

## Additional information

There are two parts to enabling Secure Boot: the firmware supporting the feature, and it being active.

Most host operating systems ship a build of EDKII (the open source EFI implementation used for QEMU VMs) that supports the Secure Boot feature, but simply using such a build will not result in unsigned guest operating systems being rejected: for that to happen, keys that can be used to validate the operating system signature need to be provided as well.

Asking for the enrolled-keys firmware feature to be enabled will cause libvirt to initialize the NVRAM/varstore file associated with the VM from a template that contains a suitable set of keys. These keys being present will cause the firmware to enforce the Secure Boot signing requirements.

The opposite configuration, where the feature is explicitly disabled, will result in no keys being present in the NVRAM/varstore file. Unable to verify signatures, the firmware will allow even unsigned operating systems to run.

If running unsigned code is desired, it's also possible to ask for the secure-boot feature to be disabled, which will cause libvirt to pick a build of EDKII that doesn't have Secure Boot support at all.

The main difference between using a build of EDKII that has Secure Boot support but without keys enrolled and one that doesn't have Secure Boot support at all is that, with the former, you could enroll your own keys and securely run an operating system that you've built and signed yourself. If you are only planning to run existing, off-the-shelf operating system images, then the two configurations are functionally equivalent.