I don't have a horse in this race or a strong opinion on the topic, in fact I'm admittedly not very knowledgeable when it comes to low-level encryption things.
However, I did have a question, even if just to generate discussion. Did we ever consider simply leaving secrets out of Zuul and offloading that "burden" to something else ? For example, end-users could use something like git-crypt [1] to crypt files in their git repos and Zuul could have a mean to decrypt them at runtime. There is also ansible-vault [2] that could perhaps be leveraged. Just trying to make sure we're not re-inventing any wheels, implementing crypto is usually not straightfoward. [1]: https://www.agwa.name/projects/git-crypt/ [2]: http://docs.ansible.com/ansible/playbooks_vault.html David Moreau Simard Senior Software Engineer | Openstack RDO dmsimard = [irc, github, twitter] On Tue, Mar 21, 2017 at 12:36 PM, James E. Blair <[email protected]> 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+project: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: [email protected]?subject:unsubscribe > http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev __________________________________________________________________________ OpenStack Development Mailing List (not for usage questions) Unsubscribe: [email protected]?subject:unsubscribe http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
