How to Build and Sign Unified Kernel Images in Ubuntu Using ukify

In traditional Linux boot workflows, the UEFI firmware launches a bootloader such as GRUB, which in turn reads an unauthenticated kernel command line, loads the Linux kernel binary (vmlinuz), and initializes an initial RAM disk (initrd) from an unencrypted boot partition. While UEFI Secure Boot verifies the GRUB binary itself, the subsequent loading of configuration files and initrd archives often leaves the early boot sequence vulnerable to physical tampering, initrd manipulation, and evil maid attacks. The Unified Kernel Image (UKI) specification addresses this vulnerability by combining the UEFI stub loader, kernel image, initrd, os-release metadata, and kernel command line into a single, self-contained, cryptographically signed UEFI PE binary.

In modern Ubuntu installations (including Ubuntu 24.04 LTS), the systemd-ukify utility provides an automated framework to compile, assemble, and sign UKIs directly. This guide details how to install ukify, configure image assembly recipes, embed kernel command lines, sign binaries with local Secure Boot keys, and boot unified images directly through UEFI firmware or systemd-boot.

Understanding Unified Kernel Images and systemd-stub

A Unified Kernel Image replaces separate boot assets with a single Portable Executable (PE) binary executed directly by UEFI firmware. The binary contains distinct PE sections recognized by the systemd-stub bootloader:

  • .linux: The decompressed or EFI-stub-enabled Linux kernel image (/boot/vmlinuz-...).
  • .initrd: The complete early userspace initial RAM filesystem containing storage drivers and cryptographic unlocking tools.
  • .cmdline: The static, immutable kernel command line parameters (such as root partition UUIDs, cgroup configurations, and console settings).
  • .osrel: System identity metadata extracted directly from /etc/os-release.
  • .splash: Optional early boot splash bitmap images displayed during hardware handover.
  • .tpm2_pcr_sig: Optional cryptographic signatures over pre-calculated TPM2 PCR registers (PCR 11), ensuring the kernel boots only if the exact measured firmware state is preserved.

Because the entire package is signed as a unified binary, any modification to the initrd or kernel command line breaks the cryptographic signature, causing UEFI Secure Boot to halt execution before untrusted code runs.

Installing ukify on Ubuntu

In Ubuntu, ukify is packaged alongside modern systemd utilities. Install the required tools using apt:

# Update package repositories and install ukify and signing tools
sudo apt update
sudo apt install systemd-ukify binutils sbsigntool

To verify that ukify is functional and review the installed version:

# Inspect ukify version and argument flags
ukify --version

Preparing Kernel Command Line and Splash Assets

Because the kernel command line is compiled directly into the binary section, create a configuration file defining your production boot parameters. Avoid referencing volatile device nodes like /dev/sda1; always use persistent filesystem UUIDs:

# Create directory for UKI build assets
sudo mkdir -p /etc/kernel/uki

# Export production kernel command line parameters
echo "root=UUID=$(findmnt / -o UUID -n) ro quiet splash vt.handoff=7" | sudo tee /etc/kernel/uki/cmdline

Verify the contents of the command line definition:

# Inspect generated kernel command line
cat /etc/kernel/uki/cmdline

Generating a Unified Kernel Image Using ukify

To construct a UKI, identify your current running kernel version or target installed kernel. You will combine the UEFI stub (linuxx64.efi.stub), the vmlinuz kernel, the generated initrd.img, and the command line file:

# Set target kernel version variable
KERNEL_VER=$(uname -r)

# Build the unified kernel image binary
sudo ukify build \
    --linux="/boot/vmlinuz-${KERNEL_VER}" \
    --initrd="/boot/initrd.img-${KERNEL_VER}" \
    --cmdline="/etc/kernel/uki/cmdline" \
    --os-release="/etc/os-release" \
    --output="/boot/efi/EFI/Linux/ubuntu-${KERNEL_VER}.efi"

If the /boot/efi/EFI/Linux directory does not exist on your EFI System Partition (ESP), create it before building:

# Ensure standard EFI Linux directory exists on the ESP
sudo mkdir -p /boot/efi/EFI/Linux

Cryptographically Signing the Image for Secure Boot

To run on hardware with UEFI Secure Boot enabled, the generated UKI must be signed using your custom Machine Owner Key (MOK) or platform signing certificate.

Generating a Custom MOK Key Pair

If you have not already enrolled a local MOK key in the system firmware, generate a 2048-bit RSA key pair:

