[PATCH v2 0/7] qemu: add support for librbd layered encryption

v2: - add luks-any commits (including nit fixes) - removed qemu 8.0.0 replies commit - remove tautological if condition in qemuBlockStorageSourceAttachData initialization - add comments on validation of a single secret in qemu encryption engine - fix leak of qemuDomainStorageSourcePrivate->encinfo - remove ctxt->node modification in privatedata xml parsing - add test to modern-in.xml - squash commit #6 - add validation for a single secret in sd card disk Or Ozeri (7): qemu: capabilities: Introduce QEMU_CAPS_RBD_ENCRYPTION_LAYERING capability qemu: add support for multiple secret aliases qemu: add multi-secret support in qemuBlockStorageSourceAttachData qemu: add multi-secret support in _qemuDomainStorageSourcePrivate qemu: add support for librbd layered encryption qemu: capabilities: Introduce QEMU_CAPS_RBD_ENCRYPTION_LUKS_ANY capability qemu: add luks-any encryption support for RBD images docs/formatstorageencryption.rst | 20 ++- src/conf/schemas/storagecommon.rng | 5 +- src/conf/storage_encryption_conf.c | 2 +- src/conf/storage_encryption_conf.h | 1 + src/libvirt_private.syms | 1 + src/qemu/qemu_alias.c | 8 +- src/qemu/qemu_alias.h | 3 +- src/qemu/qemu_block.c | 77 ++++++++--- src/qemu/qemu_block.h | 5 +- src/qemu/qemu_blockjob.c | 6 + src/qemu/qemu_capabilities.c | 4 + src/qemu/qemu_capabilities.h | 2 + src/qemu/qemu_command.c | 29 +++- src/qemu/qemu_domain.c | 130 +++++++++++++++--- src/qemu/qemu_domain.h | 3 +- src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration_params.c | 2 +- src/qemu/qemu_validate.c | 8 ++ tests/qemublocktest.c | 7 +- .../caps_8.0.0.x86_64.xml | 2 + tests/qemustatusxml2xmldata/modern-in.xml | 14 ++ ...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 ++++++ ...k-rbd-encryption-luks-any.x86_64-7.2.0.err | 1 + ...rbd-encryption-luks-any.x86_64-latest.args | 37 +++++ .../disk-network-rbd-encryption-luks-any.xml | 39 ++++++ tests/qemuxml2argvtest.c | 4 + ...-rbd-encryption-layering.x86_64-latest.xml | 46 +++++++ ...-rbd-encryption-luks-any.x86_64-latest.xml | 44 ++++++ tests/qemuxml2xmltest.c | 2 + 31 files changed, 517 insertions(+), 68 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/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-7.2.0.err create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.xml create mode 100644 tests/qemuxml2xmloutdata/disk-network-rbd-encryption-layering.x86_64-latest.xml create mode 100644 tests/qemuxml2xmloutdata/disk-network-rbd-encryption-luks-any.x86_64-latest.xml -- 2.25.1

This capability represents that qemu supports the layered encryption of RBD images, where a cloned image is encrypted with a possible different encryption than its parent image. Signed-off-by: Or Ozeri <oro@il.ibm.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml | 1 + 3 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 218e6c09a4..c03ad714fa 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -691,6 +691,7 @@ VIR_ENUM_IMPL(virQEMUCaps, /* 445 */ "netdev.stream.reconnect", /* QEMU_CAPS_NETDEV_STREAM_RECONNECT */ "virtio-gpu.blob", /* QEMU_CAPS_VIRTIO_GPU_BLOB */ + "rbd-encryption-layering", /* QEMU_CAPS_RBD_ENCRYPTION_LAYERING */ ); @@ -1556,6 +1557,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "blockdev-add/arg-type/+nvme", QEMU_CAPS_DRIVE_NVME }, { "blockdev-add/arg-type/+file/aio/^io_uring", QEMU_CAPS_AIO_IO_URING }, { "blockdev-add/arg-type/+rbd/encrypt", QEMU_CAPS_RBD_ENCRYPTION }, + { "blockdev-add/arg-type/+rbd/encrypt/parent", QEMU_CAPS_RBD_ENCRYPTION_LAYERING }, { "blockdev-add/arg-type/+nbd/tls-hostname", QEMU_CAPS_BLOCKDEV_NBD_TLS_HOSTNAME }, { "blockdev-snapshot/$allow-write-only-overlay", QEMU_CAPS_BLOCKDEV_SNAPSHOT_ALLOW_WRITE_ONLY }, { "chardev-add/arg-type/backend/+socket/data/reconnect", QEMU_CAPS_CHARDEV_RECONNECT }, diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 21f23cff96..2d2c5f8eaf 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -670,6 +670,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ /* 445 */ QEMU_CAPS_NETDEV_STREAM_RECONNECT, /* -netdev stream supports reconnect */ QEMU_CAPS_VIRTIO_GPU_BLOB, /* -device virtio-gpu-*.blob= */ + QEMU_CAPS_RBD_ENCRYPTION_LAYERING, /* layered encryption support for Ceph RBD */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml index ee35ed2258..d120f5dc3c 100644 --- a/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml @@ -204,6 +204,7 @@ <flag name='pvpanic-pci'/> <flag name='netdev.stream.reconnect'/> <flag name='virtio-gpu.blob'/> + <flag name='rbd-encryption-layering'/> <version>7002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> -- 2.25.1

