Making AlpineLinux load ZFS keys for all pools on startup
Problem statement
A while ago I posted about the secure boot with fully encrypted filesystem setup on Alpine Linux that’s ZFS based.
On some machines, though, I use more than one pool (to separate the NVME pool from the SATA SSD pool, as their performance characteristics are different).
Unfortunately, Alpine Linux does not load all the keys before attempting to mount any of the “secondary” (non-boot) pools, and thus they aren’t mounted automatically (as the key material is missing).
Solution
The solution is very straightforward, and in my first version very hacky: Simply
run zfs load-key -a
before the zfs-mount
init script (but after zfs-import
).
In other words, a one-liner turned into a 78-liner due to rather excessive ceremony:
The /etc/init.d/zfs-load-keys init script (click to expand)
#!/sbin/openrc-run
#
# zfs-load-keys This script will load encryption keys for ZFS pools
#
# chkconfig: 2345 01 99
# description: This script will perform "zfs load-key -a" during system boot.
# probe: true
#
### BEGIN INIT INFO
# Provides: zfs-load-keys
# Required-Start: zfs-import
# Required-Stop: $local_fs mtab
# Default-Start: S
# Default-Stop: 0 1 6
# X-Start-Before: zfs-mount
# X-Stop-After: zfs-mount
# Short-Description: Load ZFS encryption keys
# Description: Run the `zfs load-key -a` command.
### END INIT INFO
#
# Source the common init script
. /etc/zfs/zfs-functions
# ----------------------------------------------------
do_depend()
{
before zfs-mount
after zfs-import
keyword -lxc -openvz -prefix -vserver
}
# Output the status and list of pools
do_status()
{
check_module_loaded "zfs" || exit 0
"$ZPOOL" status && echo "" && "$ZPOOL" list
}
do_start()
{
zfs_action "Loading ZFS encryption key(s)" \
"$ZFS" load-key -a
}
# ----------------------------------------------------
if [ ! -e /sbin/openrc-run ]
then
case "$1" in
start)
do_start
;;
stop)
# no-op
;;
status)
do_status
;;
force-reload|condrestart|reload|restart)
# no-op
;;
*)
[ -n "$1" ] && echo "Error: Unknown command $1."
echo "Usage: $0 {start|status}"
exit 3
;;
esac
exit $?
else
# Create wrapper functions since Gentoo don't use the case part.
depend() { do_depend; }
start() { do_start; }
status() { do_status; }
fi
Then all that’s needed is to install it properly:
chmod 755 /etc/init.d/zfs-load-keys
rc-update add zfs-load-keys sysinit
Et voilà; after rebooting all volumes get correctly auto-mounted.
Closing words
This script only works well when you use file://
as the keylocation;
it doesn’t even bother to verify that and/or test the presence of the file.
In other words, it’s supremely fragile.
So you better make sure you don’t have any of the keylocations set to
prompt
(and also that the configured locations are accessible at boot
time).
A good quick check would be:
$ zfs get keylocation | awk '$3 != "none" { print }'
NAME PROPERTY VALUE SOURCE
nvmetank keylocation file:///crypto_keyfile.bin local
ssdtank keylocation file:///crypto_keyfile.bin local
Obviously upstreaming an expanded version of the init script to Alpine might be a good idea, but I’m not sure this is the right call in all contexts. Hence a post, not an upstream attempt.