# Create dedicated directory for local boot keys
sudo mkdir -p /etc/kernel/keys
sudo chmod 700 /etc/kernel/keys

# Generate private key and X.509 certificate
sudo openssl req -new -x509 -newkey rsa:2048 \
    -keyout /etc/kernel/keys/db.key \
    -out /etc/kernel/keys/db.crt \
    -days 3650 -nodes \
    -subj "/CN=Ubuntu Local Secure Boot Key/"

Signing during the ukify Build Process

You can pass private keys and certificates directly to ukify build, allowing image assembly and PE signing in a single command:

# Assemble and cryptographically sign UKI in one step
sudo ukify build \
    --linux="/boot/vmlinuz-${KERNEL_VER}" \
    --initrd="/boot/initrd.img-${KERNEL_VER}" \
    --cmdline="/etc/kernel/uki/cmdline" \
    --os-release="/etc/os-release" \
    --signtool=sbsign \
    --secureboot-private-key=/etc/kernel/keys/db.key \
    --secureboot-certificate=/etc/kernel/keys/db.crt \
    --output="/boot/efi/EFI/Linux/ubuntu-${KERNEL_VER}.efi"

To verify that the resulting binary contains a valid Secure Boot signature:

# Inspect digital signature headers on the generated binary
sbverify --list /boot/efi/EFI/Linux/ubuntu-${KERNEL_VER}.efi

Inspecting Internal PE Sections of the Generated Image

You can verify that all components are correctly mapped inside the resulting binary using objdump or systemd-dissect:

# Inspect PE sections within the UKI binary
objdump -h /boot/efi/EFI/Linux/ubuntu-${KERNEL_VER}.efi

The output confirms the presence and exact byte sizes of the embedded assets:

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000a420  0000000000001000  0000000000001000  00001000  2**4
  1 .osrel        00000195  000000000000c000  000000000000c000  0000c000  2**2
  2 .cmdline      00000052  000000000000d000  000000000000d000  0000d000  2**2
  3 .initrd       02812f80  000000000000e000  000000000000e000  0000e000  2**4
  4 .linux        00e48100  0000000002821000  0000000002821000  02821000  2**4

Automating UKI Generation on Kernel Upgrades

To ensure new Unified Kernel Images are built automatically whenever apt installs an updated Ubuntu kernel package, configure a kernel post-install hook in /etc/kernel/postinst.d/:

# Create automated kernel upgrade hook script
cat << 'EOF' | sudo tee /etc/kernel/postinst.d/zz-build-uki
#!/bin/sh
set -e

VERSION="$1"
LOCATION="$2"

if [ -x /usr/bin/ukify ]; then
    echo "Generating Unified Kernel Image for kernel ${VERSION}..."
    ukify build \
        --linux="/boot/vmlinuz-${VERSION}" \
        --initrd="/boot/initrd.img-${VERSION}" \
        --cmdline="/etc/kernel/uki/cmdline" \
        --os-release="/etc/os-release" \
        --signtool=sbsign \
        --secureboot-private-key=/etc/kernel/keys/db.key \
        --secureboot-certificate=/etc/kernel/keys/db.crt \
        --output="/boot/efi/EFI/Linux/ubuntu-${VERSION}.efi"
fi
EOF

# Make hook executable
sudo chmod +x /etc/kernel/postinst.d/zz-build-uki

Troubleshooting UKI Generation and Secure Boot Booting

When deploying Unified Kernel Images, keep these key troubleshooting pointers in mind:

  • Missing EFI Stub Binary: If ukify outputs an error reporting that linuxx64.efi.stub cannot be located, ensure systemd-boot or systemd-ukify packages are completely installed, or specify the stub path explicitly using --stub=/usr/lib/systemd/boot/efi/linuxx64.efi.stub.
  • ESP Partition Space Exhaustion: Because each UKI contains both the full kernel and compressed initrd (often 60–100 MB per image), maintaining multiple UKIs on a small 100 MB default ESP can exhaust disk space. Resize your EFI System Partition to at least 1 GB when adopting UKI workflows.
  • Secure Boot Verification Failed (Access Denied): If the motherboard firmware refuses to launch the UKI with an “Access Denied” or “Invalid Signature” error, verify that the custom MOK certificate (db.crt) was successfully enrolled into the system NVRAM using mokutil --import /etc/kernel/keys/db.crt followed by a reboot to complete the MOK enrollment dialog.

By leveraging ukify, system administrators can convert standard Ubuntu boot assets into tamper-resistant, standalone UEFI binaries that protect systems against unauthorized boot-level tampering.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.