Secure Boot and Encryption
kldload supports Secure Boot via MOK (Machine Owner Key) enrollment and ZFS native encryption (AES-256-GCM). Works on all supported distros.
This is the hands-on guide. For the conceptual explanation of why the boot chain matters, what attack scenarios look like, and how the three verification layers work together, read Secure Boot & the Boot Chain. This page is about doing it — configuring encryption, signing modules, enrolling keys, and recovering when things go wrong.
ZFS encryption
Enable during install
Set KLDLOAD_ZFS_ENCRYPT=1 in the answers file or select
encryption in the web UI. The installer creates the pool with:
encryption=aes-256-gcmkeyformat=passphrasekeylocation=prompt
You’ll enter a passphrase at every boot.
Verify encryption status
zfs get encryption,keystatus rpool
NAME PROPERTY VALUE
rpool encryption aes-256-gcm
rpool keystatus available
Encrypt individual datasets (on an unencrypted pool)
You don’t have to encrypt the whole pool. Encrypt only sensitive data:
# Create an encrypted dataset
zfs create -o encryption=aes-256-gcm \
-o keyformat=passphrase \
rpool/srv/secrets
# Enter passphrase when prompted
# Create with a key file instead of passphrase
dd if=/dev/urandom of=/root/.zfs-key bs=32 count=1
chmod 600 /root/.zfs-key
zfs create -o encryption=aes-256-gcm \
-o keyformat=raw \
-o keylocation=file:///root/.zfs-key \
rpool/srv/automated-secrets
Per-dataset encryption is the feature that changes how you think about data protection.
LUKS encrypts the whole disk with one key. Unlock it at boot and everything is exposed — every file, every user, every secret. All or nothing. ZFS encryption is per-dataset. /home/alice has Alice's key. /srv/secrets has a hardware token. /srv/customer-data has its own passphrase. Lock one dataset and the rest stay accessible. A compromise of one key doesn't expose everything else.
For the quantum bridge contract: every customer gets their own encrypted dataset with their own key. Offboard a customer? zfs unload-key — their data is ciphertext on disk. Root can't read it. The admin can't read it. The backup server storing the replica can't read it. The key never left the customer's hands.
Lock and unlock
# Lock (unmount and unload key)
zfs unmount rpool/srv/secrets
zfs unload-key rpool/srv/secrets
# Unlock
zfs load-key rpool/srv/secrets # prompts for passphrase
zfs mount rpool/srv/secrets
Change passphrase
zfs change-key rpool
# Enter current passphrase, then new passphrase
Secure Boot with MOK
kldload ISOs boot with Secure Boot via the shim bootloader (same chain as Fedora/Ubuntu). After install, DKMS kernel modules (ZFS, NVIDIA) need signing.
How it works
- kldload installs the shim EFI binary (
BOOTX64.EFI) which is signed by Microsoft’s UEFI CA - Shim loads GRUB2 or ZFSBootMenu
- The kernel is signed by the distro vendor (CentOS/Debian)
- Third-party kernel modules (ZFS, NVIDIA) are signed with a MOK key that kldload generates during install
Check Secure Boot status
mokutil --sb-state
# SecureBoot enabled/disabled
# List enrolled MOK keys
mokutil --list-enrolled
Build-time vs runtime signing — the key distinction.
kldload compiles and signs modules at image build time, not on the target. Each build generates a unique MOK keypair. The signed modules ship in the image alongside the kernel — a matched pair. No compiler on the target. No DKMS in the boot path. If the machine boots, the modules are loaded and verified.
After deployment, DKMS is still on the machine for kernel updates. When you run kupgrade, it rebuilds the module, re-signs it with the MOK key, and verifies it loaded. If signing fails, kupgrade warns you and the pre-upgrade boot environment is one reboot away. The build-time signing covers the initial deploy. The MOK key on the target covers post-deploy kernel updates. Both are automatic.
The MOK key
kldload stores the MOK key pair at:
/var/lib/kldload/mok/MOK.priv # private key (600 permissions)
/var/lib/kldload/mok/MOK.der # public certificate (enrolled in firmware)
Sign a kernel module manually
If you install a new DKMS module (or the automatic signing fails):
# Find the module
modinfo -n zfs
# /lib/modules/5.14.0-xxx/extra/zfs.ko.xz
# Sign it
/usr/src/kernels/$(uname -r)/scripts/sign-file sha256 \
/var/lib/kldload/mok/MOK.priv \
/var/lib/kldload/mok/MOK.der \
/lib/modules/$(uname -r)/extra/zfs.ko.xz
# Verify the signature
modinfo zfs | grep signer
Enroll a new MOK key
If you generated a new key and need to enroll it in the firmware:
# Stage the key for enrollment
mokutil --import /var/lib/kldload/mok/MOK.der
# Enter a one-time password
# Reboot — the shim MOK manager will prompt you to enroll the key
reboot
At the blue MOK Manager screen: 1. Select “Enroll MOK” 2. Select “Continue” 3. Enter the one-time password you set 4. Select “Reboot”
DKMS auto-signing
The honest truth about DKMS + Secure Boot
DKMS modules on kernel upgrades are historically fragile on Linux. Auto-signing can fail silently — the kernel upgrades, DKMS rebuilds the module, but the signing step fails and you don’t know until the module won’t load on reboot.
kldload mitigates this in three ways:
- Boot environments —
ksnapbefore everykupgrade. If the kernel upgrade breaks ZFS module loading, reboot into the previous boot environment. 30 seconds to recover. - DKMS sign-tool — kldload installs a signing script at
/var/lib/dkms/mok-signing.shthat DKMS calls automatically. If it fails,kupgradewarns you before reboot. - Verification —
kupgraderunsdkms statusafter every kernel upgrade and checks that the ZFS module is built and signed for the new kernel. If not, it blocks the reboot and tells you.
# Check DKMS module status
dkms status
# Rebuild and sign for current kernel
dkms autoinstall
# Verify the module is signed
modinfo -F signer zfs
# Should show: kldload Secure Boot MOK
# If signing failed — roll back
kbe activate before-upgrade && reboot
Full disk encryption + Secure Boot together
This is the most secure configuration — encrypted data at rest with verified boot chain:
- Install with
KLDLOAD_ZFS_ENCRYPT=1and Secure Boot enabled in firmware - kldload generates MOK key, creates encrypted pool, signs ZFS module
- At boot: firmware verifies shim → shim verifies GRUB → GRUB loads kernel → ZFS prompts for passphrase
Automating unlock with Clevis (TPM2)
To avoid typing the passphrase at every boot, bind the encryption key to the TPM:
# CentOS/RHEL
dnf install -y clevis clevis-luks clevis-tpm2
# Debian
apt install -y clevis clevis-tpm2
Note: ZFS native encryption doesn’t integrate directly with Clevis the way LUKS does. The kldload firstboot service stages the passphrase at
/etc/kldload/zfs-passphrasefor potential Clevis sealing. This is an area of active development.
The three layers working together:
Layer 1 — Verified boot: Firmware → shim → kernel → signed modules
(tampered binary = refused to load)
Layer 2 — Encrypted storage: AES-256-GCM per dataset, key never on disk
(stolen disk = ciphertext)
Layer 3 — Checksummed I/O: Every block verified on every read
(bit rot / tampering = detected + repaired)
Combined: the system boots verified, stores data encrypted, and
verifies every read. An attacker needs to compromise the firmware,
steal the encryption key, AND bypass block checksums. Each layer
is independent. Breaking one doesn't break the others.
No single security tool on ext4 gives you all three. You'd need Secure Boot + LUKS + AIDE/Tripwire, each configured separately, each with its own failure modes. On ZFS, layers 2 and 3 are properties of the filesystem. Layer 1 is the boot chain kldload configures for you.
Troubleshooting
# Module won't load — signature issue
dmesg | grep -i "module verification failed"
# Fix: re-sign the module (see above)
# MOK key not enrolled
mokutil --test-key /var/lib/kldload/mok/MOK.der
# "is not enrolled" → need to run mokutil --import and reboot
# Encrypted pool won't import
zpool import -a # prompts for passphrase
zfs load-key -a # load all keys
zfs mount -a # mount everything
# Forgot the passphrase
# No recovery possible with ZFS native encryption.
# If you have a backup (zfs send), restore from that.
# This is why boot environment snapshots matter — they're part of the encrypted pool.