Re: [PATCH v1 7/7] qemu: add support for librbd layered encryption

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Mar 06, 2023 at 06:53:12 -0600, Or Ozeri wrote:
> 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@xxxxxxxxxx>
> ---
>  docs/formatstorageencryption.rst              | 11 +++--
>  src/conf/schemas/storagecommon.rng            |  4 +-
>  src/qemu/qemu_block.c                         | 23 +++++++---
>  src/qemu/qemu_domain.c                        | 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  | 40 +++++++++++++++++
>  tests/qemuxml2argvtest.c                      |  2 +
>  ...-rbd-encryption-layering.x86_64-latest.xml | 45 +++++++++++++++++++
>  tests/qemuxml2xmltest.c                       |  1 +
>  10 files changed, 169 insertions(+), 11 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/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
> index f6d21d2040..e0f355874f 100644
> --- a/src/qemu/qemu_block.c
> +++ b/src/qemu/qemu_block.c
> @@ -543,7 +543,8 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src,
>      qemuDomainStorageSourcePrivate *srcPriv = QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src);
>      g_autoptr(virJSONValue) servers = NULL;
>      virJSONValue *ret = NULL;
> -    g_autoptr(virJSONValue) encrypt = NULL;
> +    g_autolist(virJSONValue) encrypts = NULL;
> +    virJSONValue *null_encrypt = NULL;
>      const char *encformat = NULL;
>      const char *username = NULL;
>      g_autoptr(virJSONValue) authmodes = NULL;

[...]

> @@ -579,11 +582,17 @@ 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) {
> +            virJSONValue *encrypt = NULL;
> +            if (virJSONValueObjectAdd(&encrypt,
> +                                      "s:format", encformat,
> +                                      "s:key-secret", srcPriv->encinfo[i-1]->alias,
> +                                      "A:parent", encrypts ? (virJSONValue **)&encrypts->data : &null_encrypt,
> +                                      NULL) < 0)
> +                return NULL;
> +
> +            encrypts = g_list_prepend(encrypts, encrypt);
> +        }
>      }
>  
>      if (virJSONValueObjectAdd(&ret,
> @@ -592,7 +601,7 @@ qemuBlockStorageSourceGetRBDProps(virStorageSource *src,
>                                "S:snapshot", src->snapshot,
>                                "S:conf", src->configFile,
>                                "A:server", &servers,
> -                              "A:encrypt", &encrypt,
> +                              "A:encrypt", encrypts ? (virJSONValue **)&encrypts->data : &null_encrypt,
>                                "S:user", username,
>                                "A:auth-client-required", &authmodes,
>                                "S:key-secret", keysecret,


The use of the 'list' makes the code very opaque and confusing.

You declare the list as an automatic list, thus the members will be
freed, but the 'A:' formatter of virJSONValueObjectAdd actually consumes
the pointer. So you basically are creating a list, where each member in
the list is empty except for the top, as it was consumed by
virJSONValueObjectAdd.

That means you don't even need a list and it will make the code also
more clear:

You only need this:

        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);
        }
    }

You can drop all the other hunks in the function. (except for adding
size_t i).



> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index ffe29dc832..e336273588 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c

[...]

> @@ -5210,6 +5216,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;
> +                    }

As noted in previous patch you must here validate that also the disk is
not an SD card.

> +                }
>                  break;
>  
>              case VIR_STORAGE_ENCRYPTION_ENGINE_DEFAULT:

[...]

> 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..cbde665958
> --- /dev/null
> +++ b/tests/qemuxml2argvdata/disk-network-rbd-encryption-layering.xml
> @@ -0,0 +1,40 @@
> +<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'/>

Since the first secret is used for the current image and subsequent ones
for the parents it results in config:

"encrypt":{"format":"luks",
           "key-secret":"libvirt-1-format-encryption-secret0",
           "parent": { "format":"luks",
                       "key-secret":"libvirt-1-format-encryption-secret1" }}

You thus want to use at least 3 secrets to show the multiple layers the
documentation talks about

> +        </encryption>
> +      </source>
> +      <target dev='vda' bus='virtio'/>
> +    </disk>




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux