From 77c9663d72d03158e117fe96be8a483e0164b5e2 Mon Sep 17 00:00:00 2001 From: Or Ozeri Date: Mon, 13 Mar 2023 04:50:21 -0500 Subject: [PATCH] qemu: add support for librbd layered encryption This commit enables libvirt users to use layered encryption of RBD images, using the librbd encryption engine. This allows opening of an encrypted cloned image whose parent is encrypted with a possibly different encryption key. To open such images, multiple encryption secrets are expected to be defined under the encryption XML tag. Signed-off-by: Or Ozeri Reviewed-by: Peter Krempa --- docs/formatstorageencryption.rst | 11 +++-- src/conf/schemas/storagecommon.rng | 4 +- src/qemu/qemu_block.c | 20 ++++++-- src/qemu/qemu_domain.c | 14 ++++++ src/qemu/qemu_validate.c | 8 ++++ ...k-rbd-encryption-layering.x86_64-7.2.0.err | 1 + ...rbd-encryption-layering.x86_64-latest.args | 39 ++++++++++++++++ .../disk-network-rbd-encryption-layering.xml | 41 +++++++++++++++++ tests/qemuxml2argvtest.c | 2 + ...-rbd-encryption-layering.x86_64-latest.xml | 46 +++++++++++++++++++ tests/qemuxml2xmltest.c | 1 + 11 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-7.2.0.err create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.xml create mode 100644 tests/qemuxml2xmloutdata/disk-network-rbd-encryption-layering.x86_64-latest.xml diff --git a/docs/formatstorageencryption.rst b/docs/formatstorageencryption.rst index 2c19473d6b..3b3e9ea379 100644 --- a/docs/formatstorageencryption.rst +++ b/docs/formatstorageencryption.rst @@ -28,7 +28,10 @@ network disks. If the engine tag is not specified, the ``qemu`` engine will be used by default (assuming the qemu driver is used). Note that ``librbd`` engine is currently only supported by the qemu VM driver, and is not supported by the storage driver. Furthermore, the storage driver currently ignores the ``engine`` -tag. +tag. :since:`since 9.3.0` RBD layered encryption is supported. Layered +encryption requires a secret per each encrypted layer. The first secret +corresponds to the (child) image itself, the second secret to the parent image, +and so forth. The ``encryption`` tag can currently contain a sequence of ``secret`` tags, each with mandatory attributes ``type`` and either ``uuid`` or ``usage`` ( @@ -55,7 +58,8 @@ added to libvirt. The ``luks`` format is specific to a luks encrypted volume and the secret is used in order to either encrypt during volume creation or decrypt the volume for usage by the domain. A single ```` element is -expected. :since:`Since 2.1.0` . +expected (except for the case of RBD layered encryption mentioned above). +:since:`Since 2.1.0` . For volume creation, it is possible to specify the encryption algorithm used to encrypt the luks volume. The following two optional elements may be provided for @@ -102,7 +106,8 @@ can only be applied to RBD network disks (RBD images). Since the ``librbd`` engine is currently not supported by the libvirt storage driver, you cannot use it to control such disks. However, pre-formatted RBD luks2 disks can be loaded to a qemu VM using the qemu VM driver. A single -```` element is expected. +```` element is expected (except for the case of +RBD layered encryption mentioned above). Examples -------- diff --git a/src/conf/schemas/storagecommon.rng b/src/conf/schemas/storagecommon.rng index 23eff9ecb1..225456f03c 100644 --- a/src/conf/schemas/storagecommon.rng +++ b/src/conf/schemas/storagecommon.rng @@ -26,7 +26,9 @@ - + + + diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 0cc3b82cca..d50cfa20c5 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -564,6 +564,8 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, if (src->encryption && src->encryption->engine == VIR_STORAGE_ENCRYPTION_ENGINE_LIBRBD) { + size_t i; + switch ((virStorageEncryptionFormatType) src->encryption->format) { case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS: encformat = "luks"; @@ -580,11 +582,19 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, break; } - if (virJSONValueObjectAdd(&encrypt, - "s:format", encformat, - "s:key-secret", srcPriv->encinfo[0]->alias, - NULL) < 0) - return NULL; + for (i = src->encryption->nsecrets; i > 0; --i) { + g_autoptr(virJSONValue) new = NULL; + + /* we consume the lower layer 'encrypt' into a new object */ + if (virJSONValueObjectAdd(&new, + "s:format", encformat, + "s:key-secret", srcPriv->encinfo[i-1]->alias, + "A:parent", &encrypt, + NULL) < 0) + return NULL; + + encrypt = g_steal_pointer(&new); + } } if (virJSONValueObjectAdd(&ret, diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 4f40c89c59..cb0138c6fe 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5198,6 +5198,12 @@ qemuDomainValidateStorageSource(virStorageSource *src, return -1; } + if (src->encryption->nsecrets > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("qemu encryption engine expects only a single secret")); + return -1; + } + break; case VIR_STORAGE_ENCRYPTION_ENGINE_LIBRBD: @@ -5213,6 +5219,14 @@ qemuDomainValidateStorageSource(virStorageSource *src, _("librbd encryption is supported only with RBD backed disks")); return -1; } + + if (src->encryption->nsecrets > 1) { + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_RBD_ENCRYPTION_LAYERING)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("librbd encryption layering is not supported by this QEMU binary")); + return -1; + } + } break; case VIR_STORAGE_ENCRYPTION_ENGINE_DEFAULT: diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index d6aa2a58ab..12128acda6 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -3346,6 +3346,14 @@ qemuValidateDomainDeviceDefDisk(const virDomainDiskDef *disk, return -1; } + if (disk->bus == VIR_DOMAIN_DISK_BUS_SD && + disk->src && disk->src->encryption && disk->src->encryption->nsecrets > 1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("sd card '%s' does not support multiple encryption secrets"), + disk->dst); + return -1; + } + if (disk->src->type == VIR_STORAGE_TYPE_VHOST_USER) { if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VHOST_USER_BLK)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-7.2.0.err b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-7.2.0.err new file mode 100644 index 0000000000..73e5b2a1f3 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-7.2.0.err @@ -0,0 +1 @@ +unsupported configuration: librbd encryption layering is not supported by this QEMU binary diff --git a/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-latest.args b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-latest.args new file mode 100644 index 0000000000..c9e1a0cc72 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.x86_64-latest.args @@ -0,0 +1,39 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/var/lib/libvirt/qemu/domain--1-encryptdisk \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/var/lib/libvirt/qemu/domain--1-encryptdisk/.local/share \ +XDG_CACHE_HOME=/var/lib/libvirt/qemu/domain--1-encryptdisk/.cache \ +XDG_CONFIG_HOME=/var/lib/libvirt/qemu/domain--1-encryptdisk/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=encryptdisk,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain--1-encryptdisk/master-key.aes"}' \ +-machine pc-i440fx-2.1,usb=off,dump-guest-core=off,memory-backend=pc.ram,acpi=off \ +-accel tcg \ +-cpu qemu64 \ +-m 1024 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":1073741824}' \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 496898a6-e6ff-f7c8-5dc2-3cf410945ee9 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-boot strict=on \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \ +-object '{"qom-type":"secret","id":"libvirt-1-format-encryption-secret0","data":"9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1","keyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw==","format":"base64"}' \ +-object '{"qom-type":"secret","id":"libvirt-1-format-encryption-secret1","data":"9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1","keyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw==","format":"base64"}' \ +-object '{"qom-type":"secret","id":"libvirt-1-format-encryption-secret2","data":"9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1","keyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw==","format":"base64"}' \ +-blockdev '{"driver":"rbd","pool":"pool","image":"image","server":[{"host":"mon1.example.org","port":"6321"},{"host":"mon2.example.org","port":"6322"},{"host":"mon3.example.org","port":"6322"}],"encrypt":{"format":"luks","key-secret":"libvirt-1-format-encryption-secret0","parent":{"format":"luks","key-secret":"libvirt-1-format-encryption-secret1","parent":{"format":"luks","key-secret":"libvirt-1-format-encryption-secret2"}}},"node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x2","drive":"libvirt-1-format","id":"virtio-disk0","bootindex":1}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","addr":"0x3"}' \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.xml b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.xml new file mode 100644 index 0000000000..8c2c008dc3 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.xml @@ -0,0 +1,41 @@ + + encryptdisk + 496898a6-e6ff-f7c8-5dc2-3cf410945ee9 + 1048576 + 524288 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + + + +
+ + + + + +
+ + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index efecb7c89d..8473f84ba4 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1249,6 +1249,8 @@ mymain(void) DO_TEST_CAPS_LATEST("disk-network-rbd"); DO_TEST_CAPS_VER_PARSE_ERROR("disk-network-rbd-encryption", "6.0.0"); DO_TEST_CAPS_LATEST("disk-network-rbd-encryption"); + DO_TEST_CAPS_VER_PARSE_ERROR("disk-network-rbd-encryption-layering", "7.2.0"); + DO_TEST_CAPS_LATEST("disk-network-rbd-encryption-layering"); DO_TEST_CAPS_LATEST_PARSE_ERROR("disk-encryption-wrong"); DO_TEST_CAPS_LATEST("disk-network-rbd-no-colon"); /* qemu-6.0 is the last qemu version supporting sheepdog */ diff --git a/tests/qemuxml2xmloutdata/disk-network-rbd-encryption-layering.x86_64-latest.xml b/tests/qemuxml2xmloutdata/disk-network-rbd-encryption-layering.x86_64-latest.xml new file mode 100644 index 0000000000..e3a9463e43 --- /dev/null +++ b/tests/qemuxml2xmloutdata/disk-network-rbd-encryption-layering.x86_64-latest.xml @@ -0,0 +1,46 @@ + + encryptdisk + 496898a6-e6ff-f7c8-5dc2-3cf410945ee9 + 1048576 + 524288 + 1 + + hvm + + + + qemu64 + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + + + + + + + + + + + + +
+ + +
+ + + + +