Introduction

These instructions let you setup a virtual machine setup based on KVM and Tianocore which has secure boot on. This setup already has Microsoft and distribution-specific keys built-in.

These instructions should be run as a normal user. We assume sudo has been installed and the user who runs the commands can use sudo to get root privileges.

Initial setup

Manual

Install ovmf and qemu-system-x86:

$ sudo apt install ovmf qemu-system-x86 gpg debian-keyring

Create a directory to store the virtual machine files:

$ mkdir ~/secureboot-vm
$ cd ~/secureboot-vm

Download and verify some installation media which supports UEFI and SecureBoot, e.g. a Debian network install AMD64 ISO image (check for the latest version here):

$ base=https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/
$ keyring=/usr/share/keyrings/debian-role-keys.gpg
$ wget $base/SHA512SUMS $base/SHA512SUMS.sign
$ mkdir ~/.gnupg ; chmod 700 ~/.gnupg
$ gpg --no-options --no-default-keyring --keyring $keyring --verify SHA512SUMS.sign SHA512SUMS
$ grep 'debian-[0-9.]*-amd64-netinst.iso$' SHA512SUMS | tr -s ' ' | cut -d' ' -f2 | head -n1 | xargs -i wget -N -c "$base/{}"
$ sha512sum --check --ignore-missing --strict SHA512SUMS
$ rm -f SHA512SUMS*

For convenience, create a script to launch the VM:

$ echo > start-vm <<EOF
#!/bin/bash

set -Eeuxo pipefail

MACHINE_NAME="test"
QEMU_IMG="${MACHINE_NAME}.img"
SSH_PORT="5555"
OVMF_CODE="/usr/share/OVMF/OVMF_CODE_4M.ms.fd"
OVMF_VARS_ORIG="/usr/share/OVMF/OVMF_VARS_4M.ms.fd"
OVMF_VARS="$(basename "${OVMF_VARS_ORIG}")"

if [ ! -e "${QEMU_IMG}" ]; then
        qemu-img create -f qcow2 "${QEMU_IMG}" 8G
fi

if [ ! -e "${OVMF_VARS}" ]; then
        cp "${OVMF_VARS_ORIG}" "${OVMF_VARS}"
fi

qemu-system-x86_64 \
        -enable-kvm \
        -cpu host -smp cores=4,threads=1 -m 4096 \
        -object rng-random,filename=/dev/urandom,id=rng0 \
        -device virtio-rng-pci,rng=rng0 \
        -name "${MACHINE_NAME}" \
        -drive file="${QEMU_IMG}",format=qcow2 \
        -net nic,model=virtio -net user,hostfwd=tcp::${SSH_PORT}-:22 \
        -vga virtio \
        -machine q35,smm=on \
        -global driver=cfi.pflash01,property=secure,value=on \
        -drive if=pflash,format=raw,unit=0,file="${OVMF_CODE}",readonly=on \
        -drive if=pflash,format=raw,unit=1,file="${OVMF_VARS}" \
        $@
EOF

And make it executable:

$ chmod a+x start-vm

This script will automatically create a QEMU image (default: test.img) and create a local copy of the OVMF code section (which stores writeable UEFI variables). Additional parameters for QEMU can be passed to the script on execution.

Launch the VM for the first time, with the installation media:

$ ./start-vm -cdrom ./debian-*-amd64-netinst.iso -boot menu=on

Explanation

The last five lines of the qemu-system-x86_64 invocation are the important ones:

Passing -boot menu=on to qemu-system-x86_64 means that you will have more time to press ESC during boot to enter the UEFI menu.

Using if=virtio for the first drive stanza should have better performance, but it means that it won't be recognised by the UEFI firmware (it can be enabled after a system has been installed).

Once installed, you'll be able to SSH to the virtual machine by connecting to localhost, port 5555 (e.g. ssh -p5555 user@localhost).

Of course, the start-vm script above is just an example and can be adapted to suit your own needs.

Alternatively: using virt-manager

It is really easy to activate secure boot by using virt-manager, ovmf and qemu-system-x86:

  1. Choose Customize configuration before install
    http://34.83.134.122/virt-manager1.png

  2. Choose Q35 as Chipset and OVMF_CODE_4M.ms.fd as Firmware
    http://34.83.134.122/virt-manager2.png

  3. That's all!

Change the boot order

For ovmf, it is usually necessary to change the boot order because the UEFI shell has the highest boot priority (set in OVMF_VARS*.ms.fd).

Press <ESC> when the machine boots and you should see a menu like this:

  Select Language: <Standard English>

▶ Device Manager
▶ Boot Manager
▶ Boot Maintenance Manager

  Continue
  Reset

Tip

Secure boot settings, including the ability to enable/disable secure boot, can be found under Device ManagerSecure Boot Configuration.

Navigate through the UEFI menus Boot Maintenance ManagerBoot OptionsChange Boot Order.

Next, you will see a list like this (the exact number and order of the items may vary):

<UEFI QEMU HARDDISK QM00001>
<EFI Internal Shell>
<UEFI QEMU DVD-ROM QM00005>
<UEFI PXEv4 (MAC:...)>
<UEFI PXEv4 (MAC:...) 2>
<UEFI PXEv6 (MAC:...)>
<UEFI HTTPv4 (MAC:...)>
<UEFI HTTPv6 (MAC:...)>

Press <enter> and use + and - to change the order of the entries so that the hard disk is first and the DVD entry is second:

<UEFI QEMU HARDDISK QM00001>
<UEFI QEMU DVD-ROM QM00005>
<EFI Internal Shell>
...

Press <enter> when finished, then <F10>, confirm with <y>, then press <ESC> until you are back at the main menu and select Continue.

The Debian netinst image should load and launch the DebianInstaller. Proceed to install your system as usual.

Subsequent boots

For subsequent boots, the installation media and boot menu delay are no longer necessary, so simply launch the VM as follows (if not using virt-manager) as follows:

$ cd ~/secureboot-vm
$ ./start-vm

Checking if secure boot is active

mokutil

You can check if secure boot is enabled (with root access) using mokutil:

$ mokutil --sb-state
SecureBoot enabled

bootctl

You can also check if secure boot is enabled by using bootctl:

$ sudo bootctl
systemd-boot not installed in ESP.
No default/fallback boot loader installed in ESP.
System:
     Firmware: n/a (n/a)
  Secure Boot: enabled
...

dmesg

When Linux has been booted with secure boot, dmesg should print:

secureboot: Secure boot enabled
Kernel is locked down from EFI Secure Boot mode

Otherwise secure boot is not activated.

Useful links