Here are the steps to sign ZFS kernel module in Enterprise Linux (RHEL, Rocky Linux, Alma Linux). I will need to write about secure boot, the ccontext, prerequisite later. But for now here are the steps I documented:
Generate key pair to sign custom kernel modules #
First, we need to generate a key pair that will be used to sign the custom kernel modules. This key pair consists of a private key, which will be used for signing, and a public key, which will be used to verify the signature.
Note the --module
flag below indicates that certificate is for signing kernel modules
efikeygen --dbdir /etc/pki/pesign \
--self-sign \
--module \
--common-name 'CN=<your org who is signing the key>' \
--nickname '<your key nickname>'
- –dbdir /etc/pki/pesign: the dir where the keys and certificates will be stored
- –self-sign: indicates that certificate should be self-signed
Enroll the public key to system keyring/MOK list #
To ensure the kernel can validate the signed modules, we need to enroll the public key into the Machine Owner Key (MOK) list.
Export public key to file sb_cert.cer
certutil -d /etc/pki/pesign \
-n 'ZFS Secure Boot key' \
-Lr \
> sb_cert.cer
- -d /etc/pki/pesign the dir containing the key database
- -n ‘ZFS Secure Boot key’: nickname of the key
- -Lr: list the public key in a readable format, redirecting the output to
sb_cert.cer
file
Then import file sb_cert.cer
to machine owner key (MOK) list
mokutil --import sb_cert.cer
Create the password and reboot.
Once a key is on the MOK list, it will be automatically propagated to the .platform keyring on this and subsequent boots when UEFI Secure Boot is enabled.
During the next boot, you will be asked to enroll MOK. Select the key and enter the password above to enroll.
Verify that your public keys are on the system keyring:
keyctl list %:.platform
Find the location of module’s ELF image #
Next we need to find where the ELF image of the kernel module we want to sign is. It’s under .ko
format. In this case it’s
find /lib/modules/ -iname *zfs*.ko
This returns locations of module ELF file, for example
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/avl/zavl.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/icp/icp.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/lua/zlua.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/nvpair/znvpair.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/unicode/zunicode.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/zcommon/zcommon.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/zstd/zzstd.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/zfs/zfs.ko
/lib/modules/4.18.0-513.18.1.el8_9.x86_64/extra/zfs/spl/spl.ko
The string 4.18.0-513.18.1.el8_9.x86_64
above is the kernel version. There could be several versions containing different modules.
Note that we need to make sure we’re getting the right ELF file of the current kernel we’re running. Do this with
uname -a
Extract the private key from the keypair we created as a PKCS #12 key #
pk12util -o sb_cert.p12 \
-n 'ZFS Secure Boot key' \
-d /etc/pki/pesign
-o sb_cert.p12: specifies output file
Create a password to encrypt the private key
Then export the unencrypted private key:
openssl pkcs12 \
-in sb_cert.p12 \
-out sb_cert.priv \
-nocerts \
-nodes
Sign the kernel modules #
Here we will append the .ko
files of the modules with our private key
/usr/src/kernels/$(uname -r)/scripts/sign-file \
sha256 \
sb_cert.priv \
sb_cert.cer \
path-to-zfs_module.ko
Verify with
modinfo zfs_module.ko | grep signer
This should display the signer of the module.
Load the signed modules #
If neccessary, install the kernel-modules-extra
package. This creates /lib/modules/$(uname -r)/extra/
directory.
Then copy the signed modules to /lib/modules/$(uname -r)/extra/
if it’s not in there yet
cp zfs_module.ko /lib/modules/$(uname -r)/extra/
Update modules dependency list with
depmod -a
Load the kernel module in verbose mode to see if we’re missing any .ko
file:
modprobe -v zfs
This will help identify if any additional .ko files are required.