Blob Blame Raw
From 523f1361c759d5af0952b0137d4dbd51be1e7b3d Mon Sep 17 00:00:00 2001
From: Sergio Correia <scorreia@redhat.com>
Date: Sun, 22 Dec 2019 17:01:09 -0500
Subject: [PATCH] Use one clevis-luks-askpass per device

This should improve the reliability of the boot unlocking, especially
when unlocking multiple devices upon boot.

It also greatly simplifies the configuration, as three is no need to
enable any systemd units manually nor add _netdev to either fstab or
crypttab.
---
 src/luks/clevis-luks-unlockers.7.adoc         | 16 +++----------
 src/luks/systemd/clevis-luks-askpass          |  7 +++++-
 src/luks/systemd/clevis-luks-askpass.path     | 10 --------
 .../systemd/clevis-luks-askpass.service.in    |  8 -------
 src/luks/systemd/clevis-luks-askpass@.path    | 12 ++++++++++
 .../systemd/clevis-luks-askpass@.service.in   |  9 +++++++
 src/luks/systemd/dracut/module-setup.sh.in    | 24 +++++++++++++++++++
 src/luks/systemd/meson.build                  |  8 +++----
 8 files changed, 58 insertions(+), 36 deletions(-)
 delete mode 100644 src/luks/systemd/clevis-luks-askpass.path
 delete mode 100644 src/luks/systemd/clevis-luks-askpass.service.in
 create mode 100644 src/luks/systemd/clevis-luks-askpass@.path
 create mode 100644 src/luks/systemd/clevis-luks-askpass@.service.in

diff --git a/src/luks/clevis-luks-unlockers.7.adoc b/src/luks/clevis-luks-unlockers.7.adoc
index 161b73a..e8d47ba 100644
--- a/src/luks/clevis-luks-unlockers.7.adoc
+++ b/src/luks/clevis-luks-unlockers.7.adoc
@@ -26,7 +26,7 @@ You can unlock a LUKS volume manually using the following command:
 
 For more information, see link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)].
 
-== EARLY BOOT UNLOCKING
+== BOOT UNLOCKING
 
 If Clevis integration does not already ship in your initramfs, you may need to
 rebuild your initramfs with this command:
@@ -34,23 +34,13 @@ rebuild your initramfs with this command:
     $ sudo dracut -f
 
 Once Clevis is integrated into your initramfs, a simple reboot should unlock
-your root volume. Note, however, that early boot integration only works for the
-root volume. Non-root volumes should use the late boot unlocker.
+your clevis-bound volumes. Root volumes will be unlocked in early-boot, while the
+remaining volumes will be unlocked after dracut switch-root.
 
 Dracut will bring up your network using DHCP by default. If you need to specify
 additional network parameters, such as static IP configuration, please consult
 the dracut documentation.
 
-== LATE BOOT UNLOCKING
-
-You can enable late boot unlocking by executing the following command:
-
-    $ sudo systemctl enable clevis-luks-askpass.path
-
-After a reboot, Clevis will attempt to unlock all *_netdev* devices listed in
-*/etc/crypttab* when systemd prompts for their passwords. This implies that
-systemd support for *_netdev* is required.
-
 == DESKTOP UNLOCKING
 
 When the udisks2 unlocker is installed, your GNOME desktop session should
diff --git a/src/luks/systemd/clevis-luks-askpass b/src/luks/systemd/clevis-luks-askpass
index b01d93a..feebb1a 100755
--- a/src/luks/systemd/clevis-luks-askpass
+++ b/src/luks/systemd/clevis-luks-askpass
@@ -24,15 +24,17 @@ UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
 shopt -s nullglob
 
 path=/run/systemd/ask-password
-while getopts ":lp:" o; do
+while getopts ":lpu:" o; do
     case "$o" in
     l) loop=true;;
     p) path=$OPTARG;;
+    u) device_uuid=$OPTARG;;
     esac
 done
 
 while true; do
     todo=0
+    [ -n "${device_uuid}" ] && todo=1 && loop=true
 
     for question in $path/ask.*; do
         metadata=false
@@ -48,6 +50,8 @@ while true; do
         done < "$question"
 
         [ -z "$d" -o -z "$s" ] && continue
+        [[ -n "${device_uuid}" ]] && [[ "${d}" != *"${device_uuid}"* ]] \
+            && continue
 
         if cryptsetup isLuks --type luks1 "$d"; then
             # If the device is not initialized, sliently skip it.
@@ -79,6 +83,7 @@ while true; do
             done
         fi
 
+        [ -n "${device_uuid}" ] && [ "${unlocked}" == true ] && todo=0 && break
         [ $metadata == true ] || continue
         [ $unlocked == true ] && continue
         todo=$((todo + 1))
