Implementation
Mkinitfs
Mkinitfs is the initramfs generator of Alpine Linux. Among the usual operations to setup zlevis, i.e. writing the encryption key of the ZFS root pool to the TPM after the creation of the ZFS root pool, enabling the zlevis-hook in mkinitfs.conf and installing zlevis on the host system, we require to make an adaptation to the initramfs-init script of mkinitfs.
Particularly, in the prepare_zfs_root() function we need to add the option zlevis decrypt "$_root_pool" | zfs load-key -L prompt "$_root_pool":
Retaining the fallback to eval zfs load-key with the || operator.
Furthermore, we need to configure the zlevis-hook by notifying mkinitfs which binaries and libraries to add into the initramfs:
/usr/bin/zlevis
/usr/bin/zlevis-decrypt
/usr/bin/tpm2*
/usr/bin/jose
/usr/lib/libtss2-tcti*
and to notify what kernel drivers are required:
Dracut
Dracut is the default initramfs generator of Gentoo Linux and Void Linux. Among the usual operations to setup zlevis, i.e. writing the encryption key of the ZFS root pool to the TPM after the creation of the ZFS root pool, enabling the zlevis module in /etc/dracut.conf.d and installing zlevis on the host system, we require to add the zlevis module in /usr/lib/dracut/modules.d.
Create the executable module setup of the zlevis-dracut module:
#!/bin/bash
# Depend on udev-rules and zfs
depends() {
echo udev-rules zfs
return 0
}
install() {
# Install the appropriate binaries and libraries
inst_multiple /usr/bin /usr/bin/zlevis /usr/bin/zlevis-decrypt /usr/bin/jose /usr/bin/tpm2*
inst_multiple /usr/lib /usr/lib/libtss2-tcti*
# Run the zlevis decryption hook before the 90zfs hook
inst_hook pre-mount 85 "${moddir}/zlevis.sh"
inst_simple "${moddir}/zlevis.sh" "/sbin/zlevis.sh"
}
and create the executable module script of the zlevis-dracut module:
#!/bin/sh
# Load the ZFS kernel module
modprobe zfs 2>/dev/null
udevadm settle
# Search for encrypted pool's by means of the cmdline root atribute
local _root_vol="${root}"
local _root_pool="${_root_vol%%/*}"
# Import the root pool
zpool import -N -d /dev $_root_pool
# If the pool is encrypted run `zlevis decrypt` to obtain the key stored in the TPM and load the key
if [ $(zpool list -H -o feature@encryption $_root_pool) = "active" ]; then
local _encryption_root=$(zfs get -H -o value encryptionroot $_root_vol)
if [ "$_encryption_root" != "-" ]; then
zlevis decrypt $_root_pool | zfs load-key -L prompt "$_root_pool" || echo "Failed to unlock $_root_pool with TPM"
fi
fi
Now dracut will recognise the zlevis module, and if enabled will be added to the initramfs to be executed before the 90zfs hook.