[openstack-dev] [infra][security] Encryption in Zuul v3

Matthieu Huin mhuin at redhat.com
Tue Mar 21 17:43:49 UTC 2017


Hello James,

Thanks for opening the discussion on this topic. I'd like to mention that a
very common type of secrets that are used in Continuous Deployments
scenarios are SSH keys. Correct me if I am wrong, but PKCS#1 wouldn't
qualify if standard keys were to be stored.

Regards,

Matthieu

On Tue, Mar 21, 2017 at 6:38 PM, Matthieu Huin <mhuin at redhat.com> wrote:

> Hello James,
>
> Thanks for opening the discussion on this topic. I'd like to mention that
> a very common type of secrets that are used in Continuous Deployments
> scenarios are SSH keys. Correct me if I am wrong, but PKCS#1 wouldn't
> qualify if standard keys were to be stored.
>
> On Tue, Mar 21, 2017 at 5:36 PM, James E. Blair <corvus at inaugust.com>
> wrote:
>
>> Hi,
>>
>> In working on the implementation of the encrypted secrets feature of
>> Zuul v3, I have found some things that warrant further discussion.  It's
>> important to be deliberate about this and I welcome any feedback.
>>
>> For reference, here is the relevant portion of the Zuul v3 spec:
>>
>> http://specs.openstack.org/openstack-infra/infra-specs/specs
>> /zuulv3.html#secrets
>>
>> And here is an implementation of that:
>>
>> https://review.openstack.org/#/q/status:open+topic:secrets+p
>> roject:openstack-infra/zuul
>>
>> The short version is that we want to allow users to store private keys
>> in the public git repos which Zuul uses to run jobs.  To do this, we
>> propose to use asymmetric cryptography (RSA) to encrypt the data.  The
>> specification suggests implementing PKCS#1-OAEP, a standard for
>> implementing RSA encryption.
>>
>> Note that RSA is not able to encrypt a message longer than the key, and
>> PKCS#1 includes some overhead which eats into that.  If we use 4096 bit
>> RSA keys in Zuul, we will be able to encrypt 3760 bits (or 470 bytes) of
>> information.
>>
>> Further, note that value only holds if we use SHA-1.  It has been
>> suggested that we may want to consider using SHA-256 with PKCS#1.  If we
>> do, we will be able to encrypt slightly less data.  However, I'm not
>> sure that the Python cryptography library allows this (yet?).  Also, see
>> this answer for why it may not be necessary to use SHA-256 (and also,
>> why we may want to anyway):
>>
>> https://security.stackexchange.com/questions/112029/should-
>> sha-1-be-used-with-rsa-oaep
>>
>> One thing to note is that the OpenSSL CLI utility uses SHA-1.  Right
>> now, I have a utility script which uses that to encrypt secrets so that
>> it's easy for anyone to encrypt a secret without installing many
>> dependencies.  Switching to another hash function would probably mean we
>> wouldn't be able to use that anymore.  But that's also true for other
>> systems (see below).
>>
>> In short, PKCS#1 pros: Simple, nicely packaged asymmetric encryption,
>> hides plaintext message length (up to its limit).  Cons: limited to 470
>> bytes (or less).
>>
>> Generally, when faced with the prospect of encrypting longer messages,
>> the advice is to adopt a hybrid encryption scheme (as opposed to, say,
>> chaining RSA messages together, or increasing the RSA key size) which
>> uses symmetric encryption with a single-use key for the message and
>> asymmetric encryption to hide the key.  If we want Zuul to support the
>> encryption of longer secrets, we may want to adopt the hybrid approach.
>> A frequent hybrid approach is to encrypt the message with AES, and then
>> encrypt the AES key with RSA.
>>
>> The hiera-eyaml work which originally inspired some of this is based on
>> PKCS#7 with AES as the cipher -- ultimately a hybrid approach.  An
>> interesting aspect of that implementation is that the use of PKCS#7 as a
>> message passing format allows for multiple possible underlying ciphers
>> since the message is wrapped in ASN.1 and is self-descriptive.  We might
>> have simply chosen to go with that except that there don't seem to be
>> many good options for implementing this in Python, largely because of
>> the nightmare that is ASN.1 parsing.
>>
>> The system we have devised for including encrypted content in our YAML
>> files involves a YAML tag which specifies the encryption scheme.  So we
>> can evolve our use to add or remove systems as needed in the future.
>>
>> So to break this down into a series of actionable questions:
>>
>> 1) Do we want a system to support encrypting longer secrets?  Our PKCS#1
>> system supports up to 470 bytes.  That should be sufficient for most
>> passwords and API keys, but unlikely to be sufficient for some
>> certificate related systems, etc.
>>
>> 2) If so, what system should we use?
>>
>>    2.1a) GPG?  This has hybrid encryption and transport combined.
>>    Implementation is likely to be a bit awkward, probably involving
>>    popen to external processes.
>>
>>    2.1b) RSA+AES?  This recommendation from the pycryptodome
>>    documentation illustrates a typical hybrid approach:
>>    https://pycryptodome.readthedocs.io/en/latest/src/examples.
>> html#encrypt-data-with-rsa
>>    The transport protocol would likely just be the concatenation of
>>    the RSA and AES encrypted data, as it is in that example.  We can
>>    port that example to use the python-cryptography primatives, or we
>>    can switch to pycryptodome and use it exactly.
>>
>>    2.1c) RSA+Fernet?  We can stay closer to the friendly recipes in
>>    python-cryptography.  While there is no complete hybrid recipe,
>>    there is a symmetric recipe for "Fernet" which is essentially a
>>    recipe for AES encryption and transport.  We could encode the
>>    Fernet key with RSA and concatenate the Fernet token.
>>    https://github.com/fernet/spec/blob/master/Spec.md
>>
>>    2.1d) NaCL?  A "sealed box" in libsodium (which underlies PyNaCL)
>>    would do what we want with a completely different set of
>>    algorithms.
>>    https://github.com/pyca/pynacl/issues/189
>>
>> 3) Do we think it is important to hide the length of the secret?  AES
>> will expose the approximate length of the secret up to the block size
>> (16 bytes).  This is probably not important for long secrets, but for
>> short ones, it may at least indicate the order of magnitude of a
>> password, for instance.  If we want, we can pad the secret further
>> before encrypting it.
>>
>> 4) If we adopt a system for longer secrets, do we still want to include
>> PKCS#1 for shorter ones?  The PKCS#1 ciphertext will be shorter than the
>> same secret would be in a hybrid system.  But either way, we're talking
>> about a fairly big blob (about 9 lines of base64 for PKCS#1).
>>
>> 5) If we keep PKCS#1, are we okay using SHA-1 or should we see about
>> using SHA-256?
>>
>> 6) Considering all of that, should we:
>>
>>   A) Stick with PKCS#1 for now (we can always add something else later)
>>   B) Keep PKCS#1 and add something else now
>>   C) Drop PKCS#1 and replace it with something else
>>
>> Thanks,
>>
>> Jim
>>
>>
>> ____________________________________________________________
>> ______________
>> OpenStack Development Mailing List (not for usage questions)
>> Unsubscribe: OpenStack-dev-request at lists.openstack.org?subject:unsubscrib
>> e
>> http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstack.org/pipermail/openstack-dev/attachments/20170321/c694b43b/attachment.html>


More information about the OpenStack-dev mailing list