Blame SOURCES/0008-Use-one-clevis-luks-askpass-per-device.patch

64015d
From 3250784e99016d9f920892dbb1438b9e76fb210b Mon Sep 17 00:00:00 2001
64015d
From: Sergio Correia <scorreia@redhat.com>
64015d
Date: Sun, 10 May 2020 15:57:23 -0300
64015d
Subject: [PATCH 8/8] Use one clevis-luks-askpass per device
64015d
64015d
This should improve the reliability of the boot unlocking, especially
64015d
when unlocking multiple devices upon boot.
64015d
64015d
It also greatly simplifies the configuration, as there is no need to
64015d
enable any systemd units manually nor add _netdev to either fstab or
64015d
crypttab.
64015d
---
64015d
 src/luks/clevis-luks-common-functions         |  8 ++
64015d
 src/luks/clevis-luks-unlockers.7.adoc         | 16 +---
64015d
 src/luks/systemd/clevis-luks-askpass          | 81 ++++++-------------
64015d
 src/luks/systemd/clevis-luks-askpass.path     | 10 ---
64015d
 .../systemd/clevis-luks-askpass.service.in    |  8 --
64015d
 src/luks/systemd/clevis-luks-askpass@.path    | 12 +++
64015d
 .../systemd/clevis-luks-askpass@.service.in   |  8 ++
64015d
 .../systemd/dracut/clevis/module-setup.sh.in  | 23 ++++++
64015d
 src/luks/systemd/meson.build                  |  6 +-
64015d
 9 files changed, 80 insertions(+), 92 deletions(-)
64015d
 delete mode 100644 src/luks/systemd/clevis-luks-askpass.path
64015d
 delete mode 100644 src/luks/systemd/clevis-luks-askpass.service.in
64015d
 create mode 100644 src/luks/systemd/clevis-luks-askpass@.path
64015d
 create mode 100644 src/luks/systemd/clevis-luks-askpass@.service.in
64015d
64015d
diff --git a/src/luks/clevis-luks-common-functions b/src/luks/clevis-luks-common-functions
64015d
index 5b515ad..c9d712a 100644
64015d
--- a/src/luks/clevis-luks-common-functions
64015d
+++ b/src/luks/clevis-luks-common-functions
64015d
@@ -555,3 +555,11 @@ clevis_luks_restore_dev() {
64015d
     fi
64015d
     return 0
64015d
 }
64015d
+
64015d
+# clevis_is_luks_device_by_uuid_open() checks whether the LUKS device with
64015d
+# given UUID is open.
64015d
+clevis_is_luks_device_by_uuid_open() {
64015d
+    local LUKS_UUID="${1}"
64015d
+    [ -z "${LUKS_UUID}" ] && return 1
64015d
+    test -b /dev/disk/by-id/dm-uuid-*"${LUKS_UUID//-/}"*
64015d
+}
64015d
diff --git a/src/luks/clevis-luks-unlockers.7.adoc b/src/luks/clevis-luks-unlockers.7.adoc
64015d
index 161b73a..e8d47ba 100644
64015d
--- a/src/luks/clevis-luks-unlockers.7.adoc
64015d
+++ b/src/luks/clevis-luks-unlockers.7.adoc
64015d
@@ -26,7 +26,7 @@ You can unlock a LUKS volume manually using the following command:
64015d
 
64015d
 For more information, see link:clevis-luks-unlock.1.adoc[*clevis-luks-unlock*(1)].
64015d
 
64015d
-== EARLY BOOT UNLOCKING
64015d
+== BOOT UNLOCKING
64015d
 
64015d
 If Clevis integration does not already ship in your initramfs, you may need to
64015d
 rebuild your initramfs with this command:
64015d
@@ -34,23 +34,13 @@ rebuild your initramfs with this command:
64015d
     $ sudo dracut -f
64015d
 
64015d
 Once Clevis is integrated into your initramfs, a simple reboot should unlock
64015d
-your root volume. Note, however, that early boot integration only works for the
64015d
-root volume. Non-root volumes should use the late boot unlocker.
64015d
+your clevis-bound volumes. Root volumes will be unlocked in early-boot, while the
64015d
+remaining volumes will be unlocked after dracut switch-root.
64015d
 