diff --git a/src/luks/systemd/clevis-luks-askpass.path b/src/luks/systemd/clevis-luks-askpass.path
deleted file mode 100644
index a4d01ba..0000000
--- a/src/luks/systemd/clevis-luks-askpass.path
+++ /dev/null
@@ -1,10 +0,0 @@
-[Unit]
-Description=Clevis systemd-ask-password Watcher
-Before=remote-fs-pre.target
-Wants=remote-fs-pre.target
-
-[Path]
-PathChanged=/run/systemd/ask-password
-
-[Install]
-WantedBy=remote-fs.target
diff --git a/src/luks/systemd/clevis-luks-askpass.service.in b/src/luks/systemd/clevis-luks-askpass.service.in
deleted file mode 100644
index 2c6bbed..0000000
--- a/src/luks/systemd/clevis-luks-askpass.service.in
+++ /dev/null
@@ -1,8 +0,0 @@
-[Unit]
-Description=Clevis LUKS systemd-ask-password Responder
-Requires=network-online.target
-After=network-online.target
-
-[Service]
-Type=oneshot
-ExecStart=@libexecdir@/clevis-luks-askpass -l
diff --git a/src/luks/systemd/clevis-luks-askpass@.path b/src/luks/systemd/clevis-luks-askpass@.path
new file mode 100644
index 0000000..3f23665
--- /dev/null
+++ b/src/luks/systemd/clevis-luks-askpass@.path
@@ -0,0 +1,12 @@
+[Unit]
+Description=Clevis systemd-ask-password Watcher for %i
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=basic.target shutdown.target
+
+[Path]
+DirectoryNotEmpty=/run/systemd/ask-password
+MakeDirectory=yes
+
+[Install]
+WantedBy=basic.target
diff --git a/src/luks/systemd/clevis-luks-askpass@.service.in b/src/luks/systemd/clevis-luks-askpass@.service.in
new file mode 100644
index 0000000..cd26eb2
--- /dev/null
+++ b/src/luks/systemd/clevis-luks-askpass@.service.in
@@ -0,0 +1,9 @@
+[Unit]
+Description=Clevis LUKS systemd-ask-password Responder for luks-%i
+DefaultDependencies=no
+Conflicts=shutdown.target
+Before=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=@libexecdir@/clevis-luks-askpass -u %i
diff --git a/src/luks/systemd/dracut/module-setup.sh.in b/src/luks/systemd/dracut/module-setup.sh.in
index 841f7a8..1877715 100755
--- a/src/luks/systemd/dracut/module-setup.sh.in
+++ b/src/luks/systemd/dracut/module-setup.sh.in
@@ -29,6 +29,29 @@ is_bound_to_tang() {
     return 1
 }
 
+configure_passwd_watchers() {
+    if ! command -v systemctl >/dev/null; then
+        return 1
+    fi
+
+    local proc_cmdline
+    proc_cmdline=$(</proc/cmdline)
+
+    local luks_uuid
+    local cfg
+    for dev in $(lsblk -p -n -s -r \
+                 | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
+        luks_uuid=$(cryptsetup luksUUID "${dev}")
+        [[ "${proc_cmdline}" == *"rd.luks.uuid=luks-${luks_uuid}"* ]] && continue
+
+        if cfg=$(clevis luks list -d "${dev}" 2>/dev/null); then
+            local action=enable
+            [ -z "${cfg}" ] && action=disable
+            systemctl "${action}" "clevis-luks-askpass@${luks_uuid}.path" 2>/dev/null
+        fi
+    done
+}
+
 depends() {
     local depends="crypt systemd"
     if is_bound_to_tang; then
@@ -84,6 +107,7 @@ install() {
 	inst_libdir_file "libtss2-tcti-device.so*"
     fi
 
+    configure_passwd_watchers
     dracut_need_initqueue
 }
 
diff --git a/src/luks/systemd/meson.build b/src/luks/systemd/meson.build
index 108e9d8..334e84c 100644
--- a/src/luks/systemd/meson.build
+++ b/src/luks/systemd/meson.build
@@ -6,14 +6,14 @@ if systemd.found()
   unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
 
   configure_file(
-    input: 'clevis-luks-askpass.service.in',
-    output: 'clevis-luks-askpass.service',
+    input: 'clevis-luks-askpass@.service.in',
+    output: 'clevis-luks-askpass@.service',
     install_dir: unitdir,
     configuration: data,
   )
 
-  install_data('clevis-luks-askpass.path', install_dir: unitdir)
+  install_data('clevis-luks-askpass@.path', install_dir: unitdir)
   install_data('clevis-luks-askpass', install_dir: libexecdir)
 else
   warning('Will not install systemd support due to missing dependencies!')
-endif
\ No newline at end of file
+endif
-- 
2.18.1