[Top][All Lists]

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

Re: API definition for LUKS key management

From: Daniel P . Berrangé
Subject: Re: API definition for LUKS key management
Date: Mon, 11 Nov 2019 18:34:24 +0000
User-agent: Mutt/1.12.1 (2019-06-15)

On Mon, Nov 11, 2019 at 05:58:20PM +0200, Maxim Levitsky wrote:
> Hi!
> I would like to discuss the API for LUKS key management.
> First of all very brief overview of LUKS v1 format:
> Each sector of the image is encrypted with same master key, which
> is not stored directly on the disk.
> Instead in the LUKS header we have 8 slots. Each slot optionally stores
> an encrypted version of the master key, encrypted by the user password.
> Knowing the password, you can retrieve the master key from the keyslot.
> Slot can be marked as active or inactive, inactive slots are not considered
> when opening the image.
> In addition to that LUKS header has a hash of the master key, so that
> you can check if the password 'opens' a keyslot by decrypting it
> with given the password, and then checking if 
> the hash of the decrypted master key candidate obtained matches the stored 
> hash.
> That basically means that you can have up to 8 different passwords that will
> open a luks volume and you can change them as you wish without re-encrypting
> everything.
> Now for raw luks volumes you have cryptsetup which allows to manage these
> keyslots, but we also have so called encrypted qcow2 format which
> basically has the luks header, together with keyslots embedded, plus each
> cluster is encrypted with the master key as in raw luks.
> Cryptsetup doesn't support this, thus I implemented this in qemu block layer.

Even for raw luks volumes, the traditional "cryptsetup" tool is
undesirable. eg consider LUKS on an RBD or ISCSI volume where
you are using the in-QEMU RBD/ISCSI client. You don't want to
have to configure the host kernel client just to change the
keyslot info. You don't want to use the in-QEMU clients for

> Link to bugzilla here: https://bugzilla.redhat.com/show_bug.cgi?id=1662412
> Relevant to the API,
> first of all qemu has the notion of amend (qemu-img amend), which allows
> currently to change format specific extensions of qcow2.
> Since luks, especially luks inside qcow2 is a format on its own, it fits to 
> use that interface to change the 'format' options, in this case,
> the encryption key slots.
> There are the following requirements (they are 100% hardcoded, we might 
> discuss
> to drop some of these):
> 1. ability to add a new password to a free keyslot 
> (best is to let api to pick a free keyslot)
> Also user should not need to know all the passwords in existing keyslots.
> 2. ability to erase a keyslot, usually by giving the password that should be 
> erased, and erasing all
> the keyslots that match the password, or by giving a keyslot index.
> This will usually be done after adding a new password.
> 3. Allow to do so online, that is while qemu is running, but also support 
> offline management.
> Note that online management is even useful for raw luks volumes, since its 
> not safe
> to run cryptsetup on them while qemu is using the images.
> I implemented those requirements using the following interface.
> (I have sent the patches already)
> I will try to explain the interface with bunch of examples:
> # adds a new password, defined by qemu secret 'sec0' to first unused slot
> # give user a error if all keyslots are occupied
> qemu-img amend --secret ... -o key-secret=sec1 image.luks

I think you meant "--object secret,...." instead of "--secret ..."

Also, this example needs to have 2 secrets provided. The first
secret to unlock the image using the existing password, and the
second secret is the one being added.

> # erases all keyslots that can be opened by password that is contained in a 
> qemu secret 'sec0'
> # active=off means that the given password/keyslot won't be active after the 
> operation
> qemu-img amend --secret ... -o key-secret=sec0,active=off image.luks
> # erase the slot 5 (this is more low level command, less expected to be used)
> qemu-img amend --secret ... -o slot=5,active=off image.luks
> # add new secret to slot 5 (will fail if the slot is already marked as active)
> qemu-img amend --secret ... -o slot=5,key-secret=sec1 image.luks

This also needs two secrets provideed.

> This is basically it.
> The full option syntax is as following:
> active=on/off (optional, default to on) - toggles if we enabling a keyslot or 
> are erasing it.
> slot=number (optional, advanced option) - specifies which exactly slot to 
> erase or which
> slot to put the new key on
> key-secret = id of the secret object - specifies the secret. when slot is 
> enabled,
> it will be put into the new slot. when disabling (erasing a keyslot), all 
> keyslots
> matching that secret will be erased. 
> Specifying both key-secret and slot index is treated as error I think
> As as very advanced option, --force is added to qemu-img to allow to do 
> unsafe operation,
> which in this case is removing last keyslot which will render the encrypted 
> image useless.
> In addition to that, QMP interface was added for online version of the above.
> It is very similiar, but since we don't have blockdev-amend,
> I added one and it has the following interface:
> ##
> # @x-blockdev-amend:
> #
> # Starts a job to amend format specific options of an existing open block 
> device.
> # The job is automatically finalized, but a manual job-dismiss is required.
> #
> # @job-id:          Identifier for the newly created job.
> #
> # @node-name:       Name of the block node to work on
> #
> # @options:         Options (same as for image creation)
> #
> # @force:           Allow unsafe operations, format specific
> #                   For luks that allows erase of the last active keyslot
> #                   (permanent loss of data),
> #                   and replacement of an active keyslot
> #                   (possible loss of data if IO error happens)
> #
> # Since: 4.2
> ##
> { 'command': 'x-blockdev-amend',
>   'data': { 'job-id': 'str',
>             'node-name': 'str',
>             'options': 'BlockdevCreateOptions',
>             '*force': 'bool' } }
> It takes the same BlockdevCreateOptions as blockdev-create (this is open to 
> debate if to leave this as is)
> BlockdevCreateOptionsLUKS (its parent QCryptoBlockCreateOptionsLUKS 
> technically is extended in this way):
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -190,6 +190,21 @@
>  #                  Currently defaults to 'sha256'
>  # @hash-alg: the master key hash algorithm
>  #            Currently defaults to 'sha256'
> +#
> +# @active: Should the new secret be added (true) or erased (false)
> +#          (amend only, since 4.2)
> +#
> +# @slot: The slot in which to put/erase the secret
> +#        if not given, will select first free slot for secret addtion
> +#        and erase all keyslots that match the given @key-secret for erase.
> +#        except the last one
> +#        (optional, since 4.2)
> +#
> +# @unlock-secret: The secret to use to unlock the image
> +#        If not given, will use the secret that was used
> +#        when opening the image.
> +#        (optional, for amend only, since 4.2)
> +#
>  # @iter-time: number of milliseconds to spend in
>  #             PBKDF passphrase processing. Currently defaults
>  #             to 2000. (since 2.8)
> @@ -201,7 +216,12 @@
>              '*cipher-mode': 'QCryptoCipherMode',
>              '*ivgen-alg': 'QCryptoIVGenAlgorithm',
>              '*ivgen-hash-alg': 'QCryptoHashAlgorithm',
> +
>              '*hash-alg': 'QCryptoHashAlgorithm',
> +            '*active' : 'bool',
> +            '*slot': 'int',
> +            '*unlock-secret': 'str',
> +
>              '*iter-time': 'int'}}
> Here note that key-secret is already present in the in api, and I am adding 
> the 'slot','active' and 'unlock-secret'
> 'slot' can be also used for new created image to specify where to place the 
> the secret.
> 'active' not allowed to be false for blockdev-create of an image and can be 
> true/false for 'blockdev-amend'
> 'unlock-secret' (might be removed later) covers an corner case that is 
> specific for online key management.
> The case is that if the keyslot used to open the image in first place is 
> removed, it can be used to specify
> the password to retrieve the master key from one of existing keyslots, since 
> the driver doesn't officially
> keep the master key all the time (it can be in theory only loaded in hardware 
> crypto device)
> That is why for adding a new keyslot, the secret that was used to open the 
> image is tried first, and if it
> doesn't open a keyslot, the 'unlock-secret' can be used instead. This can be 
> thought of as the 'current password'
> that is need to update the password on many web forums.
> One of the concerns that was raised during the review was that amend 
> interface for luks that I propose is
> different from the amend inteface used currently for qcow2.
> qcow2 amend interface specifies all the format options, thus overwrites the 
> existing options.
> Thus it seems natural to make the luks amend interface work the same way, 
> that it receive an array
> of 8 slots, and for each slot specify if it is active, and if true what 
> password to put in it.
> This does allow to add and erase the keyslots, but it doesn't allow:
>    * add a password without knowing all other passwords that exist in 
> existing keyslots
>      this can be mitigated by specifying which keyslots to modify for example 
> by omitting the
>      keyslots that shouldn't be touched from the array (passing null 
> placeholder instead)
>      but then it already doesn't follow the 'specify all the options each 
> time' principle.

I think this is highly undesirable, as we must not assume that the
mgmt app has access to all the passwords currently set.

The two key use cases for having multiple key slots are

  - To enable a two-phase change of passwords to ensure new password
    is safely written out before erasing the old password
  - To allow for multiple access passwords with different controls
    or access to when each password is made available.

    eg each VM may have a separate "backup password" securely
    stored off host that is only made available for use when
    doing disaster recovery.

the second use case is doomed if you need to always provide all
current passwords when changing any key slots.

>    * erase all keyslots matching a password - this is really hard to do using 
> this approach,
>      unless we give user some kind of api to try each keyslot with given 
> password,
>      which is kind of ugly and might be racy as well.

> So what do you think?

The point of using "amend" is that we already have some of the boilerplate
supporting framework around that, so it saves effort for both QEMU and
our users. If the semantics of "amend" don't fit nicely though, then the
benefit of re-using "amend" is cancelled out and we should go back to
considering a separate "key-manage" command.

|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

reply via email to

[Prev in Thread] Current Thread [Next in Thread]