Secure Boot on Linux: How I Signed My Own Kernel to Kill Bootkits

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

The 2:14 AM Wake-up Call: When Hardware Stops Trusting Software

The Slack alert hit at 2:14 AM. A primary database node had failed to reboot after a routine security patch. When I pulled up the remote console, I didn’t see a login prompt. Instead, a cold, white-on-black error stared back: Security Violation. The system was refusing to load the OS. My first thought was a dead NVMe drive, but the truth was more clinical: Secure Boot was doing its job and rejecting a kernel it didn’t recognize.

In a production crisis, many admins take the bait and disable Secure Boot in the UEFI settings. It’s a 30-second fix that leaves the front door wide open. Without it, you’re vulnerable to bootkits and UEFI rootkits—malware that burrows into the boot process before the OS even wakes up. These threats are invisible to standard antivirus. I decided to fix the root cause by establishing my own chain of trust.

How the Chain of Trust Actually Works

Secure Boot is essentially a gatekeeper. During startup, the UEFI firmware checks the digital signature of your bootloader (usually GRUB). If that signature matches a trusted key in the firmware’s database, it runs. The bootloader then verifies the Linux kernel’s signature. This creates a continuous ‘Chain of Trust’ from the hardware to the user space.

Most motherboards ship only with Microsoft’s keys. Mainstream distros like Ubuntu or Fedora bypass this by using a Microsoft-signed shim. However, this chain snaps the moment you compile a custom kernel or use out-of-tree modules like ZFS and Nvidia. If your distribution doesn’t provide signed binaries, you’re stuck. To keep the server secure while running custom code, I had to become my own Certificate Authority.

Building Your Own Trust: The Step-by-Step Workflow

To resolve the lockout, I implemented a Machine Owner Key (MOK). This is a user-generated key that you manually tell the UEFI firmware to trust. Here is the exact process I used to bring that server back online.

1. Diagnose the Boot Failure

Before changing anything, I had to confirm Secure Boot was the bottleneck. I used mokutil, the standard tool for managing these keys on Linux.

# Verify Secure Boot status
mokutil --sb-state

If the output shows SecureBoot enabled, the firmware will kill any unsigned process. My mission was to add my specific signature to the whitelist.

2. Generate a 2048-bit Signing Key

I needed two things: a private key to sign the kernel and a public certificate for the firmware. I isolated these in a secure directory. Remember, if these keys are world-readable, your security is theater.

sudo mkdir -p /var/lib/shim-signed/mok
sudo chmod 700 /var/lib/shim-signed/mok
cd /var/lib/shim-signed/mok

# Create a 100-year certificate
sudo openssl req -new -x509 -newkey rsa:2048 -nodes -days 36500 -outform DER -keyout MOK.priv -out MOK.der

When prompted for a Common Name, use something descriptive like “Ops-Prod-Kernel-Signer”. This helps you identify the key in a messy UEFI menu later.

3. Enroll the Key in the Firmware

Keys are useless if the hardware doesn’t recognize them. I used mokutil to stage the public .der file for enrollment. Having managed over 15 high-traffic nodes, I’ve learned to double-check these commands—one typo can mean another hour in the data center.

sudo mokutil --import MOK.der

The utility prompted for a temporary password. This is a one-time code for the next reboot. I wrote it on a sticky note and hit the reset button.

During the reboot, a blue screen titled “MOK Management” appeared. I selected Enroll MOK, confirmed the key fingerprints matched, and entered the one-time password. After one more reboot, the firmware officially trusted my custom CA.

4. Sign the Kernel Binary

The last hurdle was signing the actual kernel file. Even with the key enrolled, an unsigned kernel is still untrusted. I used sbsign to wrap the binary in my new signature.

# Define the target kernel
KERNEL_PATH="/boot/vmlinuz-$(uname -r)"

# Apply the signature
sudo sbsign --key MOK.priv --cert MOK.der --output $KERNEL_PATH.signed $KERNEL_PATH

# Overwrite the unsigned version
sudo mv $KERNEL_PATH.signed $KERNEL_PATH

For drivers like Nvidia, you’ll need the kernel’s internal signing scripts. Most modern systems can automate this via DKMS configurations in /etc/dkms/, ensuring new updates are signed automatically.

Hardening the Result

By 4:00 AM, the database was back in the cluster, Secure Boot was active, and the Security Violation was gone. The peace of mind is worth the effort. You now have a system that refuses to boot anything you haven’t personally vetted.

One warning for production environments: guard your MOK.priv file with your life. If an attacker steals that private key, they can sign their own malicious kernels and bypass your entire defense. I store mine in an encrypted vault, only mounting it during maintenance windows.

Configuring Secure Boot manually can feel like a battle against cryptic BIOS menus, but it is a definitive win for system integrity. Once that chain is locked, you can sleep better—even when the alerts start chirping at 2 AM.

Share: