From b1caebefb89bb6260993a2074770603d69d1b9d9 Mon Sep 17 00:00:00 2001 From: Antonio Russo Date: Sun, 2 Jun 2019 08:57:10 -0400 Subject: [PATCH] systemd encryption key support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modify zfs-mount-generator to produce a dependency on new zfs-import-key-*.service units, dynamically created at boot to call zfs load-key for the encryption root, before attempting to mount any encrypted datasets. These units are created by zfs-mount-generator, and RequiresMountsFor on the keyfile, if present, or call systemd-ask-password if a passphrase is requested. This patch includes suggestions from @Fabian-Gruenbichler, @ryanjaeb and @rlaager, as well an adaptation of @rlaager's script to retry on incorrect password entry. Reviewed-by: Richard Laager Reviewed-by: Fabian Grünbichler Reviewed-by: Brian Behlendorf Signed-off-by: Antonio Russo Closes #8750 Closes #8848 --- .../zed.d/history_event-zfs-list-cacher.sh.in | 4 +- .../system-generators/zfs-mount-generator.in | 54 ++++++++++++++++++- man/man8/zfs-mount-generator.8.in | 2 +- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in b/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in index c1513cf3a01f..6d0f44ab3260 100755 --- a/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in +++ b/cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in @@ -47,7 +47,7 @@ case "${ZEVENT_HISTORY_INTERNAL_NAME}" in # Only act if one of the tracked properties is altered. case "${ZEVENT_HISTORY_INTERNAL_STR%%=*}" in canmount|mountpoint|atime|relatime|devices|exec| \ - readonly|setuid|nbmand) ;; + readonly|setuid|nbmand|encroot|keylocation) ;; *) exit 0 ;; esac ;; @@ -62,7 +62,7 @@ zed_lock zfs-list trap abort_alter EXIT PROPS="name,mountpoint,canmount,atime,relatime,devices,exec,readonly" -PROPS="${PROPS},setuid,nbmand" +PROPS="${PROPS},setuid,nbmand,encroot,keylocation" "${ZFS}" list -H -t filesystem -o $PROPS -r "${ZEVENT_POOL}" > "${FSLIST_TMP}" diff --git a/etc/systemd/system-generators/zfs-mount-generator.in b/etc/systemd/system-generators/zfs-mount-generator.in index 5428eb25d92c..ae208c965f97 100755 --- a/etc/systemd/system-generators/zfs-mount-generator.in +++ b/etc/systemd/system-generators/zfs-mount-generator.in @@ -71,6 +71,8 @@ process_line() { p_readonly="${8}" p_setuid="${9}" p_nbmand="${10}" + p_encroot="${11}" + p_keyloc="${12}" # Check for canmount=off . if [ "${p_canmount}" = "off" ] ; then @@ -168,6 +170,54 @@ process_line() { "${dataset}" >/dev/kmsg fi + # Minimal pre-requisites to mount a ZFS dataset + wants="zfs-import.target" + if [ -n "${p_encroot}" ] && + [ "${p_encroot}" != "-" ] ; then + keyloadunit="zfs-load-key-$(systemd-escape "${p_encroot}").service" + if [ "${p_encroot}" = "${dataset}" ] ; then + pathdep="" + if [ "${p_keyloc%%://*}" = "file" ] ; then + pathdep="RequiresMountsFor='${p_keyloc#file://}'" + keyloadcmd="@sbindir@/zfs load-key '${dataset}'" + elif [ "${p_keyloc}" = "prompt" ] ; then + keyloadcmd="sh -c 'set -eu;"\ +"count=0;"\ +"while [ \$\$count -lt 3 ];do"\ +" systemd-ask-password --id=\"zfs:${dataset}\""\ +" \"Enter passphrase for ${dataset}:\"|"\ +" @sbindir@/zfs load-key \"${dataset}\" && exit 0;"\ +" count=\$\$((count + 1));"\ +"done;"\ +"exit 1'" + else + printf 'zfs-mount-generator: (%s) invalid keylocation\n' \ + "${dataset}" >/dev/kmsg + fi + cat > "${dest_norm}/${keyloadunit}" << EOF +# Automatically generated by zfs-mount-generator + +[Unit] +Description=Load ZFS key for ${dataset} +SourcePath=${cachefile} +Documentation=man:zfs-mount-generator(8) +DefaultDependencies=no +Wants=${wants} +After=${wants} +${pathdep} + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=${keyloadcmd} +ExecStop=@sbindir@/zfs unload-key '${dataset}' +EOF + fi + # Update the dependencies for the mount file to require the + # key-loading unit. + wants="${wants},${keyloadunit}" + fi + # If the mountpoint has already been created, give it precedence. if [ -e "${dest_norm}/${mountfile}" ] ; then printf 'zfs-mount-generator: %s already exists\n' "${mountfile}" \ @@ -183,8 +233,8 @@ process_line() { SourcePath=${cachefile} Documentation=man:zfs-mount-generator(8) Before=local-fs.target zfs-mount.service -After=zfs-import.target -Wants=zfs-import.target +After=${wants} +Wants=${wants} [Mount] Where=${p_mountpoint} diff --git a/man/man8/zfs-mount-generator.8.in b/man/man8/zfs-mount-generator.8.in index 79720601d62a..48e4e2dfac29 100644 --- a/man/man8/zfs-mount-generator.8.in +++ b/man/man8/zfs-mount-generator.8.in @@ -26,7 +26,7 @@ information on ZFS mountpoints must be stored separately. The output of the command .PP .RS 4 -zfs list -H -o name,mountpoint,canmount,atime,relatime,devices,exec,readonly,setuid,nbmand +zfs list -H -o name,mountpoint,canmount,atime,relatime,devices,exec,readonly,setuid,nbmand,encroot,keylocation .RE .PP for datasets that should be mounted by systemd, should be kept