From f17d817ae0f0f3fa7ba69eb927116fcf073308a8 Mon Sep 17 00:00:00 2001 From: Matt McEuen Date: Tue, 18 Sep 2018 14:16:13 -0500 Subject: [PATCH] Spec: Pegleg encryption and decryption This patchset rounds out the encryption-related design changes for Pegleg, on top of the existing secret generation material. It also incorporates some late-add feedback from the previous patchset. Change-Id: Ifff04551d24d29e41d71812526bd04c9512b4fbd Story: 2003708 Task: 26535 --- specs/approved/pegleg-secrets.rst | 95 ++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 19 deletions(-) diff --git a/specs/approved/pegleg-secrets.rst b/specs/approved/pegleg-secrets.rst index ba40145..9c8536a 100644 --- a/specs/approved/pegleg-secrets.rst +++ b/specs/approved/pegleg-secrets.rst @@ -43,9 +43,8 @@ The following Airship components will be impacted by this solution: #. Pegleg: enhanced to generate, rotate, encrypt, and decrypt secrets. #. Promenade: PKICatalog will move to Pegleg. -#. Treasuremap: site manifests augmented to support the updated Secrets schema. -#. Airship-in-a-Bottle: site manifests augmented to support the updated - Secrets schema. +#. Treasuremap: update site manifests to use new Catalogs. +#. Airship-in-a-Bottle: update site manifests to use new Catalogs. Proposed change =============== @@ -79,7 +78,7 @@ example:: abstract: false # Pegleg will initially support generation at site level only layer: site - storagePolicy: encrypted + storagePolicy: cleartext data: generated: at: @@ -89,6 +88,7 @@ example:: reference: path: managedDocument: + schema: metadata: storagePolicy: encrypted schema: @@ -109,12 +109,13 @@ example:: layeringDefinition: abstract: false layer: matching-wrapped-doc - storagePolicy: encrypted + storagePolicy: cleartext data: encrypted: at: by: managedDocument: + schema: metadata: storagePolicy: encrypted schema: @@ -126,7 +127,7 @@ A PeglegManagedDocument that is both generated via a Catalog, and encrypted (as specified by the catalog) will contain both ``generated`` and ``encrypted`` stanzas. -Note that this ``encrypted`` has a different purpose than the Deckhand +Note that this ``encrypted`` key has a different purpose than the Deckhand ``storagePolicy: encrypted`` metadata, which indicates an *intent* for Deckhand to store a document encrypted at rest in the cluster. The two can be used together to ensure security, however: if a document is marked as @@ -134,6 +135,11 @@ together to ensure security, however: if a document is marked as persisted (e.g. to a Git repository) if it is in fact encrypted within a PeglegManagedDocument. +Note also that the Deckhand ``storagePolicy`` of the PeglegManagedDocument +itself is always ``cleartext``, since its data stanza is not encrypted -- it +only wraps a document that *is* ``storagePolicy: encrypted``. +This should be implemented as a Pegleg lint rule. + Document Generation ------------------- @@ -204,7 +210,10 @@ The nonobvious bits of the document described above are: replace dashes in the ``document_name`` with underscores. * ``length`` is optional, and denotes the length in characters of the generated cleartext passphrase data. If absent, ``length`` defaults - to ``24``. + to ``24``. Note that with this length and the selected character set there + will be less than 8x10^48 probability of getting a new passphrase that is + identical to the previous passphrase. This is sufficiently random to + ensure no duplication of rotated passphrases in practice. * ``description`` is optional. The ``encrypted`` key will be added to the PKICatalog schema, and adds the same @@ -220,16 +229,27 @@ Committing and pushing the changes will be left to the operator or to script-based automation. For the CLI commands below which encrypt or decrypt secrets, an environment -variable (e.g. ``$PEGLEG_KEY`` will be use to capture the key/passphrase to use. -``pegleg site secrets rotate`` will use a second variable -(e.g. ``$PEGLEG_PREVIOUS_KEY``) to hold the key/passphrase being rotated -out. +variable (e.g. ``PEGLEG_PASSPHRASE`` will be use to capture the master +passphrase to use. ``pegleg site secrets rotate`` will use a second variable +(e.g. ``PEGLEG_PREVIOUS_PASSPHRASE``) to hold the key/passphrase being rotated +out. The contents of these keys/passphrases are not generated by Pegleg, +but are created externally and set by a deployment engineer or tooling. +A configurable minimum length (default 24) for master passphrases will +be checked by all CLI commands which use the passphrase. All other criteria +around passphrase strength are assumed to be enforced elsewhere, as it is an +external secret that is consumed/used by Pegleg. ``pegleg site secrets generate passphrases``: Generate passphrases according to all PassphraseCatalog documents in the site. Note that regenerating passphrases can be accomplished simply by re-running ``pegleg site secrets generate passphrases``. +``pegleg generate passphrase``: A standalone version of passphrase generation. +This generates a single passphrase based on the default length, character set, +and implementation described above, and outputs it to the console. The +PassphraseCatalog is not involved in this operation. This command is suitable +for generation of a highly-secure Pegleg master passphrase. + ``pegleg site secrets generate pki``: Generate certificates and keys according to all PKICatalog documents in the site. Note that regenerating certificates can be accomplished @@ -258,22 +278,28 @@ original document YAML to standard output. This is intended to be used when an authorized deployment engineer needs to determine a particular cleartext secret for a specific operational purpose. -``pegleg site secrets rotate``: This action re-encrypts encrypted secrets -with a new key/passphrase, and it takes the previously-used key and a new -key as input. It accomplishes its task via two activities: +``pegleg site secrets rotate passphrases``: This action re-encrypts +encrypted passphrases with a new key/passphrase, and it takes the +previously-used key and a new key as input. It accomplishes its task via +two activities: -* For encrypted secrets that were imported from outside of Pegleg +* For encrypted passphrases that were imported from outside of Pegleg (i.e. PeglegManagedDocuments which lack the ``generated`` stanza), decrypt them with the old key (in-memory), re-encrypt them with the new key, and output the results. -* Perform a fresh ``pegleg site secrets generate`` process using the new key. - This will replace all ``generated`` secrets with new secret values +* Perform a fresh ``pegleg site secrets generate passphrases`` process + using the new key. + This will replace all ``generated`` passphrases with new secret values for added security. There is an assumption here that the only actors that need to know generated secrets are the services within the Airship-managed cluster, not external services or deployment engineers, except perhaps for point-in-time troubleshooting or operational exercises. +Similar functionality for rotating certificates (which is expected to have +a different cadence than passphrase rotation, typically) will be +added in the future. + Driving deployment of a site directly via Pegleg is follow-on functionality which will collect site documents, use them to create the ``genesis.sh`` script, and then @@ -289,7 +315,7 @@ PeglegManagedDocuments will be written (encrypted) to disk. To enable special case full site secret decryption, a ``--force-decrypt`` flag will be added to ``pegleg collect`` to do this under controlled circumstances, and to help bridge the gap with existing CICD pipelines until Pegleg-driven -site deployment is in place. It will leverage the ``$PEGLEG_KEY`` +site deployment is in place. It will leverage the ``PEGLEG_PASSPHRASE`` variable described above. Secret Generation @@ -309,7 +335,33 @@ Python string.ascii_letters, string.digits, and string.punctuation. Secret Encryption ----------------- -Details around encryption will be defined in a follow-on patch set to this spec. +The Python ``cryptography`` library has been chosen to implement the +encryption and decryption of secrets within Pegleg. ``cryptography`` +aims to be the standard cryptographic approach for Python, and takes +pains to make it difficult to do encryption poorly (via its ``recipes`` +layer), while still allowing access to the algorithmic details when +truly needed (via its ``hazmat`` layer). ``cryptography`` is actively +maintained and is the target encryption library for OpenStack as well. + +The ``cryptography.fernet`` module will be used for symmetric encryption. +It uses AES with a 128-bit key for encryption, and HMAC using SHA256 +for encryption. + +Fernet requires as input a URL-safe, base64-encoded 32-byte encryption key, +which will be derived from the master passphrase passed into Pegleg via +``PEGLEG_PASSPHRASE`` as described above. +The example for password-based encryption from the `Fernet documentation`_ +should be followed as a guide. The ``salt`` to be used in key derivation +will be configurable, and will be set to a fixed value within a built +Pegleg container via an environment variable passed into the Pegleg +Dockerfile. This will allow the salt to be different on an +operator-by-operator basis. + +The ``cryptography.exceptions.InvalidSignature`` exception is thrown by +``cryptography`` when an attempt is made to decrypt a message with a key that +is different than the one used to encrypt a message, i.e., when the user has +supplied an incorrect phassphrase. It should be handled gracefully by Pegleg, +resulting in an informative message back to the user. Security impact =============== @@ -346,6 +398,10 @@ the point-in-time encryption status. ``storagePolicy`` is still valuable in this context to make sure everything that *should* be encrypted *is*, prior to performing actions with it (e.g. Git commits). +The ``PyCrypto`` library is a popular solution for encryption in Python; +however, it is no longer actively maintained. Following the lead of OpenStack +and others, we opted instead for the ``cryptography`` library. + This proposed implementation writes the output of generation/encryption events back to the same source files from which the original data came. This is a destructive operation; however, it wasn't evident that it is problematic in @@ -370,3 +426,4 @@ References .. _Storyboard Story: https://storyboard.openstack.org/#!/story/2003708 .. _Git branch and revision support: https://review.openstack.org/#/c/577886/ +.. _Fernet documentation: https://cryptography.io/en/latest/fernet/