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 + + + + + + + + + + + + + +
+ + +
+ + + + +