64015d
 Dracut will bring up your network using DHCP by default. If you need to specify
64015d
 additional network parameters, such as static IP configuration, please consult
64015d
 the dracut documentation.
64015d
 
64015d
-== LATE BOOT UNLOCKING
64015d
-
64015d
-You can enable late boot unlocking by executing the following command:
64015d
-
64015d
-    $ sudo systemctl enable clevis-luks-askpass.path
64015d
-
64015d
-After a reboot, Clevis will attempt to unlock all *_netdev* devices listed in
64015d
-*/etc/crypttab* when systemd prompts for their passwords. This implies that
64015d
-systemd support for *_netdev* is required.
64015d
-
64015d
 == DESKTOP UNLOCKING
64015d
 
64015d
 When the udisks2 unlocker is installed, your GNOME desktop session should
64015d
diff --git a/src/luks/systemd/clevis-luks-askpass b/src/luks/systemd/clevis-luks-askpass
64015d
index 9fea6aa..20294e5 100755
64015d
--- a/src/luks/systemd/clevis-luks-askpass
64015d
+++ b/src/luks/systemd/clevis-luks-askpass
64015d
@@ -19,96 +19,61 @@
64015d
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
64015d
 #
64015d
 
64015d
-UUID=cb6e8904-81ff-40da-a84a-07ab9ab5715e
64015d
+. clevis-luks-common-functions
64015d
 
64015d
 shopt -s nullglob
64015d
 
64015d
 path=/run/systemd/ask-password
64015d
-while getopts ":lp:" o; do
64015d
+while getopts ":lp:u:" o; do
64015d
     case "$o" in
64015d
     l) loop=true;;
64015d
     p) path="$OPTARG";;
64015d
+    u) device_uuid=$OPTARG;;
64015d
+    *) ;;
64015d
     esac
64015d
 done
64015d
 
64015d
-luks1_decrypt() {
64015d
-    luksmeta load "$@" \
64015d
-        | clevis decrypt
64015d
-
64015d
-    local rc
64015d
-    for rc in "${PIPESTATUS[@]}"; do
64015d
-        [ $rc -eq 0 ] || return $rc
64015d
-    done
64015d
-    return 0
64015d
-}
64015d
-
64015d
-luks2_jwe() {
64015d
-    # jose jwe fmt -c outputs extra \n, so clean it up
64015d
-    cryptsetup token export "$@" \
64015d
-        | jose fmt -j- -Og jwe -o- \
64015d
-        | jose jwe fmt -i- -c \
64015d
-        | tr -d '\n'
64015d
-
64015d
-    local rc
64015d
-    for rc in "${PIPESTATUS[@]}"; do
64015d
-        [ $rc -eq 0 ] || return $rc
64015d
-    done
64015d
-    return 0
64015d
-}
64015d
-
64015d
 while true; do
64015d
     todo=0
64015d
 
64015d
     for question in "$path"/ask.*; do
64015d
-        metadata=false
64015d
         unlocked=false
64015d
         d=
64015d
         s=
64015d
 
64015d
-        while read line; do
64015d
+        while read -r line; do
64015d
             case "$line" in
64015d
                 Id=cryptsetup:*) d="${line##Id=cryptsetup:}";;
64015d
                 Socket=*) s="${line##Socket=}";;
64015d
             esac
64015d
         done < "$question"
64015d
 
64015d
-        [ "$d" ] && [ "$s" ] || continue
64015d
+        [ -b "${d}" ] || continue
64015d
+        [ -S "${s}" ] || continue
64015d
 
64015d
-        if cryptsetup isLuks --type luks1 "$d"; then
64015d
-            # If the device is not initialized, sliently skip it.
64015d
-            luksmeta test -d "$d" || continue
64015d
-
64015d
-            while read -r slot state uuid; do
64015d
-                [ "$state" == "active" ] || continue
64015d
-                [ "$uuid" == "$UUID" ] || continue
64015d
-                metadata=true
64015d
-
64015d
-                if pt="$(luks1_decrypt -d "$d" -s "$slot" -u "$UUID")"; then
64015d
-                    echo -n "+$pt" | ncat -U -u --send-only "$s"
64015d
-                    unlocked=true
64015d
-                    break
64015d
-                fi
64015d
-            done < <(luksmeta show -d "$d")
64015d
-        elif cryptsetup isLuks --type luks2 "$d"; then
64015d
-            while read -r id; do
64015d
-                jwe="$(luks2_jwe --token-id "$id" "$d")" \
64015d
-                    || continue
64015d
-                metadata=true
64015d
+        if [ -n "${device_uuid}" ]; then
64015d
+            uuid="$(cryptsetup luksUUID "${d}")"
64015d
+            [ "${uuid}" != "${device_uuid}" ] && todo=1 && continue
64015d
+        fi
64015d
 
