From 51ea2e3af9caa434e847ca74a86f5de5ade6058f Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 30 Jun 2022 14:20:47 +0200 Subject: [PATCH] introduce the "clevis_luks_unlock" API Introduce a new guestfs API called "clevis_luks_unlock". At the libguestfs level, it is quite simple; it wraps the "clevis luks unlock" guest command (implemented by the "clevis-luks-unlock" executable, which is in fact a shell script). The complexity is instead in the network-based disk encryption (Clevis/Tang) scheme. Useful documentation: - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/security_hardening/index#configuring-automated-unlocking-of-encrypted-volumes-using-policy-based-decryption_security-hardening - https://github.com/latchset/clevis#clevis - https://github.com/latchset/tang#tang The package providing "clevis-luks-unlock" is usually called "clevis-luks", occasionally "clevis". Some distros don't package clevis at all. Add the new API under a new option group (which may not be available) called "clevisluks". Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453 Signed-off-by: Laszlo Ersek Message-Id: <20220630122048.19335-3-lersek@redhat.com> Reviewed-by: Richard W.M. Jones (cherry picked from commit 9a3e9a6c03eaffe60196bc4c7ae4699beae01dc3) --- appliance/packagelist.in | 4 +++ daemon/Makefile.am | 1 + daemon/clevis-luks.c | 58 +++++++++++++++++++++++++++++++++++++++ generator/actions_core.ml | 40 +++++++++++++++++++++++++++ generator/proc_nr.ml | 1 + lib/MAX_PROC_NR | 2 +- lib/guestfs.pod | 19 ++++++++++--- 7 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 daemon/clevis-luks.c diff --git a/appliance/packagelist.in b/appliance/packagelist.in index 77a07acc6..0b79edcdd 100644 --- a/appliance/packagelist.in +++ b/appliance/packagelist.in @@ -23,6 +23,7 @@ dnl Basically the same with a few minor tweaks. ifelse(UBUNTU,1,`define(`DEBIAN',1)') ifelse(REDHAT,1, + clevis-luks cryptsetup cryptsetup-luks dnl old name used before Fedora 17 dhclient @@ -53,6 +54,7 @@ ifelse(DEBIAN,1, bsdmainutils dnl old name used in Jessie and earlier btrfs-tools + clevis-luks cryptsetup dash extlinux @@ -92,6 +94,7 @@ dnl iproute has been renamed to iproute2 ifelse(ARCHLINUX,1, cdrkit cdrtools + clevis cryptsetup dhclient dhcpcd @@ -119,6 +122,7 @@ ifelse(SUSE,1, augeas-lenses btrfsprogs cdrkit-cdrtools-compat + clevis cryptsetup dhcpcd dhcp-client diff --git a/daemon/Makefile.am b/daemon/Makefile.am index bbd49f9ea..f50faecd6 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -98,6 +98,7 @@ guestfsd_SOURCES = \ cap.c \ checksum.c \ cleanups.c \ + clevis-luks.c \ cmp.c \ command.c \ command.h \ diff --git a/daemon/clevis-luks.c b/daemon/clevis-luks.c new file mode 100644 index 000000000..d3d970d78 --- /dev/null +++ b/daemon/clevis-luks.c @@ -0,0 +1,58 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009-2022 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "daemon.h" +#include "actions.h" +#include "optgroups.h" + +#define MAX_ARGS 8 + +int +optgroup_clevisluks_available (void) +{ + return prog_exists ("clevis-luks-unlock"); +} + +int +do_clevis_luks_unlock (const char *device, const char *mapname) +{ + const char *argv[MAX_ARGS]; + size_t i = 0; + int r; + CLEANUP_FREE char *err = NULL; + + ADD_ARG (argv, i, "clevis"); + ADD_ARG (argv, i, "luks"); + ADD_ARG (argv, i, "unlock"); + ADD_ARG (argv, i, "-d"); + ADD_ARG (argv, i, device); + ADD_ARG (argv, i, "-n"); + ADD_ARG (argv, i, mapname); + ADD_ARG (argv, i, NULL); + + r = commandv (NULL, &err, argv); + if (r == -1) { + reply_with_error ("%s: %s: %s", device, mapname, err); + return -1; + } + + udev_settle (); + return 0; +} diff --git a/generator/actions_core.ml b/generator/actions_core.ml index 6cd42a290..3c9b0a9b2 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -9676,4 +9676,44 @@ and I the name of the underlying block device." }; shortdesc = "read directories entries"; longdesc = "Internal function for readdir." }; + { defaults with + name = "clevis_luks_unlock"; added = (1, 49, 3); + style = RErr, + [String (Device, "device"); String (PlainString, "mapname")], + []; + optional = Some "clevisluks"; + test_excuse = "needs networking and a configured Tang server"; + shortdesc = "open an encrypted LUKS block device with Clevis and Tang"; + longdesc = "\ +This command opens a block device that has been encrypted according to +the Linux Unified Key Setup (LUKS) standard, using network-bound disk +encryption (NBDE). + +C is the encrypted block device. + +The appliance will connect to the Tang servers noted in the tree of +Clevis pins that is bound to a keyslot of the LUKS header. The Clevis +pin tree may comprise C (redudancy) pins as internal nodes +(optionally), and C pins as leaves. C pins are not +supported. The appliance unlocks the encrypted block device by +combining responses from the Tang servers with metadata from the LUKS +header; there is no C parameter. + +This command will fail if networking has not been enabled for the +appliance. Refer to C. + +The command creates a new block device called F. +Reads and writes to this block device are decrypted from and encrypted +to the underlying C respectively. Close the decrypted block +device with C. + +C cannot be C<\"control\"> because that name is reserved by +device-mapper. + +If this block device contains LVM volume groups, then calling +C with the C parameter C will make +them visible. + +Use C to list all device mapper devices." }; + ] diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml index bdced51c9..edd9bd99d 100644 --- a/generator/proc_nr.ml +++ b/generator/proc_nr.ml @@ -514,6 +514,7 @@ let proc_nr = [ 509, "cryptsetup_close"; 510, "internal_list_rpm_applications"; 511, "internal_readdir"; +512, "clevis_luks_unlock" ] (* End of list. If adding a new entry, add it at the end of the list diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR index c0556fb20..4d0e90cbc 100644 --- a/lib/MAX_PROC_NR +++ b/lib/MAX_PROC_NR @@ -1 +1 @@ -511 +512 diff --git a/lib/guestfs.pod b/lib/guestfs.pod index 946ce2d36..0fbe114a5 100644 --- a/lib/guestfs.pod +++ b/lib/guestfs.pod @@ -591,11 +591,22 @@ For Windows BitLocker it returns C. Then open these devices by calling L. Obviously you will require the passphrase! +Passphrase-less unlocking is supported for LUKS (not BitLocker) +block devices that have been encrypted with network-bound disk +encryption (NBDE), using Clevis on the Linux guest side, and +Tang on a separate Linux server. Open such devices with +L. The appliance will need +networking enabled (refer to L) and actual +connectivity to the Tang servers noted in the C Clevis +pins that are bound to the LUKS header. (This includes the +ability to resolve the names of the Tang servers.) + Opening an encrypted device creates a new device mapper device -called F (where C is the -string you supply to L). -Reads and writes to this mapper device are decrypted from and -encrypted to the underlying block device respectively. +called F (where C is the string +you supply to L or +L). Reads and writes to this mapper +device are decrypted from and encrypted to the underlying block +device respectively. LVM volume groups on the device can be made visible by calling L followed by L. -- 2.31.1