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 <lersek@redhat.com>
Message-Id: <20220630122048.19335-3-lersek@redhat.com>
Reviewed-by: Richard W.M. Jones <rjones@redhat.com>
This commit is contained in:
Laszlo Ersek
2022-06-30 14:20:47 +02:00
parent 99844660b4
commit 9a3e9a6c03
7 changed files with 120 additions and 5 deletions

View File

@@ -23,6 +23,7 @@ dnl Basically the same with a few minor tweaks.
ifelse(UBUNTU,1,`define(`DEBIAN',1)') ifelse(UBUNTU,1,`define(`DEBIAN',1)')
ifelse(REDHAT,1, ifelse(REDHAT,1,
clevis-luks
cryptsetup cryptsetup
cryptsetup-luks dnl old name used before Fedora 17 cryptsetup-luks dnl old name used before Fedora 17
dhclient dhclient
@@ -53,6 +54,7 @@ ifelse(DEBIAN,1,
bsdmainutils bsdmainutils
dnl old name used in Jessie and earlier dnl old name used in Jessie and earlier
btrfs-tools btrfs-tools
clevis-luks
cryptsetup cryptsetup
dash dash
extlinux extlinux
@@ -92,6 +94,7 @@ dnl iproute has been renamed to iproute2
ifelse(ARCHLINUX,1, ifelse(ARCHLINUX,1,
cdrkit cdrkit
cdrtools cdrtools
clevis
cryptsetup cryptsetup
dhclient dhclient
dhcpcd dhcpcd
@@ -119,6 +122,7 @@ ifelse(SUSE,1,
augeas-lenses augeas-lenses
btrfsprogs btrfsprogs
cdrkit-cdrtools-compat cdrkit-cdrtools-compat
clevis
cryptsetup cryptsetup
dhcpcd dhcpcd
dhcp-client dhcp-client

View File

@@ -98,6 +98,7 @@ guestfsd_SOURCES = \
cap.c \ cap.c \
checksum.c \ checksum.c \
cleanups.c \ cleanups.c \
clevis-luks.c \
cmp.c \ cmp.c \
command.c \ command.c \
command.h \ command.h \

58
daemon/clevis-luks.c Normal file
View File

@@ -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 <config.h>
#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;
}

View File

@@ -9720,4 +9720,44 @@ and I<not> the name of the underlying block device." };
shortdesc = "read directories entries"; shortdesc = "read directories entries";
longdesc = "Internal function for readdir." }; 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<device> 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<sss> (redudancy) pins as internal nodes
(optionally), and C<tang> pins as leaves. C<tpm2> 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<key> parameter.
This command will fail if networking has not been enabled for the
appliance. Refer to C<guestfs_set_network>.
The command creates a new block device called F</dev/mapper/mapname>.
Reads and writes to this block device are decrypted from and encrypted
to the underlying C<device> respectively. Close the decrypted block
device with C<guestfs_cryptsetup_close>.
C<mapname> cannot be C<\"control\"> because that name is reserved by
device-mapper.
If this block device contains LVM volume groups, then calling
C<guestfs_lvm_scan> with the C<activate> parameter C<true> will make
them visible.
Use C<guestfs_list_dm_devices> to list all device mapper devices." };
] ]

View File

@@ -514,6 +514,7 @@ let proc_nr = [
509, "cryptsetup_close"; 509, "cryptsetup_close";
510, "internal_list_rpm_applications"; 510, "internal_list_rpm_applications";
511, "internal_readdir"; 511, "internal_readdir";
512, "clevis_luks_unlock"
] ]
(* End of list. If adding a new entry, add it at the end of the list (* End of list. If adding a new entry, add it at the end of the list

View File

@@ -1 +1 @@
511 512

View File

@@ -591,11 +591,22 @@ For Windows BitLocker it returns C<BitLocker>.
Then open these devices by calling L</guestfs_cryptsetup_open>. Then open these devices by calling L</guestfs_cryptsetup_open>.
Obviously you will require the passphrase! 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</guestfs_clevis_luks_unlock>. The appliance will need
networking enabled (refer to L</guestfs_set_network>) and actual
connectivity to the Tang servers noted in the C<tang> 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 Opening an encrypted device creates a new device mapper device
called F</dev/mapper/mapname> (where C<mapname> is the called F</dev/mapper/mapname> (where C<mapname> is the string
string you supply to L</guestfs_cryptsetup_open>). you supply to L</guestfs_cryptsetup_open> or
Reads and writes to this mapper device are decrypted from and L</guestfs_clevis_luks_unlock>). Reads and writes to this mapper
encrypted to the underlying block device respectively. device are decrypted from and encrypted to the underlying block
device respectively.
LVM volume groups on the device can be made visible by calling LVM volume groups on the device can be made visible by calling
L</guestfs_vgscan> followed by L</guestfs_vg_activate_all>. L</guestfs_vgscan> followed by L</guestfs_vg_activate_all>.