64015d
-                if pt="$(echo -n "$jwe" | clevis decrypt)"; then
64015d
-                    echo -n "+$pt" | ncat -U -u --send-only "$s"
64015d
-                    unlocked=true
64015d
-                    break
64015d
-                fi
64015d
-            done < <(cryptsetup luksDump "$d" | sed -rn 's|^\s+([0-9]+): clevis|\1|p')
64015d
+        if pt="$(clevis_luks_unlock_device "${d}")"; then
64015d
+            echo -n "+$pt" | ncat -U -u --send-only "$s"
64015d
+            unlocked=true
64015d
         fi
64015d
 
64015d
-        [ "$metadata" == true ] || continue
64015d
+        [ -n "${device_uuid}" ] && [ "${unlocked}" == true ] && break
64015d
         [ "$unlocked" == true ] && continue
64015d
         ((todo++))
64015d
     done
64015d
 
64015d
-    if [ $todo -eq 0 ] || [ "$loop" != true ]; then
64015d
+    if [ -n "${device_uuid}" ]; then
64015d
+        [ ! -b /dev/disk/by-uuid/"${device_uuid}" ] && break
64015d
+        if clevis_is_luks_device_by_uuid_open "${device_uuid}"; then
64015d
+            break
64015d
+        fi
64015d
+    fi
64015d
+
64015d
+    if [ "$todo" -eq 0 ] || [ "$loop" != true ]; then
64015d
         break;
64015d
     fi
64015d
 
64015d
diff --git a/src/luks/systemd/clevis-luks-askpass.path b/src/luks/systemd/clevis-luks-askpass.path
64015d
deleted file mode 100644
64015d
index a4d01ba..0000000
64015d
--- a/src/luks/systemd/clevis-luks-askpass.path
64015d
+++ /dev/null
64015d
@@ -1,10 +0,0 @@
64015d
-[Unit]
64015d
-Description=Clevis systemd-ask-password Watcher
64015d
-Before=remote-fs-pre.target
64015d
-Wants=remote-fs-pre.target
64015d
-
64015d
-[Path]
64015d
-PathChanged=/run/systemd/ask-password
64015d
-
64015d
-[Install]
64015d
-WantedBy=remote-fs.target
64015d
diff --git a/src/luks/systemd/clevis-luks-askpass.service.in b/src/luks/systemd/clevis-luks-askpass.service.in
64015d
deleted file mode 100644
64015d
index 2c6bbed..0000000
64015d
--- a/src/luks/systemd/clevis-luks-askpass.service.in
64015d
+++ /dev/null
64015d
@@ -1,8 +0,0 @@
64015d
-[Unit]
64015d
-Description=Clevis LUKS systemd-ask-password Responder
64015d
-Requires=network-online.target
64015d
-After=network-online.target
64015d
-
64015d
-[Service]
64015d
-Type=oneshot
64015d
-ExecStart=@libexecdir@/clevis-luks-askpass -l
64015d
diff --git a/src/luks/systemd/clevis-luks-askpass@.path b/src/luks/systemd/clevis-luks-askpass@.path
64015d
new file mode 100644
64015d
index 0000000..3f23665
64015d
--- /dev/null
64015d
+++ b/src/luks/systemd/clevis-luks-askpass@.path
64015d
@@ -0,0 +1,12 @@
64015d
+[Unit]
64015d
+Description=Clevis systemd-ask-password Watcher for %i
64015d
+DefaultDependencies=no
64015d
+Conflicts=shutdown.target
64015d
+Before=basic.target shutdown.target
64015d
+
64015d
+[Path]
64015d
+DirectoryNotEmpty=/run/systemd/ask-password
64015d
+MakeDirectory=yes
64015d
+
64015d
+[Install]
64015d
+WantedBy=basic.target
64015d
diff --git a/src/luks/systemd/clevis-luks-askpass@.service.in b/src/luks/systemd/clevis-luks-askpass@.service.in
64015d
new file mode 100644
64015d
index 0000000..4165ec5
64015d
--- /dev/null
64015d
+++ b/src/luks/systemd/clevis-luks-askpass@.service.in
64015d
@@ -0,0 +1,8 @@
64015d
+[Unit]
64015d
+Description=Clevis LUKS systemd-ask-password Responder for luks-%i
64015d
+DefaultDependencies=no
64015d
+Conflicts=shutdown.target
64015d
+Before=shutdown.target
64015d
+
64015d
+[Service]
64015d
+ExecStart=@libexecdir@/clevis-luks-askpass -u %i
64015d
diff --git a/src/luks/systemd/dracut/clevis/module-setup.sh.in b/src/luks/systemd/dracut/clevis/module-setup.sh.in
64015d
index abc79b3..1a0d6f7 100755
64015d
--- a/src/luks/systemd/dracut/clevis/module-setup.sh.in
64015d
+++ b/src/luks/systemd/dracut/clevis/module-setup.sh.in
64015d
@@ -23,6 +23,24 @@ depends() {
64015d
     return 255
64015d
 }
