]> granicus.if.org Git - zfs/commitdiff
systemd encryption key support
authorAntonio Russo <antonio.e.russo@gmail.com>
Sun, 2 Jun 2019 12:57:10 +0000 (08:57 -0400)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Mon, 15 Jul 2019 23:31:47 +0000 (16:31 -0700)
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 <rlaager@wiktel.com>
Reviewed-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Antonio Russo <antonio.e.russo@gmail.com>
Closes #8750
Closes #8848

cmd/zed/zed.d/history_event-zfs-list-cacher.sh.in
etc/systemd/system-generators/zfs-mount-generator.in
man/man8/zfs-mount-generator.8.in

index c1513cf3a01fb0a2a009ed2177cc01818faa66cb..6d0f44ab326016ac18a7d1038f79ee5baf63ce18 100755 (executable)
@@ -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}"
 
index 5428eb25d92c5a2ff50b28b7997f96157ee268ca..ae208c965f971a9f9c3879408b35bd781def7aaf 100755 (executable)
@@ -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}
index 79720601d62ae5ffa8d7effdef31b6b24cbdf662..48e4e2dfac29146ebe13085b562ac18ca1c2f2ff 100644 (file)
@@ -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