Every time I DuckDuckGoed anything remotely related to NVIDIA, Linux and secure boot, all I could ever find was “TURN IT OFF”. But I was adamant, why would I turn off something that’s supposed to make my workstation more secure? I am always looking to secure my stuff; I already use TPM, LUKS and Bitlocker, so why should I turn off secure boot every time I want to use a graphics card on Linux?
Being a Mechanical Engineer by degree and a Market Analyst by profession, everything I know about computers is a weird mixture of trial-and-error, common sense, and StackExchange. So, needless to say, proceed at your own risk.
Here’s the directory structure we will be using for the script.
auto_kernel_signer |- keys |- public_key.der |- private_key.priv |- main.py |- modules.conf |- autosigner.log |- configuration_file.config
First, we will make the parent directory (named auto_kernel_signer here), and the keys subdirectory. Sign in to your root account using sudo su and cd to wherever you want to keep this script.
~]# mkdir auto_kernel_signer && cd "$_"
~]# mkdir keys
Next, we will create new Machine Owner Key (MOK) and put the keypair in the keys subdirectory.
~]# cat << EOF > configuration_file.config [ req ] default_bits = 4096 distinguished_name = req_distinguished_name prompt = no string_mask = utf8only x509_extensions = myexts [ req_distinguished_name ] O = Machine Owner CN = Machine Owner signing key emailAddress = root@localhost [ myexts ] basicConstraints=critical,CA:FALSE keyUsage=digitalSignature subjectKeyIdentifier=hash authorityKeyIdentifier=keyid EOF
~]# openssl req -x509 -new -nodes -utf8 -sha256 -days 36500 \ -batch -config configuration_file.config -outform DER \ -out keys/public_key.der \ -keyout keys/private_key.priv
Now that we have our key pairs, it’s time to register the public key with our MOK Management.
~]# mokutil --import keys/public_key.der
You will be asked to enter and confirm a password for this MOK enrollment request. Restart the computer to trigger MOK Management, and import the key using the same password. Remember, mokutil does not work for everyone (although it does work most of the time). If it doesn’t work for you, you will have to go into your UEFI firmware settings and import the public key directly. It should most likely be named MOK Management or some variations of that.
After we import the key to MOK database, the hard part (for you) is over! Copy the content from below and put it in main.py.
Pay close attention to the top four variables defined in the main.py file.
I am using Fedora, so if you’re in the RHEL ecosystem, you probably won’t have to change much.
The main_path variable is directory path where your main.py file resides.
For Ubuntu or other Debian based distros, the sign_script_path would be.
The path_common variable is defined for the kernel modules parent directory. You probably won’t need to change that. Just make sure that’s where your kernel modules reside for various kernel versions. So for example, if you want to sign the nvidia kernel and it’s at:
We will just keep the parent directory path of various kernel versions in our path_common variable as below.
The modules.conf file contains a list of modules you want to sign, but only relative paths to the updated kernel version. For example,
extra/nvidia/nvidia.ko extra/nvidia/nvidia-drm.ko extra/nvidia/nvidia-modeset.ko extra/nvidia/nvidia-uvm.ko
Or, the directory as shown below, if you want to sign all the files in the specified directory
So, in essence, your path_common variable will provide the base path for the modules you want to sign, the script will discover updated kernels in that directory, and modules.conf file will provide relative paths to the actual files that need to be signed within that updated kernel directory.
The shell_scr variable is the shell script that lists out installed kernel versions in ascending order. If you are in Ubuntu or other Debian based distros, you shell_scr would be:
dpkg --list | grep linux-image | grep ii | sort -V
After you make modules.conf, we will make a systemctl service that will run this script before shutdown.
~]# nano /lib/systemd/system/auto-kernel-signer.service
Then write the following:
[Unit] Description=Auto Sign Kernel Modules [Service] User=root Group=root WorkingDirectory=/PATH_TO_SCRIPT_PARENT_DIR/auto_kernel_signer Type=oneshot RemainAfterExit=true ExecStop=/usr/bin/python3 /PATH_TO_SCRIPT_PARENT_DIR/auto_kernel_signer/main.py [Install] WantedBy=multi-user.target
After saving the service, let’s start it.
~]# systemctl daemon-reload
~]# systemctl enable auto-kernel-signer --now
Now that we have the service up and running, let’s sign the kernel modules for the first time. If you’re somehow doing this after a recent kernel upgrade and before the subsequent reboot, you won’t have to manually sign the kernels.
Otherwise, cd into the auto_kernel_signer directory and run:
~]# python3 main.py force
And that’s it! You’re done. The service will run the script every time before your computer is turned off. The script checks if kernel has been updated. If there’s no update, the script does nothing, if there’s an update, the script signs the modules defined in modules.conf with the keys from keys subdirectory.
Enjoy secure booting Linux!
2 Replies to “How to Automatically Sign Linux Kernel Modules After Kernel Update for Secure Boot”
I have trouble with unsigned linux kernels after enabling secure boot. I am using Pop OS 21.04. Will this script work?
From what I remember, PopOS! does not officially support secure boot, so, it might not. You might need to sign your bootloader first to get secure boot working, but I may be wrong. If PopOS! does have a signed bootloader, in which case you can potentially implement this script, you just have to edit the required directory paths to match your specific OS.