64015d
 
64015d
+configure_passwd_watchers() {
64015d
+    if ! command -v systemctl >/dev/null; then
64015d
+        return 1
64015d
+    fi
64015d
+
64015d
+    find /etc/systemd/system/ -name "clevis-luks-askpass*" -exec rm -f {} \;
64015d
+
64015d
+    local uuid
64015d
+    for dev in $(lsblk -p -n -s -r \
64015d
+                 | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
64015d
+        uuid=$(cryptsetup luksUUID "${dev}")
64015d
+
64015d
+        if clevis luks list -d "${dev}" >/dev/null 2>/dev/null; then
64015d
+            systemctl enable "clevis-luks-askpass@${uuid}.path" 2>/dev/null
64015d
+        fi
64015d
+    done
64015d
+}
64015d
+
64015d
 install() {
64015d
     inst_hook initqueue/online 60 "$moddir/clevis-hook.sh"
64015d
     inst_hook initqueue/settled 60 "$moddir/clevis-hook.sh"
64015d
@@ -30,6 +48,10 @@ install() {
64015d
     inst_multiple \
64015d
 	/etc/services \
64015d
         @libexecdir@/clevis-luks-askpass \
64015d
+        clevis-luks-common-functions \
64015d
+        head \
64015d
+        grep \
64015d
+        sed \
64015d
         clevis-decrypt \
64015d
         cryptsetup \
64015d
         luksmeta \
64015d
@@ -38,5 +60,6 @@ install() {
64015d
         jose \
64015d
         ncat
64015d
 
64015d
+    configure_passwd_watchers
64015d
     dracut_need_initqueue
64015d
 }
64015d
diff --git a/src/luks/systemd/meson.build b/src/luks/systemd/meson.build
64015d
index 369e7f7..334e84c 100644
64015d
--- a/src/luks/systemd/meson.build
64015d
+++ b/src/luks/systemd/meson.build
64015d
@@ -6,13 +6,13 @@ if systemd.found()
64015d
   unitdir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
64015d
 
64015d
   configure_file(
64015d
-    input: 'clevis-luks-askpass.service.in',
64015d
-    output: 'clevis-luks-askpass.service',
64015d
+    input: 'clevis-luks-askpass@.service.in',
64015d
+    output: 'clevis-luks-askpass@.service',
64015d
     install_dir: unitdir,
64015d
     configuration: data,
64015d
   )
64015d
 
64015d
-  install_data('clevis-luks-askpass.path', install_dir: unitdir)
64015d
+  install_data('clevis-luks-askpass@.path', install_dir: unitdir)
64015d
   install_data('clevis-luks-askpass', install_dir: libexecdir)
64015d
 else
64015d
   warning('Will not install systemd support due to missing dependencies!')
64015d
-- 
64015d
2.18.4
64015d