Sign out-of-tree kernel modules so they load under Secure Boot.
VMware's vmmon/vmnet and VirtualBox's vboxdrv are rebuilt from source every
time your kernel updates. The rebuild is unsigned, Secure Boot refuses it, and
you get:
modprobe: ERROR: could not insert 'vmmon': Key was rejected by service
The usual advice is "turn off Secure Boot." This script is the other option: generate your own signing key, enrol it with your firmware once, and re-sign the modules after each kernel update.
One command after a kernel upgrade:
sudo sign-modules
- Finds the kernel's
sign-filehelper, wherever your distribution hides it - Rebuilds the modules if none exist for the running kernel
- Signs them with your key
- Loads them, and optionally restarts a service
--setuphandles first-run key generation and MOK enrolment--statustells you what is built, signed, loaded and enrolled
It is one Bash file with no dependencies beyond openssl, mokutil and your
kernel headers.
No curl | sudo bash here. This runs as root and handles a signing key — read
it first.
curl -fLO https://raw.githubusercontent.com/Spyril/sign-modules/main/sign-modules
less sign-modules # read it
sudo install -m 0755 sign-modules /usr/local/bin/sign-modulesRequirements: openssl, mokutil, and the kernel headers matching your running
kernel.
| Distribution | Packages |
|---|---|
| Debian, Ubuntu | mokutil openssl build-essential linux-headers-$(uname -r) |
| Fedora, RHEL | mokutil openssl kernel-devel |
| openSUSE | mokutil openssl kernel-default-devel |
| Arch | mokutil openssl linux-headers |
sudo sign-modules --setupThis generates an RSA-2048 keypair in /var/lib/sign-modules (private key
0600, certificate 0644), writes a default /etc/sign-modules.conf, and runs
mokutil --import. You will be asked to choose a one-time password.
Then reboot. A blue MOK Manager screen appears before the system starts. It times out after about ten seconds and boots normally if you miss it, so don't walk away.
Enroll MOK → Continue → Yes → [the password you just chose] → Reboot
Edit /etc/sign-modules.conf to match what you are signing, then:
sudo sign-modules/etc/sign-modules.conf is sourced as shell. Override the path with
SIGN_MODULES_CONFIG=/some/other.conf.
MODULES="vmmon vmnet"
MOK_DIR="/var/lib/sign-modules"
MOK_KEY="$MOK_DIR/MOK.priv"
MOK_CERT="$MOK_DIR/MOK.der"
REBUILD_CMD="vmware-modconfig --console --install-all"
RESTART_SERVICE="vmware"VirtualBox:
MODULES="vboxdrv vboxnetflt vboxnetadp"
REBUILD_CMD="/sbin/vboxconfig"
RESTART_SERVICE=""Every setting is also readable from the environment, so
MODULES="vboxdrv" sudo -E sign-modules works for a one-off.
A systemd unit on boot is the simplest version:
# /etc/systemd/system/sign-modules.service
[Unit]
Description=Sign and load out-of-tree kernel modules
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/sign-modules
RemainAfterExit=yes
[Install]
WantedBy=multi-user.targetsudo systemctl enable --now sign-modules.serviceA DKMS-registered module can be signed at build time instead; see the notes at the bottom.
If you enrolled a key by hand previously, point the config at it and skip
--setup:
MOK_KEY="/root/module-signing/MOK.priv"
MOK_CERT="/root/module-signing/MOK.der"sign-modules --status will confirm whether that certificate is enrolled.
Only what has actually been run. Everything else is untested — it should work, but nobody has checked.
| Distribution | Kernel | Modules | Status |
|---|---|---|---|
| Kubuntu 26.04 LTS | 7.0 | vmmon, vmnet | verified |
| openSUSE Tumbleweed | 7.1.5 | vmmon, vmnet | verified |
| Fedora / RHEL | — | — | untested, path included |
| Arch | — | — | untested, path included |
| VirtualBox (any distro) | — | vboxdrv et al | untested |
Reports welcome — open an issue with your distribution, uname -r, and the
output of sign-modules --status.
Key was rejected by service after signing. The key is not enrolled yet.
sign-modules --status will say so. You either skipped the blue MOK screen or
mistyped the password. Run --setup again and reboot.
sign-file not found. Your kernel headers are missing, or they don't match
the running kernel. Install the headers package for uname -r and reboot if you
have updated the kernel since.
The modules signed, then stopped working after you ran the vendor installer
again. Any rebuild discards the signature. Re-run sign-modules. Order
matters: build first, sign last, load after that — don't let the vendor tool
load them in between.
Compressed modules are skipped. Some distributions ship .ko.zst. Signing a
compressed module does nothing useful; decompress, sign, and re-compress, or
configure your module compression off.
It does not patch module source for new kernels. When VMware breaks against a kernel that moved an API out from under it, no amount of signing will help — that is a different problem with a different fix:
Patch with those, then sign with this.
The private key lives at /var/lib/sign-modules/MOK.priv, mode 0600, in a
0700 directory. Anyone who can read it can sign a kernel module that your
firmware will trust — which is to say, they can load arbitrary code into your
kernel with Secure Boot on and nothing complaining. Treat it like an SSH host
key.
The key is unencrypted on disk, because sign-file needs it non-interactively.
That is the standard trade-off for MOK signing and it is why the key is a local,
machine-specific one rather than something you copy between hosts. If you back
it up, encrypt the backup.
The certificate is valid for 100 years. Expiry buys nothing here: firmware
trusts the enrolled certificate, there is no revocation path short of
mokutil --delete, and an expired key would just mean an annoying re-enrolment
on a machine whose owner has not changed.
MIT.