Unlock encrypted root partition over SSH
This commit add a new feature for Debian-based distributions to unlock encrypted root partition over SSH. This feature is very handy on headless NAS or VPS cloud servers. To use this feature, you will need to install the dropbear-initramfs package. Reviewed-By: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-By: Tom Caputi <tcaputi@datto.com> Signed-off-by: Andrey Prokopenko <job@terem.fr> Signed-off-by: Richard Laager <rlaager@wiktel.com> Closes #10027
This commit is contained in:
parent
746d22ee02
commit
1cc635a2dd
|
@ -1,5 +1,8 @@
|
||||||
initrddir = /usr/share/initramfs-tools
|
initrddir = /usr/share/initramfs-tools
|
||||||
|
|
||||||
|
dist_initrd_SCRIPTS = \
|
||||||
|
zfsunlock
|
||||||
|
|
||||||
SUBDIRS = conf.d conf-hooks.d hooks scripts
|
SUBDIRS = conf.d conf-hooks.d hooks scripts
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
|
|
@ -72,3 +72,15 @@ The following kernel command line arguments are supported:
|
||||||
* `zfsdebug=(on,yes,1)`: Show extra debugging information
|
* `zfsdebug=(on,yes,1)`: Show extra debugging information
|
||||||
* `zfsforce=(on,yes,1)`: Force import the pool
|
* `zfsforce=(on,yes,1)`: Force import the pool
|
||||||
* `rollback=(on,yes,1)`: Rollback to (instead of clone) the snapshot
|
* `rollback=(on,yes,1)`: Rollback to (instead of clone) the snapshot
|
||||||
|
|
||||||
|
### Unlocking a ZFS encrypted root over SSH
|
||||||
|
|
||||||
|
To use this feature:
|
||||||
|
|
||||||
|
1. Install the `dropbear-initramfs` package. You may wish to uninstall the
|
||||||
|
`cryptsetup-initramfs` package to avoid warnings.
|
||||||
|
2. Add your SSH key(s) to `/etc/dropbear-initramfs/authorized_keys`. Note
|
||||||
|
that Dropbear does not support ed25519 keys; use RSA (2048-bit or more)
|
||||||
|
instead.
|
||||||
|
3. Rebuild the initramfs with your keys: `update-initramfs -u`
|
||||||
|
4. During the system boot, login via SSH and run: `zfsunlock`
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
zfs
|
zfs
|
||||||
|
zfsunlock
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
hooksdir = /usr/share/initramfs-tools/hooks
|
hooksdir = /usr/share/initramfs-tools/hooks
|
||||||
|
|
||||||
hooks_SCRIPTS = \
|
hooks_SCRIPTS = \
|
||||||
zfs
|
zfs \
|
||||||
|
zfsunlock
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
$(top_srcdir)/contrib/initramfs/hooks/zfs.in
|
$(top_srcdir)/contrib/initramfs/hooks/zfs.in \
|
||||||
|
$(top_srcdir)/contrib/initramfs/hooks/zfsunlock.in
|
||||||
|
|
||||||
$(hooks_SCRIPTS):%:%.in Makefile
|
$(hooks_SCRIPTS):%:%.in Makefile
|
||||||
-$(SED) -e 's,@sbindir\@,$(sbindir),g' \
|
-$(SED) -e 's,@sbindir\@,$(sbindir),g' \
|
||||||
|
|
|
@ -21,6 +21,7 @@ COPY_FILE_LIST="$COPY_FILE_LIST @udevruledir@/69-vdev.rules"
|
||||||
# These prerequisites are provided by the base system.
|
# These prerequisites are provided by the base system.
|
||||||
COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/dirname /bin/hostname /sbin/blkid"
|
COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/dirname /bin/hostname /sbin/blkid"
|
||||||
COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/env"
|
COPY_EXEC_LIST="$COPY_EXEC_LIST /usr/bin/env"
|
||||||
|
COPY_EXEC_LIST="$COPY_EXEC_LIST $(which systemd-ask-password)"
|
||||||
|
|
||||||
# Explicitly specify all kernel modules because automatic dependency resolution
|
# Explicitly specify all kernel modules because automatic dependency resolution
|
||||||
# is unreliable on many systems.
|
# is unreliable on many systems.
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
PREREQ="dropbear"
|
||||||
|
|
||||||
|
prereqs() {
|
||||||
|
echo "$PREREQ"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
prereqs)
|
||||||
|
prereqs
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
. /usr/share/initramfs-tools/hook-functions
|
||||||
|
|
||||||
|
copy_exec /usr/share/initramfs-tools/zfsunlock /usr/bin
|
|
@ -405,6 +405,8 @@ decrypt_fs()
|
||||||
ENCRYPTIONROOT="$(get_fs_value "${fs}" encryptionroot)"
|
ENCRYPTIONROOT="$(get_fs_value "${fs}" encryptionroot)"
|
||||||
KEYLOCATION="$(get_fs_value "${ENCRYPTIONROOT}" keylocation)"
|
KEYLOCATION="$(get_fs_value "${ENCRYPTIONROOT}" keylocation)"
|
||||||
|
|
||||||
|
echo "${ENCRYPTIONROOT}" > /run/zfs_fs_name
|
||||||
|
|
||||||
# If root dataset is encrypted...
|
# If root dataset is encrypted...
|
||||||
if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
|
if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
|
||||||
KEYSTATUS="$(get_fs_value "${ENCRYPTIONROOT}" keystatus)"
|
KEYSTATUS="$(get_fs_value "${ENCRYPTIONROOT}" keystatus)"
|
||||||
|
@ -418,6 +420,7 @@ decrypt_fs()
|
||||||
|
|
||||||
# Prompt with plymouth, if active
|
# Prompt with plymouth, if active
|
||||||
elif [ -e /bin/plymouth ] && /bin/plymouth --ping 2>/dev/null; then
|
elif [ -e /bin/plymouth ] && /bin/plymouth --ping 2>/dev/null; then
|
||||||
|
echo "plymouth" > /run/zfs_console_askpwd_cmd
|
||||||
while [ $TRY_COUNT -gt 0 ]; do
|
while [ $TRY_COUNT -gt 0 ]; do
|
||||||
plymouth ask-for-password --prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}" | \
|
plymouth ask-for-password --prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}" | \
|
||||||
$ZFS load-key "${ENCRYPTIONROOT}" && break
|
$ZFS load-key "${ENCRYPTIONROOT}" && break
|
||||||
|
@ -426,6 +429,7 @@ decrypt_fs()
|
||||||
|
|
||||||
# Prompt with systemd, if active
|
# Prompt with systemd, if active
|
||||||
elif [ -e /run/systemd/system ]; then
|
elif [ -e /run/systemd/system ]; then
|
||||||
|
echo "systemd-ask-password" > /run/zfs_console_askpwd_cmd
|
||||||
while [ $TRY_COUNT -gt 0 ]; do
|
while [ $TRY_COUNT -gt 0 ]; do
|
||||||
systemd-ask-password "Encrypted ZFS password for ${ENCRYPTIONROOT}" --no-tty | \
|
systemd-ask-password "Encrypted ZFS password for ${ENCRYPTIONROOT}" --no-tty | \
|
||||||
$ZFS load-key "${ENCRYPTIONROOT}" && break
|
$ZFS load-key "${ENCRYPTIONROOT}" && break
|
||||||
|
@ -434,7 +438,8 @@ decrypt_fs()
|
||||||
|
|
||||||
# Prompt with ZFS tty, otherwise
|
# Prompt with ZFS tty, otherwise
|
||||||
else
|
else
|
||||||
# Setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet"
|
# Temporarily setting "printk" to "7" allows the prompt to appear even when the "quiet" kernel option has been used
|
||||||
|
echo "load-key" > /run/zfs_console_askpwd_cmd
|
||||||
storeprintk="$(awk '{print $1}' /proc/sys/kernel/printk)"
|
storeprintk="$(awk '{print $1}' /proc/sys/kernel/printk)"
|
||||||
echo 7 > /proc/sys/kernel/printk
|
echo 7 > /proc/sys/kernel/printk
|
||||||
$ZFS load-key "${ENCRYPTIONROOT}"
|
$ZFS load-key "${ENCRYPTIONROOT}"
|
||||||
|
@ -964,6 +969,11 @@ mountroot()
|
||||||
mount_fs "$fs"
|
mount_fs "$fs"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
touch /run/zfs_unlock_complete
|
||||||
|
if [ -e /run/zfs_unlock_complete_notify ]; then
|
||||||
|
read zfs_unlock_complete_notify < /run/zfs_unlock_complete_notify
|
||||||
|
fi
|
||||||
|
|
||||||
# ------------
|
# ------------
|
||||||
# Debugging information
|
# Debugging information
|
||||||
if [ -n "${ZFS_DEBUG}" ]
|
if [ -n "${ZFS_DEBUG}" ]
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
if [ ! -e /run/zfs_fs_name ]; then
|
||||||
|
echo "Wait for the root pool to be imported or press Ctrl-C to exit."
|
||||||
|
fi
|
||||||
|
while [ ! -e /run/zfs_fs_name ]; do
|
||||||
|
if [ -e /run/zfs_unlock_complete ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 0.5
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
echo "Unlocking encrypted ZFS filesystems..."
|
||||||
|
echo "Enter the password or press Ctrl-C to exit."
|
||||||
|
echo
|
||||||
|
zfs_fs_name=""
|
||||||
|
if [ ! -e /run/zfs_unlock_complete_notify ]; then
|
||||||
|
mkfifo /run/zfs_unlock_complete_notify
|
||||||
|
fi
|
||||||
|
while [ ! -e /run/zfs_unlock_complete ]; do
|
||||||
|
zfs_fs_name=$(cat /run/zfs_fs_name)
|
||||||
|
zfs_console_askpwd_cmd=$(cat /run/zfs_console_askpwd_cmd)
|
||||||
|
systemd-ask-password "Encrypted ZFS password for ${zfs_fs_name}:" | \
|
||||||
|
/sbin/zfs load-key "$zfs_fs_name" || true
|
||||||
|
if [ "$(/sbin/zfs get -H -ovalue keystatus "$zfs_fs_name" 2> /dev/null)" = "available" ]; then
|
||||||
|
echo "Password for $zfs_fs_name accepted."
|
||||||
|
zfs_console_askpwd_pid=$(ps a -o pid= -o args | grep -v grep | grep "$zfs_console_askpwd_cmd" | cut -d ' ' -f3 | sort -n | head -n1)
|
||||||
|
if [ -n "$zfs_console_askpwd_pid" ]; then
|
||||||
|
kill "$zfs_console_askpwd_pid"
|
||||||
|
fi
|
||||||
|
# Wait for another filesystem to unlock.
|
||||||
|
while [ "$(cat /run/zfs_fs_name)" = "$zfs_fs_name" ] && [ ! -e /run/zfs_unlock_complete ]; do
|
||||||
|
sleep 0.5
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "Wrong password. Try again."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "Unlocking complete. Resuming boot sequence..."
|
||||||
|
echo "Please reconnect in a while."
|
||||||
|
echo "ok" > /run/zfs_unlock_complete_notify
|
Loading…
Reference in New Issue