summary refs log tree commit diff
path: root/gnu
diff options
context:
space:
mode:
authorTomas Volf <wolf@wolfsden.cz>2024-01-11 18:35:39 +0100
committerLudovic Courtès <ludo@gnu.org>2024-01-14 23:00:03 +0100
commitd082312ef7adfea69c79d30ef947817b39832161 (patch)
treed588cc3cda334c2c08cf08fe311255a5aa56841b /gnu
parentdb43edaa0a7eaa0064224b31fbce07469ebeb93e (diff)
downloadguix-d082312ef7adfea69c79d30ef947817b39832161.tar.gz
mapped-devices: Allow unlocking by a key file.
Requiring the user to input their password in order to unlock a device is not
always reasonable, so having an option to unlock the device using a key file
is a nice quality of life change.

* gnu/system/mapped-devices.scm (open-luks-device): Add #:key-file argument.
(luks-device-mapping-with-options): New procedure.
* doc/guix.texi (Mapped Devices): Describe the new procedure.

Change-Id: I1de4e045f8c2c11f9a94f1656e839c785b0c11c4
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Diffstat (limited to 'gnu')
-rw-r--r--gnu/system/mapped-devices.scm67
1 files changed, 42 insertions, 25 deletions
diff --git a/gnu/system/mapped-devices.scm b/gnu/system/mapped-devices.scm
index e6b8970c12..c19a818453 100644
--- a/gnu/system/mapped-devices.scm
+++ b/gnu/system/mapped-devices.scm
@@ -2,6 +2,7 @@
 ;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org>
 ;;; Copyright © 2016 Andreas Enge <andreas@enge.fr>
 ;;; Copyright © 2017, 2018 Mark H Weaver <mhw@netris.org>
+;;; Copyright © 2024 Tomas Volf <~@wolfsden.cz>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -64,6 +65,7 @@
             check-device-initrd-modules           ;XXX: needs a better place
 
             luks-device-mapping
+            luks-device-mapping-with-options
             raid-device-mapping
             lvm-device-mapping))
 
@@ -188,7 +190,7 @@ option of @command{guix system}.\n")
 ;;; Common device mappings.
 ;;;
 
-(define (open-luks-device source targets)
+(define* (open-luks-device source targets #:key key-file)
   "Return a gexp that maps SOURCE to TARGET as a LUKS device, using
 'cryptsetup'."
   (with-imported-modules (source-module-closure
@@ -198,7 +200,8 @@ option of @command{guix system}.\n")
       ((target)
        #~(let ((source #$(if (uuid? source)
                              (uuid-bytevector source)
-                             source)))
+                             source))
+               (keyfile #$key-file))
            ;; XXX: 'use-modules' should be at the top level.
            (use-modules (rnrs bytevectors) ;bytevector?
                         ((gnu build file-systems)
@@ -215,29 +218,35 @@ option of @command{guix system}.\n")
            ;; 'cryptsetup open' requires standard input to be a tty to allow
            ;; for interaction but shepherd sets standard input to /dev/null;
            ;; thus, explicitly request a tty.
-           (zero? (system*/tty
-                   #$(file-append cryptsetup-static "/sbin/cryptsetup")
-                   "open" "--type" "luks"
-
-                   ;; Note: We cannot use the "UUID=source" syntax here
-                   ;; because 'cryptsetup' implements it by searching the
-                   ;; udev-populated /dev/disk/by-id directory but udev may
-                   ;; be unavailable at the time we run this.
-                   (if (bytevector? source)
-                       (or (let loop ((tries-left 10))
-                             (and (positive? tries-left)
-                                  (or (find-partition-by-luks-uuid source)
-                                      ;; If the underlying partition is
-                                      ;; not found, try again after
-                                      ;; waiting a second, up to ten
-                                      ;; times.  FIXME: This should be
-                                      ;; dealt with in a more robust way.
-                                      (begin (sleep 1)
-                                             (loop (- tries-left 1))))))
-                           (error "LUKS partition not found" source))
-                       source)
-
-                   #$target)))))))
+           (let ((partition
+                  ;; Note: We cannot use the "UUID=source" syntax here
+                  ;; because 'cryptsetup' implements it by searching the
+                  ;; udev-populated /dev/disk/by-id directory but udev may
+                  ;; be unavailable at the time we run this.
+                  (if (bytevector? source)
+                      (or (let loop ((tries-left 10))
+                            (and (positive? tries-left)
+                                 (or (find-partition-by-luks-uuid source)
+                                     ;; If the underlying partition is
+                                     ;; not found, try again after
+                                     ;; waiting a second, up to ten
+                                     ;; times.  FIXME: This should be
+                                     ;; dealt with in a more robust way.
+                                     (begin (sleep 1)
+                                            (loop (- tries-left 1))))))
+                          (error "LUKS partition not found" source))
+                      source)))
+             ;; We want to fallback to the password unlock if the keyfile fails.
+             (or (and keyfile
+                      (zero? (system*/tty
+                              #$(file-append cryptsetup-static "/sbin/cryptsetup")
+                              "open" "--type" "luks"
+                              "--key-file" keyfile
+                              partition #$target)))
+                 (zero? (system*/tty
+                         #$(file-append cryptsetup-static "/sbin/cryptsetup")
+                         "open" "--type" "luks"
+                         partition #$target)))))))))
 
 (define (close-luks-device source targets)
   "Return a gexp that closes TARGET, a LUKS device."
@@ -276,6 +285,14 @@ option of @command{guix system}.\n")
    (close close-luks-device)
    (check check-luks-device)))
 
+(define* (luks-device-mapping-with-options #:key key-file)
+  "Return a luks-device-mapping object with open modified to pass the arguments
+into the open-luks-device procedure."
+  (mapped-device-kind
+   (inherit luks-device-mapping)
+   (open (λ (source targets) (open-luks-device source targets
+                                               #:key-file key-file)))))
+
 (define (open-raid-device sources targets)
   "Return a gexp that assembles SOURCES (a list of devices) to the RAID device
 TARGET (e.g., \"/dev/md0\"), using 'mdadm'."