Setting Up Secure Boot on Ubuntu Linux

Posted on January 22, 2023 in foss • 4 min read

I recently had to replace my motherboard on one of my PCs with a Nvidia GPU, which meant I had to figure out how to get Secure Boot working again with out-of-tree Nvidia kernel modules. Maintaining self-signed kernel modules is automated and zero-effort with dkms, but the initial setup takes a bit of legwork, so I figured I may as well document it for future reference.

This blog post specifically covers the use case of using a signed, standard distribution kernel provided by Debian/Ubuntu and using shim-signed to provision self-signed out of tree kernel modules that are registered with dkms. I'm explicitly not covering non-distribution kernels or kernel modules managed without dkms. Also, to state the obvious, this is only useful if you choose to have Secure Boot enabled. This guide should work for any non-ancient releases of Debian/Ubuntu that come with signed kernels; I know this definitely works from Ubuntu 18.04 LTS and above, but if in doubt check to make sure the shim-signed and mokutil packages came pre-installed.

On Ubuntu, shim-signed's postinst script generates a self-signed certificate, located in /var/lib/shim-signed/mok/MOK.{der,priv}. If these files are missing or you want to generate a new MOK key for whatever reason, run:

$ sudo update-secureboot-policy --new-key

AFAIK this is currently not the case in Debian, where you need to handle MOK generation yourself; refer to bug #989463. Also note that everytime you regenerate a MOK key you will need to re-enroll your keys, so you may want to include /var/lib/shim-signed/mok/MOK.{der,priv} in your scheduled backups (you do have backups, right?) and restore your MOK key if you ever need to reinstall your OS, whichever option is more convenient for you.

The next step is to enroll your MOK key. This is as simple as running:

$ sudo mokutil --import /var/lib/shim-signed/mok/MOK.der

This will prompt you for a one-time password. When you next reboot, instead of seeing the normal Grub menu, you'll instead see a UEFI key management shim screen, where you will need to enter that password to enroll your MOK key. If for whatever reason this fails, copy /var/lib/shim-signed/mok/MOK.der onto a FAT32 formatted USB drive, reboot into your motherboard's UEFI/BIOS setup menu (this will often be done by spamming F2 or Delete during boot, but check your motherboard's manual to be sure), and then dig through various menus until you find Secure Boot and key enrollment menu options, and add your key.

Sanity check that your key was successfully added with:

$ sudo mokutil --list-enrolled # your key should appear in the output, or
$ sudo mokutil --test-key /var/lib/shim-signed/mok/MOK.der
/var/lib/shim-signed/mok/MOK.der is already enrolled

You'll also need to check whether Secure Boot is enabled and enforced on your PC. This can be verified by running:

$ sudo mokutil --sb-state
SecureBoot enabled

If you do not see SecureBoot enabled, enable it by running:

$ sudo mokutil --enable-validation

When you next reboot, you'll again see a UEFI key management shim screen where you will be prompted to enable Secure Boot. Unfortunately this threw a rather non-descriptive error message with my Asus Z370-I motherboard and I had to go into UEFI setup (spam F2 during boot), go into the Secure Boot settings, and turn on "Windows UEFI mode" instead of "Other OS" to enable Secure Boot enforcement/validation. Once this is done, check sudo mokutil --sb-state to make sure it says enabled.

You can also check that Secure Boot enforcement is on and that your MOK key was successfully enrolled and in-use with dmesg, e.g.:

$ dmesg | grep "Secure Boot"
[    0.000000] Kernel is locked down from EFI Secure Boot mode; see man kernel_lockdown.7
[    1.010698] Loaded X.509 cert 'Canonical Ltd. Secure Boot Signing: 61482aa2830d0ab2ad5af10b7250da9033ddcef0'
[    1.018091] integrity: Loaded X.509 cert 'local_hostname Secure Boot Module Signature key: a0f5a8de9ffbef64e52df5c9b34b83e105287643'

From this point onwards, any and all kernel modules that are built by dkms should be signed with your MOK key. If you already have nvidia kernel modules (or any other out-of-tree modules) built before you generated a MOK key, and you want to rebuild them with dkms, you can do so by e.g.:

$ sudo dkms uninstall -k 5.4.0-90-generic -m nvidia -v 460.91.03 # replace kernel and module name/version as needed
$ sudo dkms install -k 5.4.0-90-generic -m nvidia -v 460.91.03 # replace kernel and module name/version as needed

To recap, to get Secure Boot working with a distribution kernel and out-of-tree modules:

  1. Enable Secure Boot validation.
  2. Enroll your MOK key in your motherboard's UEFI firmware.
  3. Sign your out-of-tree kernel modules with your MOK key.

Step 3 has to be done every time you update your kernel or your kernel module packages, but fortunately this is all handled by dkms for you, without any user intervention (and if you depend on out-of-tree modules but aren't using dkms, this is a strong incentive for you to start using dkms). Steps 1 and 2 are effectively one-time operations; they only need to be done if you replace your motherboard, wipe your enrolled keys in your motherboard's UEFI key management screen, or reinstall Debian/Ubuntu without backing up your enrolled keys.

If for some reason you wanted to manually sign a kernel module, you can do that by running:

$ sudo kmodsign sha512 /var/lib/shim-signed/mok/MOK.priv /var/lib/shim-signed/mok/MOK.der /path/to/kernel/module.ko

Further reading on Secure Boot integration in Debian/Ubuntu if you're curious: