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:
- Enable Secure Boot validation.
- Enroll your MOK key in your motherboard's UEFI firmware.
- 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: