qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Maxim Levitsky <mlevitsk@redhat.com>
To: "Daniel P. Berrangé" <berrange@redhat.com>
Cc: Kevin Wolf <kwolf@redhat.com>,
	qemu-block@nongnu.org, Markus Armbruster <armbru@redhat.com>,
	qemu-devel@nongnu.org, John Ferlan <jferlan@redhat.com>,
	Max Reitz <mreitz@redhat.com>, John Snow <jsnow@redhat.com>
Subject: Re: API definition for LUKS key management
Date: Thu, 14 Nov 2019 12:37:11 +0200	[thread overview]
Message-ID: <89b580b2da26da8995a90ffd70e8325ba277a20a.camel@redhat.com> (raw)
In-Reply-To: <20191111183424.GR814211@redhat.com>

On Mon, 2019-11-11 at 18:34 +0000, Daniel P. Berrangé wrote:
> 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
> qemu-img.

I didn't thought about it. This is a very good point!

> 
> > 
> > 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 ..."
> 
True, sorry about that!

> 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.
Fully agree, and thanks for these examples!


> 
> 
> >    * 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.

I guess we should anyway use amend interface, while updating its definition
a bit to suit the broader requirements of the drivers, e.g luks.

I see the amend interface being like generic 'edit the device options' thing,
which is maybe better that adding device specific commands like add-key,remove-key,
etc. No strong opinion on this though.


Best regards,
	Maxim Levitsky



  parent reply	other threads:[~2019-11-14 10:38 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-11 15:58 API definition for LUKS key management Maxim Levitsky
2019-11-11 18:34 ` Daniel P. Berrangé
2019-11-12  9:12   ` Kevin Wolf
2019-11-12 10:47     ` Max Reitz
2019-11-12 11:02     ` Daniel P. Berrangé
2019-11-14 10:54       ` Maxim Levitsky
2019-11-14 10:58     ` Maxim Levitsky
2019-11-14 10:37   ` Maxim Levitsky [this message]
2019-11-12 10:02 ` Daniel P. Berrangé
2019-11-22 14:22   ` API definition for LUKS key management [V2] Maxim Levitsky
2019-11-25 18:45     ` Max Reitz
2019-11-26  9:28       ` Maxim Levitsky
2019-11-26 14:24       ` Kevin Wolf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=89b580b2da26da8995a90ffd70e8325ba277a20a.camel@redhat.com \
    --to=mlevitsk@redhat.com \
    --cc=armbru@redhat.com \
    --cc=berrange@redhat.com \
    --cc=jferlan@redhat.com \
    --cc=jsnow@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).