Change secret aliases from %s-%s-secret0 to %s-%s-secret%lu, which will later be used for storage encryption requiring more than a single secret. Signed-off-by: Or Ozeri <oro@il.ibm.com> --- src/qemu/qemu_alias.c | 8 +++++--- src/qemu/qemu_alias.h | 3 ++- src/qemu/qemu_domain.c | 14 ++++++++------ src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration_params.c | 2 +- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index a9809797d5..2e0a50b68b 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -801,17 +801,19 @@ qemuDomainGetMasterKeyAlias(void) /* qemuAliasForSecret: * @parentalias: alias of the parent object * @obj: optional sub-object of the parent device the secret is for + * @secret_idx: secret index number (0 in the case of a single secret) * * Generate alias for a secret object used by @parentalias device or one of * the dependencies of the device described by @obj. */ char * qemuAliasForSecret(const char *parentalias, - const char *obj) + const char *obj, + size_t secret_idx) { if (obj) - return g_strdup_printf("%s-%s-secret0", parentalias, obj); - return g_strdup_printf("%s-secret0", parentalias); + return g_strdup_printf("%s-%s-secret%lu", parentalias, obj, secret_idx); + return g_strdup_printf("%s-secret%lu", parentalias, secret_idx); } /* qemuAliasTLSObjFromSrcAlias diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h index f13f4cc5f8..eae08020dc 100644 --- a/src/qemu/qemu_alias.h +++ b/src/qemu/qemu_alias.h @@ -86,7 +86,8 @@ char *qemuAliasFromHostdev(const virDomainHostdevDef *hostdev); char *qemuDomainGetMasterKeyAlias(void); char *qemuAliasForSecret(const char *parentalias, - const char *obj); + const char *obj, + size_t secret_idx); char *qemuAliasTLSObjFromSrcAlias(const char *srcAlias) ATTRIBUTE_NONNULL(1); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0feab09bee..f62fb453a9 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -1317,6 +1317,7 @@ qemuDomainSecretInfoSetup(qemuDomainObjPrivate *priv, * @priv: pointer to domain private object * @srcalias: Alias of the disk/hostdev used to generate the secret alias * @secretuse: specific usage for the secret (may be NULL if main object is using it) + * @secret_idx: secret index number (0 in the case of a single secret) * @usageType: The virSecretUsageType * @username: username to use for authentication (may be NULL) * @seclookupdef: Pointer to seclookupdef data @@ -1329,12 +1330,13 @@ static qemuDomainSecretInfo * qemuDomainSecretInfoSetupFromSecret(qemuDomainObjPrivate *priv, const char *srcalias, const char *secretuse, + size_t secret_idx, virSecretUsageType usageType, const char *username, virSecretLookupTypeDef *seclookupdef) { qemuDomainSecretInfo *secinfo; - g_autofree char *alias = qemuAliasForSecret(srcalias, secretuse); + g_autofree char *alias = qemuAliasForSecret(srcalias, secretuse, secret_idx); g_autofree uint8_t *secret = NULL; size_t secretlen = 0; VIR_IDENTITY_AUTORESTORE virIdentity *oldident = virIdentityElevateCurrent(); @@ -1384,7 +1386,7 @@ qemuDomainSecretInfoTLSNew(qemuDomainObjPrivate *priv, } seclookupdef.type = VIR_SECRET_LOOKUP_TYPE_UUID; - return qemuDomainSecretInfoSetupFromSecret(priv, srcAlias, NULL, + return qemuDomainSecretInfoSetupFromSecret(priv, srcAlias, NULL, 0, VIR_SECRET_USAGE_TYPE_TLS, NULL, &seclookupdef); } @@ -1411,7 +1413,7 @@ qemuDomainSecretStorageSourcePrepareCookies(qemuDomainObjPrivate *priv, virStorageSource *src, const char *aliasprotocol) { - g_autofree char *secretalias = qemuAliasForSecret(aliasprotocol, "httpcookie"); + g_autofree char *secretalias = qemuAliasForSecret(aliasprotocol, "httpcookie", 0); g_autofree char *cookies = qemuBlockStorageSourceGetCookieString(src); return qemuDomainSecretInfoSetup(priv, secretalias, NULL, @@ -1460,7 +1462,7 @@ qemuDomainSecretStorageSourcePrepare(qemuDomainObjPrivate *priv, usageType = VIR_SECRET_USAGE_TYPE_CEPH; if (!(srcPriv->secinfo = qemuDomainSecretInfoSetupFromSecret(priv, aliasprotocol, - "auth", + "auth", 0, usageType, src->auth->username, &src->auth->seclookupdef))) @@ -1469,7 +1471,7 @@ qemuDomainSecretStorageSourcePrepare(qemuDomainObjPrivate *priv, if (hasEnc) { if (!(srcPriv->encinfo = qemuDomainSecretInfoSetupFromSecret(priv, aliasformat, - "encryption", + "encryption", 0, VIR_SECRET_USAGE_TYPE_VOLUME, NULL, &src->encryption->secrets[0]->seclookupdef))) @@ -11185,7 +11187,7 @@ qemuDomainPrepareHostdev(virDomainHostdevDef *hostdev, if (!(srcPriv->secinfo = qemuDomainSecretInfoSetupFromSecret(priv, backendalias, - NULL, + NULL, 0, usageType, src->auth->username, &src->auth->seclookupdef))) diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index da17525824..f15b4ea31f 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1753,7 +1753,7 @@ qemuDomainDelChardevTLSObjects(virQEMUDriver *driver, * secret UUID and we have a serial TCP chardev, then formulate a * secAlias which we'll attempt to destroy. */ if (cfg->chardevTLSx509secretUUID && - !(secAlias = qemuAliasForSecret(inAlias, NULL))) + !(secAlias = qemuAliasForSecret(inAlias, NULL, 0))) return -1; qemuDomainObjEnterMonitor(vm); diff --git a/src/qemu/qemu_migration_params.c b/src/qemu/qemu_migration_params.c index bd09dcfb23..0d747580f4 100644 --- a/src/qemu/qemu_migration_params.c +++ b/src/qemu/qemu_migration_params.c @@ -1129,7 +1129,7 @@ qemuMigrationParamsResetTLS(virDomainObj *vm, return; tlsAlias = qemuAliasTLSObjFromSrcAlias(QEMU_MIGRATION_TLS_ALIAS_BASE); - secAlias = qemuAliasForSecret(QEMU_MIGRATION_TLS_ALIAS_BASE, NULL); + secAlias = qemuAliasForSecret(QEMU_MIGRATION_TLS_ALIAS_BASE, NULL, 0); qemuDomainDelTLSObjects(vm, asyncJob, secAlias, tlsAlias); g_clear_pointer(&QEMU_DOMAIN_PRIVATE(vm)->migSecinfo, qemuDomainSecretInfoFree); -- 2.25.1

This commit changes the qemuBlockStorageSourceAttachData struct to support multiple secrets (instead of a single one before this commit). This will useful for storage encryption requiring more than a single secret. Signed-off-by: Or Ozeri <oro@il.ibm.com> --- src/qemu/qemu_block.c | 32 +++++++++++++++++++++++--------- src/qemu/qemu_block.h | 5 +++-- src/qemu/qemu_blockjob.c | 6 ++++++ src/qemu/qemu_command.c | 19 +++++++++++++++---- 4 files changed, 47 insertions(+), 15 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 8fcebd8992..9e1ecf68f9 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -1311,6 +1311,7 @@ qemuBlockStorageSourceGetBlockdevStorageSliceProps(virStorageSource *src) void qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachData *data) { + size_t i; if (!data) return; @@ -1320,12 +1321,16 @@ qemuBlockStorageSourceAttachDataFree(qemuBlockStorageSourceAttachData *data) virJSONValueFree(data->prmgrProps); virJSONValueFree(data->authsecretProps); virJSONValueFree(data->httpcookiesecretProps); - virJSONValueFree(data->encryptsecretProps); + for (i = 0; i < data->encryptsecretCount; ++i) { + virJSONValueFree(data->encryptsecretProps[i]); + g_free(data->encryptsecretAlias[i]); + } virJSONValueFree(data->tlsProps); virJSONValueFree(data->tlsKeySecretProps); g_free(data->tlsAlias); g_free(data->tlsKeySecretAlias); g_free(data->authsecretAlias); + g_free(data->encryptsecretProps); g_free(data->encryptsecretAlias); g_free(data->httpcookiesecretAlias); g_free(data->driveCmd); @@ -1436,10 +1441,12 @@ static int qemuBlockStorageSourceAttachApplyFormatDeps(qemuMonitor *mon, qemuBlockStorageSourceAttachData *data) { - if (data->encryptsecretProps && - qemuMonitorAddObject(mon, &data->encryptsecretProps, - &data->encryptsecretAlias) < 0) - return -1; + size_t i; + for (i = 0; i < data->encryptsecretCount; ++i) { + if (qemuMonitorAddObject(mon, &data->encryptsecretProps[i], + &data->encryptsecretAlias[i]) < 0) + return -1; + } return 0; } @@ -1525,6 +1532,7 @@ qemuBlockStorageSourceAttachRollback(qemuMonitor *mon, qemuBlockStorageSourceAttachData *data) { virErrorPtr orig_err; + size_t i; virErrorPreserveLast(&orig_err); @@ -1550,8 +1558,10 @@ qemuBlockStorageSourceAttachRollback(qemuMonitor *mon, if (data->authsecretAlias) ignore_value(qemuMonitorDelObject(mon, data->authsecretAlias, false)); - if (data->encryptsecretAlias) - ignore_value(qemuMonitorDelObject(mon, data->encryptsecretAlias, false)); + for (i = 0; i < data->encryptsecretCount; ++i) { + if (data->encryptsecretAlias[i]) + ignore_value(qemuMonitorDelObject(mon, data->encryptsecretAlias[i], false)); + } if (data->httpcookiesecretAlias) ignore_value(qemuMonitorDelObject(mon, data->httpcookiesecretAlias, false)); @@ -1606,8 +1616,12 @@ qemuBlockStorageSourceDetachPrepare(virStorageSource *src) if (srcpriv->secinfo) data->authsecretAlias = g_strdup(srcpriv->secinfo->alias); - if (srcpriv->encinfo) - data->encryptsecretAlias = g_strdup(srcpriv->encinfo->alias); + if (srcpriv->encinfo) { + data->encryptsecretCount = 1; + data->encryptsecretProps = g_new0(virJSONValue *, 1); + data->encryptsecretAlias = g_new0(char *, 1); + data->encryptsecretAlias[0] = g_strdup(srcpriv->encinfo->alias); + } if (srcpriv->httpcookie) data->httpcookiesecretAlias = g_strdup(srcpriv->httpcookie->alias); diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index 5a61a19da2..530d88d28e 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -89,8 +89,9 @@ struct qemuBlockStorageSourceAttachData { virJSONValue *authsecretProps; char *authsecretAlias; - virJSONValue *encryptsecretProps; - char *encryptsecretAlias; + size_t encryptsecretCount; + virJSONValue **encryptsecretProps; + char **encryptsecretAlias; virJSONValue *httpcookiesecretProps; char *httpcookiesecretAlias; diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index a20cf1db62..818e90022c 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -1336,9 +1336,15 @@ qemuBlockJobProcessEventConcludedCreate(virQEMUDriver *driver, /* the format node part was not attached yet, so we don't need to detach it */ backend->formatAttached = false; if (job->data.create.storage) { + size_t i; + backend->storageAttached = false; backend->storageSliceAttached = false; + for (i = 0; i < backend->encryptsecretCount; ++i) { + VIR_FREE(backend->encryptsecretAlias[i]); + } VIR_FREE(backend->encryptsecretAlias); + VIR_FREE(backend->encryptsecretProps); } if (qemuDomainObjEnterMonitorAsync(vm, asyncJob) < 0) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 929bcc0be1..f166e1c891 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2108,15 +2108,21 @@ qemuBuildBlockStorageSourceAttachDataCommandline(virCommand *cmd, virQEMUCaps *qemuCaps) { char *tmp; + size_t i; if (qemuBuildObjectCommandline(cmd, data->prmgrProps, qemuCaps) < 0 || qemuBuildObjectCommandline(cmd, data->authsecretProps, qemuCaps) < 0 || - qemuBuildObjectCommandline(cmd, data->encryptsecretProps, qemuCaps) < 0 || qemuBuildObjectCommandline(cmd, data->httpcookiesecretProps, qemuCaps) < 0 || qemuBuildObjectCommandline(cmd, data->tlsKeySecretProps, qemuCaps) < 0 || qemuBuildObjectCommandline(cmd, data->tlsProps, qemuCaps) < 0) return -1; + for (i = 0; i < data->encryptsecretCount; ++i) { + if (qemuBuildObjectCommandline(cmd, data->encryptsecretProps[i], qemuCaps) < 0) { + return -1; + } + } + if (data->driveCmd) virCommandAddArgList(cmd, "-drive", data->driveCmd, NULL); @@ -10739,9 +10745,14 @@ qemuBuildStorageSourceAttachPrepareCommon(virStorageSource *src, qemuBuildSecretInfoProps(srcpriv->secinfo, &data->authsecretProps) < 0) return -1; - if (srcpriv->encinfo && - qemuBuildSecretInfoProps(srcpriv->encinfo, &data->encryptsecretProps) < 0) - return -1; + if (srcpriv->encinfo) { + data->encryptsecretCount = 1; + data->encryptsecretProps = g_new0(virJSONValue *, 1); + data->encryptsecretAlias = g_new0(char *, 1); + + if (qemuBuildSecretInfoProps(srcpriv->encinfo, &data->encryptsecretProps[0]) < 0) + return -1; + } if (srcpriv->httpcookie && qemuBuildSecretInfoProps(srcpriv->httpcookie, &data->httpcookiesecretProps) < 0) -- 2.25.1

This commit changes the _qemuDomainStorageSourcePrivate struct to support multiple secrets (instead of a single one before this commit). This will useful for storage encryption requiring more than a single secret. Signed-off-by: Or Ozeri <oro@il.ibm.com> --- src/qemu/qemu_block.c | 25 +++++--- src/qemu/qemu_command.c | 20 +++--- src/qemu/qemu_domain.c | 75 ++++++++++++++++++----- src/qemu/qemu_domain.h | 3 +- tests/qemublocktest.c | 7 ++- tests/qemustatusxml2xmldata/modern-in.xml | 14 +++++ 6 files changed, 108 insertions(+), 36 deletions(-) diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 9e1ecf68f9..0cc3b82cca 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -582,7 +582,7 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, if (virJSONValueObjectAdd(&encrypt, "s:format", encformat, - "s:key-secret", srcPriv->encinfo->alias, + "s:key-secret", srcPriv->encinfo[0]->alias, NULL) < 0) return NULL; } @@ -979,7 +979,8 @@ qemuBlockStorageSourceGetFormatLUKSProps(virStorageSource *src, { qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src); - if (!srcPriv || !srcPriv->encinfo || !srcPriv->encinfo->alias) { + /* validation ensures that the qemu encryption engine accepts only a single secret */ + if (!srcPriv || !srcPriv->encinfo || !srcPriv->encinfo[0]->alias) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing secret info for 'luks' driver")); return -1; @@ -987,7 +988,7 @@ qemuBlockStorageSourceGetFormatLUKSProps(virStorageSource *src, if (virJSONValueObjectAdd(&props, "s:driver", "luks", - "s:key-secret", srcPriv->encinfo->alias, + "s:key-secret", srcPriv->encinfo[0]->alias, NULL) < 0) return -1; @@ -1053,9 +1054,10 @@ qemuBlockStorageSourceGetCryptoProps(virStorageSource *src, return -1; } + /* validation ensures that the qemu encryption engine accepts only a single secret */ return virJSONValueObjectAdd(encprops, "s:format", encformat, - "s:key-secret", srcpriv->encinfo->alias, + "s:key-secret", srcpriv->encinfo[0]->alias, NULL); } @@ -1617,10 +1619,15 @@ qemuBlockStorageSourceDetachPrepare(virStorageSource *src) data->authsecretAlias = g_strdup(srcpriv->secinfo->alias); if (srcpriv->encinfo) { - data->encryptsecretCount = 1; - data->encryptsecretProps = g_new0(virJSONValue *, 1); - data->encryptsecretAlias = g_new0(char *, 1); - data->encryptsecretAlias[0] = g_strdup(srcpriv->encinfo->alias); + size_t i; + + data->encryptsecretCount = srcpriv->enccount; + data->encryptsecretProps = g_new0(virJSONValue *, srcpriv->enccount); + data->encryptsecretAlias = g_new0(char *, srcpriv->enccount); + + for (i = 0; i < srcpriv->enccount; ++i) { + data->encryptsecretAlias[i] = g_strdup(srcpriv->encinfo[i]->alias); + } } if (srcpriv->httpcookie) @@ -1986,7 +1993,7 @@ qemuBlockStorageSourceCreateGetEncryptionLUKS(virStorageSource *src, if (srcpriv && srcpriv->encinfo) - keysecret = srcpriv->encinfo->alias; + keysecret = srcpriv->encinfo[0]->alias; if (virJSONValueObjectAdd(&props, "s:key-secret", keysecret, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index f166e1c891..7c577ae6ca 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1603,7 +1603,7 @@ qemuBuildDriveSourceStr(virDomainDiskDef *disk, { virStorageType actualType = virStorageSourceGetActualType(disk->src); qemuDomainStorageSourcePrivate *srcpriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(disk->src); - qemuDomainSecretInfo *encinfo = NULL; + qemuDomainSecretInfo **encinfo = NULL; g_autoptr(virJSONValue) srcprops = NULL; bool rawluks = false; @@ -1647,12 +1647,12 @@ qemuBuildDriveSourceStr(virDomainDiskDef *disk, if (encinfo) { if (disk->src->format == VIR_STORAGE_FILE_RAW) { - virBufferAsprintf(buf, "key-secret=%s,", encinfo->alias); + virBufferAsprintf(buf, "key-secret=%s,", encinfo[0]->alias); rawluks = true; } else if (disk->src->format == VIR_STORAGE_FILE_QCOW2 && disk->src->encryption->format == VIR_STORAGE_ENCRYPTION_FORMAT_LUKS) { virBufferAddLit(buf, "encrypt.format=luks,"); - virBufferAsprintf(buf, "encrypt.key-secret=%s,", encinfo->alias); + virBufferAsprintf(buf, "encrypt.key-secret=%s,", encinfo[0]->alias); } } @@ -10746,12 +10746,16 @@ qemuBuildStorageSourceAttachPrepareCommon(virStorageSource *src, return -1; if (srcpriv->encinfo) { - data->encryptsecretCount = 1; - data->encryptsecretProps = g_new0(virJSONValue *, 1); - data->encryptsecretAlias = g_new0(char *, 1); + size_t i; - if (qemuBuildSecretInfoProps(srcpriv->encinfo, &data->encryptsecretProps[0]) < 0) - return -1; + data->encryptsecretCount = srcpriv->enccount; + data->encryptsecretProps = g_new0(virJSONValue *, srcpriv->enccount); + data->encryptsecretAlias = g_new0(char *, srcpriv->enccount); + + for (i = 0; i < srcpriv->enccount; ++i) { + if (qemuBuildSecretInfoProps(srcpriv->encinfo[i], &data->encryptsecretProps[i]) < 0) + return -1; + } } if (srcpriv->httpcookie && diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index f62fb453a9..638788c614 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -872,7 +872,13 @@ qemuDomainStorageSourcePrivateDispose(void *obj) qemuDomainStorageSourcePrivate *priv = obj; g_clear_pointer(&priv->secinfo, qemuDomainSecretInfoFree); - g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree); + if (priv->encinfo) { + size_t i; + for (i = 0; i < priv->enccount; ++i) { + g_clear_pointer(&priv->encinfo[i], qemuDomainSecretInfoFree); + } + VIR_FREE(priv->encinfo); + } g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree); g_clear_pointer(&priv->tlsKeySecret, qemuDomainSecretInfoFree); g_clear_pointer(&priv->fdpass, qemuFDPassFree); @@ -1401,7 +1407,13 @@ qemuDomainSecretDiskDestroy(virDomainDiskDef *disk) for (n = disk->src; virStorageSourceIsBacking(n); n = n->backingStore) { if ((srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(n))) { qemuDomainSecretInfoDestroy(srcPriv->secinfo); - qemuDomainSecretInfoDestroy(srcPriv->encinfo); + if (srcPriv->encinfo) { + size_t i; + + for (i = 0; i < srcPriv->enccount; ++i) { + qemuDomainSecretInfoDestroy(srcPriv->encinfo[i]); + } + } qemuDomainSecretInfoDestroy(srcPriv->tlsKeySecret); } } @@ -1470,12 +1482,19 @@ qemuDomainSecretStorageSourcePrepare(qemuDomainObjPrivate *priv, } if (hasEnc) { - if (!(srcPriv->encinfo = qemuDomainSecretInfoSetupFromSecret(priv, aliasformat, - "encryption", 0, - VIR_SECRET_USAGE_TYPE_VOLUME, - NULL, - &src->encryption->secrets[0]->seclookupdef))) - return -1; + size_t nsecrets = src->encryption->nsecrets; + size_t i; + + srcPriv->enccount = nsecrets; + srcPriv->encinfo = g_new0(qemuDomainSecretInfo *, nsecrets); + for (i = 0; i < nsecrets; ++i) { + if (!(srcPriv->encinfo[i] = qemuDomainSecretInfoSetupFromSecret(priv, aliasformat, + "encryption", i, + VIR_SECRET_USAGE_TYPE_VOLUME, + NULL, + &src->encryption->secrets[i]->seclookupdef))) + return -1; + } } if (src->ncookies && @@ -1964,13 +1983,14 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, virStorageSource *src) { qemuDomainStorageSourcePrivate *priv; + g_autofree xmlNodePtr *encnodes = NULL; g_autofree char *authalias = NULL; - g_autofree char *encalias = NULL; g_autofree char *httpcookiealias = NULL; g_autofree char *tlskeyalias = NULL; g_autofree char *thresholdEventWithIndex = NULL; bool fdsetPresent = false; unsigned int fdSetID; + int enccount; src->nodestorage = virXPathString("string(./nodenames/nodename[@type='storage']/@name)", ctxt); src->nodeformat = virXPathString("string(./nodenames/nodename[@type='format']/@name)", ctxt); @@ -1983,13 +2003,14 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, src->pr->mgralias = virXPathString("string(./reservations/@mgralias)", ctxt); authalias = virXPathString("string(./objects/secret[@type='auth']/@alias)", ctxt); - encalias = virXPathString("string(./objects/secret[@type='encryption']/@alias)", ctxt); + if ((enccount = virXPathNodeSet("./objects/secret[@type='encryption']", ctxt, &encnodes)) < 0) + return -1; httpcookiealias = virXPathString("string(./objects/secret[@type='httpcookie']/@alias)", ctxt); tlskeyalias = virXPathString("string(./objects/secret[@type='tlskey']/@alias)", ctxt); fdsetPresent = virXPathUInt("string(./fdsets/fdset[@type='storage']/@id)", ctxt, &fdSetID) == 0; - if (authalias || encalias || httpcookiealias || tlskeyalias || fdsetPresent) { + if (authalias || (enccount > 0) || httpcookiealias || tlskeyalias || fdsetPresent) { if (!src->privateData && !(src->privateData = qemuDomainStorageSourcePrivateNew())) return -1; @@ -1999,8 +2020,24 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->secinfo, &authalias) < 0) return -1; - if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo, &encalias) < 0) - return -1; + if (enccount > 0) { + size_t i; + + priv->enccount = enccount; + priv->encinfo = g_new0(qemuDomainSecretInfo *, enccount); + for (i = 0; i < enccount; ++i) { + g_autofree char *encalias = NULL; + + if (!(encalias = virXMLPropString(encnodes[i], "alias"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("missing alias on encryption secret #%lu"), i); + return -1; + } + + if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo[i], &encalias) < 0) + return -1; + } + } if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->httpcookie, &httpcookiealias) < 0) return -1; @@ -2061,10 +2098,13 @@ qemuStorageSourcePrivateDataFormat(virStorageSource *src, return -1; if (srcPriv) { + size_t i; unsigned int fdSetID; qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->secinfo, "auth"); - qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->encinfo, "encryption"); + for (i = 0; i < srcPriv->enccount; ++i) { + qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->encinfo[i], "encryption"); + } qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->httpcookie, "httpcookie"); qemuStorageSourcePrivateDataFormatSecinfo(&objectsChildBuf, srcPriv->tlsKeySecret, "tlskey"); @@ -5639,9 +5679,14 @@ qemuDomainDeviceDiskDefPostParseRestoreSecAlias(virDomainDiskDef *disk, } if (restoreEncSecret) { + if (!priv->encinfo) { + priv->enccount = 1; + priv->encinfo = g_new0(qemuDomainSecretInfo *, 1); + } + encalias = g_strdup_printf("%s-luks-secret0", disk->info.alias); - if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo, &encalias) < 0) + if (qemuStorageSourcePrivateDataAssignSecinfo(&priv->encinfo[0], &encalias) < 0) return -1; } diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index 9bcc5e1380..5928828f3b 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -296,7 +296,8 @@ struct _qemuDomainStorageSourcePrivate { qemuDomainSecretInfo *secinfo; /* data required for decryption of encrypted storage source */ - qemuDomainSecretInfo *encinfo; + size_t enccount; + qemuDomainSecretInfo **encinfo; /* secure passthrough of the http cookie */ qemuDomainSecretInfo *httpcookie; diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index 010b52f4b3..2d790e2b2e 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -237,10 +237,11 @@ testQemuDiskXMLToJSONFakeSecrets(virStorageSource *src) } if (src->encryption) { - srcpriv->encinfo = g_new0(qemuDomainSecretInfo, 1); + srcpriv->encinfo = g_new0(qemuDomainSecretInfo *, 1); + srcpriv->encinfo[0] = g_new0(qemuDomainSecretInfo, 1); - srcpriv->encinfo->alias = g_strdup_printf("%s-encalias", - NULLSTR(src->nodeformat)); + srcpriv->encinfo[0]->alias = g_strdup_printf("%s-encalias", + NULLSTR(src->nodeformat)); } return 0; diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxml2xmldata/modern-in.xml index cdab1d7178..95fc569029 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -360,6 +360,20 @@ </privateData> <diskSecretsPlacement auth='true'/> </disk> + <disk type='network' device='disk'> + <driver name='qemu' type='raw'/> + <source protocol='rbd' name='pool/image' tlsFromConfig='0'> + <host name='example.org'/> + <privateData> + <objects> + <secret type='encryption' alias='test-encryption-alias'/> + <secret type='encryption' alias='test-encryption-alias2'/> + </objects> + </privateData> + </source> + <target dev='vdc' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </disk> <disk type='file' device='cdrom'> <driver name='qemu' type='raw'/> <source file='/var/lib/libvirt/images/systemrescuecd-x86-4.9.5.iso'/> -- 2.25.1

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 <oro@il.ibm.com> --- 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 ``<secret type='passphrase'...>`` 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 -``<secret type='passphrase'...>`` element is expected. +``<secret type='passphrase'...>`` 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 @@ </optional> <optional> <interleave> - <ref name="secret"/> + <oneOrMore> + <ref name="secret"/> + </oneOrMore> <optional> <interleave> <element name="cipher"> 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 638788c614..726d0ab0a1 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 0146220d8f..345e3eef45 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -3351,6 +3351,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 @@ +<domain type='qemu'> + <name>encryptdisk</name> + <uuid>496898a6-e6ff-f7c8-5dc2-3cf410945ee9</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-i440fx-2.1'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='network' device='disk'> + <driver name='qemu' type='raw'/> + <source protocol='rbd' name='pool/image'> + <host name='mon1.example.org' port='6321'/> + <host name='mon2.example.org' port='6322'/> + <host name='mon3.example.org' port='6322'/> + <encryption format='luks' engine='librbd'> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80fb0'/> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f'/> + <secret type='passphrase' uuid='f52a81b2-424e-490c-823d-6bd4235bc572'/> + </encryption> + </source> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index c879fa90e0..94e88f7eab 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1247,6 +1247,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 @@ +<domain type='qemu'> + <name>encryptdisk</name> + <uuid>496898a6-e6ff-f7c8-5dc2-3cf410945ee9</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-i440fx-2.1'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='network' device='disk'> + <driver name='qemu' type='raw'/> + <source protocol='rbd' name='pool/image'> + <host name='mon1.example.org' port='6321'/> + <host name='mon2.example.org' port='6322'/> + <host name='mon3.example.org' port='6322'/> + <encryption format='luks' engine='librbd'> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80fb0'/> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80d6f'/> + <secret type='passphrase' uuid='f52a81b2-424e-490c-823d-6bd4235bc572'/> + </encryption> + </source> + <target dev='vda' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </disk> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index a1be43ab34..1e62fbdd19 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -325,6 +325,7 @@ mymain(void) DO_TEST_NOCAPS("disk-network-gluster"); DO_TEST_NOCAPS("disk-network-rbd"); DO_TEST_CAPS_LATEST("disk-network-rbd-encryption"); + DO_TEST_CAPS_LATEST("disk-network-rbd-encryption-layering"); DO_TEST_NOCAPS("disk-network-source-auth"); DO_TEST_NOCAPS("disk-network-sheepdog"); DO_TEST_NOCAPS("disk-network-vxhs"); -- 2.25.1

This capability represents that qemu supports the "luks-any" encryption format for RBD images. Both LUKS and LUKS2 formats can be parsed using this wildcard format. Signed-off-by: Or Ozeri <oro@il.ibm.com> --- src/qemu/qemu_capabilities.c | 2 ++ src/qemu/qemu_capabilities.h | 1 + tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml | 1 + 3 files changed, 4 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index c03ad714fa..22b0d2ca86 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -692,6 +692,7 @@ VIR_ENUM_IMPL(virQEMUCaps, "netdev.stream.reconnect", /* QEMU_CAPS_NETDEV_STREAM_RECONNECT */ "virtio-gpu.blob", /* QEMU_CAPS_VIRTIO_GPU_BLOB */ "rbd-encryption-layering", /* QEMU_CAPS_RBD_ENCRYPTION_LAYERING */ + "rbd-encryption-luks-any", /* QEMU_CAPS_RBD_ENCRYPTION_LUKS_ANY */ ); @@ -1558,6 +1559,7 @@ static struct virQEMUCapsStringFlags virQEMUCapsQMPSchemaQueries[] = { { "blockdev-add/arg-type/+file/aio/^io_uring", QEMU_CAPS_AIO_IO_URING }, { "blockdev-add/arg-type/+rbd/encrypt", QEMU_CAPS_RBD_ENCRYPTION }, { "blockdev-add/arg-type/+rbd/encrypt/parent", QEMU_CAPS_RBD_ENCRYPTION_LAYERING }, + { "blockdev-add/arg-type/+rbd/encrypt/format/^luks-any", QEMU_CAPS_RBD_ENCRYPTION_LUKS_ANY }, { "blockdev-add/arg-type/+nbd/tls-hostname", QEMU_CAPS_BLOCKDEV_NBD_TLS_HOSTNAME }, { "blockdev-snapshot/$allow-write-only-overlay", QEMU_CAPS_BLOCKDEV_SNAPSHOT_ALLOW_WRITE_ONLY }, { "chardev-add/arg-type/backend/+socket/data/reconnect", QEMU_CAPS_CHARDEV_RECONNECT }, diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index 2d2c5f8eaf..c4f1708639 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -671,6 +671,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */ QEMU_CAPS_NETDEV_STREAM_RECONNECT, /* -netdev stream supports reconnect */ QEMU_CAPS_VIRTIO_GPU_BLOB, /* -device virtio-gpu-*.blob= */ QEMU_CAPS_RBD_ENCRYPTION_LAYERING, /* layered encryption support for Ceph RBD */ + QEMU_CAPS_RBD_ENCRYPTION_LUKS_ANY, /* luks-any (LUKS and LUKS2) encryption format for Ceph RBD */ QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml b/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml index d120f5dc3c..74128be904 100644 --- a/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml +++ b/tests/qemucapabilitiesdata/caps_8.0.0.x86_64.xml @@ -205,6 +205,7 @@ <flag name='netdev.stream.reconnect'/> <flag name='virtio-gpu.blob'/> <flag name='rbd-encryption-layering'/> + <flag name='rbd-encryption-luks-any'/> <version>7002050</version> <kvmVersion>0</kvmVersion> <microcodeVersion>43100244</microcodeVersion> -- 2.25.1

The newly added luks-any rbd encryption format in qemu allows for opening both LUKS and LUKS2 encryption formats. This commit enables libvirt uses to use this wildcard format. Signed-off-by: Or Ozeri <oro@il.ibm.com> --- docs/formatstorageencryption.rst | 9 ++++ src/conf/schemas/storagecommon.rng | 1 + src/conf/storage_encryption_conf.c | 2 +- src/conf/storage_encryption_conf.h | 1 + src/libvirt_private.syms | 1 + src/qemu/qemu_block.c | 10 +++-- src/qemu/qemu_domain.c | 29 +++++++++++- ...k-rbd-encryption-luks-any.x86_64-7.2.0.err | 1 + ...rbd-encryption-luks-any.x86_64-latest.args | 37 ++++++++++++++++ .../disk-network-rbd-encryption-luks-any.xml | 39 ++++++++++++++++ tests/qemuxml2argvtest.c | 2 + ...-rbd-encryption-luks-any.x86_64-latest.xml | 44 +++++++++++++++++++ tests/qemuxml2xmltest.c | 1 + 13 files changed, 170 insertions(+), 7 deletions(-) create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-7.2.0.err create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-latest.args create mode 100644 tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.xml create mode 100644 tests/qemuxml2xmloutdata/disk-network-rbd-encryption-luks-any.x86_64-latest.xml diff --git a/docs/formatstorageencryption.rst b/docs/formatstorageencryption.rst index 3b3e9ea379..071ea8f4d1 100644 --- a/docs/formatstorageencryption.rst +++ b/docs/formatstorageencryption.rst @@ -109,6 +109,15 @@ to a qemu VM using the qemu VM driver. A single ``<secret type='passphrase'...>`` element is expected (except for the case of RBD layered encryption mentioned above). +``luks-any`` format +~~~~~~~~~~~~~~~~~~~ + +The ``luks-any`` format is currently supported only by the ``librbd`` engine, +and can only be applied to RBD network disks (RBD images). This format will try +to parse the disk as either LUKS or LUKS2, depending on the actual on-disk +format. A single ``<secret type='passphrase'...>`` element is expected (except +for the case of RBD layered encryption mentioned above) :since:`Since 9.3.0` . + Examples -------- diff --git a/src/conf/schemas/storagecommon.rng b/src/conf/schemas/storagecommon.rng index 225456f03c..14704c737e 100644 --- a/src/conf/schemas/storagecommon.rng +++ b/src/conf/schemas/storagecommon.rng @@ -14,6 +14,7 @@ <value>qcow</value> <value>luks</value> <value>luks2</value> + <value>luks-any</value> </choice> </attribute> <optional> diff --git a/src/conf/storage_encryption_conf.c b/src/conf/storage_encryption_conf.c index 3651ff8cfd..639cbf2e58 100644 --- a/src/conf/storage_encryption_conf.c +++ b/src/conf/storage_encryption_conf.c @@ -41,7 +41,7 @@ VIR_ENUM_IMPL(virStorageEncryptionSecret, VIR_ENUM_IMPL(virStorageEncryptionFormat, VIR_STORAGE_ENCRYPTION_FORMAT_LAST, - "default", "qcow", "luks", "luks2", + "default", "qcow", "luks", "luks2", "luks-any", ); VIR_ENUM_IMPL(virStorageEncryptionEngine, diff --git a/src/conf/storage_encryption_conf.h b/src/conf/storage_encryption_conf.h index 312599ad44..03f0e60feb 100644 --- a/src/conf/storage_encryption_conf.h +++ b/src/conf/storage_encryption_conf.h @@ -66,6 +66,7 @@ typedef enum { VIR_STORAGE_ENCRYPTION_FORMAT_QCOW, /* Both qcow and qcow2 */ VIR_STORAGE_ENCRYPTION_FORMAT_LUKS, VIR_STORAGE_ENCRYPTION_FORMAT_LUKS2, + VIR_STORAGE_ENCRYPTION_FORMAT_LUKS_ANY, VIR_STORAGE_ENCRYPTION_FORMAT_LAST, } virStorageEncryptionFormatType; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 6f44788233..3187112ca3 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1095,6 +1095,7 @@ virStorageVolTypeToString; # conf/storage_encryption_conf.h virStorageEncryptionFormat; +virStorageEncryptionFormatTypeToString; virStorageEncryptionFree; virStorageEncryptionParseNode; diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index d50cfa20c5..3fafc31084 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -575,6 +575,10 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src, encformat = "luks2"; break; + case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS_ANY: + encformat = "luks-any"; + break; + case VIR_STORAGE_ENCRYPTION_FORMAT_QCOW: case VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT: case VIR_STORAGE_ENCRYPTION_FORMAT_LAST: @@ -1052,10 +1056,8 @@ qemuBlockStorageSourceGetCryptoProps(virStorageSource *src, break; case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS2: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("luks2 is currently not supported by the qemu encryption engine")); - return -1; - + case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS_ANY: + /* validation code asserts the above cases are impossible */ case VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT: case VIR_STORAGE_ENCRYPTION_FORMAT_LAST: default: diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 726d0ab0a1..a832e75c3c 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5186,8 +5186,10 @@ qemuDomainValidateStorageSource(virStorageSource *src, break; case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS2: - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("luks2 is currently not supported by the qemu encryption engine")); + case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS_ANY: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("'%s' is currently not supported by the qemu encryption engine"), + virStorageEncryptionFormatTypeToString(src->encryption->format)); return -1; case VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT: @@ -5227,6 +5229,29 @@ qemuDomainValidateStorageSource(virStorageSource *src, return -1; } } + + switch ((virStorageEncryptionFormatType) src->encryption->format) { + case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS: + case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS2: + break; + + case VIR_STORAGE_ENCRYPTION_FORMAT_LUKS_ANY: + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_RBD_ENCRYPTION_LUKS_ANY)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("luks-any encryption is not supported by this QEMU binary")); + return -1; + } + break; + + case VIR_STORAGE_ENCRYPTION_FORMAT_QCOW: + /* validation code above already asserts this case is impossible */ + case VIR_STORAGE_ENCRYPTION_FORMAT_DEFAULT: + case VIR_STORAGE_ENCRYPTION_FORMAT_LAST: + default: + virReportEnumRangeError(virStorageEncryptionFormatType, + src->encryption->format); + return -1; + } break; case VIR_STORAGE_ENCRYPTION_ENGINE_DEFAULT: diff --git a/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-7.2.0.err b/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-7.2.0.err new file mode 100644 index 0000000000..66b2a65ac1 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-7.2.0.err @@ -0,0 +1 @@ +unsupported configuration: luks-any encryption is not supported by this QEMU binary diff --git a/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-latest.args b/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-latest.args new file mode 100644 index 0000000000..5dedfc5f6b --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.x86_64-latest.args @@ -0,0 +1,37 @@ +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"}' \ +-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-any","key-secret":"libvirt-1-format-encryption-secret0"},"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-luks-any.xml b/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.xml new file mode 100644 index 0000000000..37d9900e74 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-luks-any.xml @@ -0,0 +1,39 @@ +<domain type='qemu'> + <name>encryptdisk</name> + <uuid>496898a6-e6ff-f7c8-5dc2-3cf410945ee9</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-i440fx-2.1'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='network' device='disk'> + <driver name='qemu' type='raw'/> + <source protocol='rbd' name='pool/image'> + <host name='mon1.example.org' port='6321'/> + <host name='mon2.example.org' port='6322'/> + <host name='mon3.example.org' port='6322'/> + <encryption format='luks-any' engine='librbd'> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80fb0'/> + </encryption> + </source> + <target dev='vda' bus='virtio'/> + </disk> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 94e88f7eab..7bc2a134a7 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1249,6 +1249,8 @@ mymain(void) 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_VER_PARSE_ERROR("disk-network-rbd-encryption-luks-any", "7.2.0"); + DO_TEST_CAPS_LATEST("disk-network-rbd-encryption-luks-any"); 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-luks-any.x86_64-latest.xml b/tests/qemuxml2xmloutdata/disk-network-rbd-encryption-luks-any.x86_64-latest.xml new file mode 100644 index 0000000000..d9f4ad17d9 --- /dev/null +++ b/tests/qemuxml2xmloutdata/disk-network-rbd-encryption-luks-any.x86_64-latest.xml @@ -0,0 +1,44 @@ +<domain type='qemu'> + <name>encryptdisk</name> + <uuid>496898a6-e6ff-f7c8-5dc2-3cf410945ee9</uuid> + <memory unit='KiB'>1048576</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64' machine='pc-i440fx-2.1'>hvm</type> + <boot dev='hd'/> + </os> + <cpu mode='custom' match='exact' check='none'> + <model fallback='forbid'>qemu64</model> + </cpu> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <disk type='network' device='disk'> + <driver name='qemu' type='raw'/> + <source protocol='rbd' name='pool/image'> + <host name='mon1.example.org' port='6321'/> + <host name='mon2.example.org' port='6322'/> + <host name='mon3.example.org' port='6322'/> + <encryption format='luks-any' engine='librbd'> + <secret type='passphrase' uuid='0a81f5b2-8403-7b23-c8d6-21ccc2f80fb0'/> + </encryption> + </source> + <target dev='vda' bus='virtio'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </disk> + <controller type='usb' index='0' model='piix3-uhci'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <audio id='1' type='none'/> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 1e62fbdd19..3d4c038c70 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -326,6 +326,7 @@ mymain(void) DO_TEST_NOCAPS("disk-network-rbd"); DO_TEST_CAPS_LATEST("disk-network-rbd-encryption"); DO_TEST_CAPS_LATEST("disk-network-rbd-encryption-layering"); + DO_TEST_CAPS_LATEST("disk-network-rbd-encryption-luks-any"); DO_TEST_NOCAPS("disk-network-source-auth"); DO_TEST_NOCAPS("disk-network-sheepdog"); DO_TEST_NOCAPS("disk-network-vxhs"); -- 2.25.1

On Mon, Mar 13, 2023 at 04:50:16 -0500, Or Ozeri wrote:
v2: - add luks-any commits (including nit fixes) - removed qemu 8.0.0 replies commit - remove tautological if condition in qemuBlockStorageSourceAttachData initialization - add comments on validation of a single secret in qemu encryption engine - fix leak of qemuDomainStorageSourcePrivate->encinfo - remove ctxt->node modification in privatedata xml parsing - add test to modern-in.xml - squash commit #6 - add validation for a single secret in sd card disk
Or Ozeri (7): qemu: capabilities: Introduce QEMU_CAPS_RBD_ENCRYPTION_LAYERING capability qemu: add support for multiple secret aliases qemu: add multi-secret support in qemuBlockStorageSourceAttachData qemu: add multi-secret support in _qemuDomainStorageSourcePrivate qemu: add support for librbd layered encryption qemu: capabilities: Introduce QEMU_CAPS_RBD_ENCRYPTION_LUKS_ANY capability qemu: add luks-any encryption support for RBD images
Series: Reviewed-by: Peter Krempa <pkrempa@redhat.com> and pushed.
participants (2)
-
Or Ozeri
-
Peter Krempa