diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst index 9013184d57..37a4270c18 100644 --- a/doc/source/configuration.rst +++ b/doc/source/configuration.rst @@ -1813,3 +1813,123 @@ example: [ldap] url = "ldap://localhost,ldap://backup.localhost" + + +Credential Encryption +===================== + +As of the Newton release, keystone encrypts all credentials stored in the +default ``sql`` backend. Credentials are encrypted with the same mechanism used +to encrypt Fernet tokens, ``fernet``. Keystone provides only one type of +credential encryption but the encryption provider is pluggable in the event +you wish to supply a custom implementation. + +This document details how credential encryption works, how to migrate existing +credentials in a deployment, and how to manage encryption keys for credentials. + +Configuring credential encryption +--------------------------------- + +The configuration for credential encryption is straightforward. There are only +two configuration options needed: + +.. code-block:: ini + + [credential] + provider = fernet + key_repository = /etc/keystone/credential-keys/ + +``[credential] provider`` defaults to the only option supplied by keystone, +``fernet``. There is no reason to change this option unless you wish to provide +a custom credential encryption implementation. The ``[credential] +key_repository`` location is a requirement of using ``fernet`` but will default +to the ``/etc/keystone/credential-keys/`` directory. Both ``[credential] +key_repository`` and ``[fernet_tokens] key_repository`` define locations for +keys used to encrypt things. One holds the keys to encrypt and decrypt +credentials and the other holds keys to encrypt and decrypt tokens. It is +imperative that these repositories are managed separately and they must not +share keys. Meaning they cannot share the same directory path. The +``[credential] key_repository`` is only allowed to have three keys. This is not +configurable and allows for credentials to be re-encrypted periodically with a +new encryption key for the sake of security. + +How credential encryption works +------------------------------- + +The implementation of this feature did not change any existing credential API +contracts. All changes are transparent to the user unless you're inspecting the +credential backend directly. + +When creating a credential, keystone will encrypt the ``blob`` attribute before +persisting it to the backend. Keystone will also store a hash of the key that +was used to encrypt the information in that credential. Since Fernet is used to +encrypt credentials, a key repository consists of multiple keys. Keeping track +of which key was used to encrypt each credential is an important part of +encryption key management. Why this is important is detailed later in the +`Encryption key management` section. + +When updating an existing credential's ``blob`` attribute, keystone will encrypt +the new ``blob`` and update the key hash. + +When listing or showing credentials, all ``blob`` attributes are decrypted in +the response. Neither the cipher text, nor the hash of the key used to encrypt +the ``blob`` are exposed through the API. Furthermore, the key is only used +internally to keystone. + +Encrypting existing credentials +------------------------------- + +When upgrading a Mitaka deployment to Newton, three database migrations will +ensure all credentials are encrypted. The process is as follows: + +1. An additive schema change is made to create the new ``encrypted_blob`` and + ``key_hash`` columns in the existing ``credential`` table using + ``keystone-manage db_sync --expand``. +2. A data migration will loop through all existing credentials, encrypt each + ``blob`` and store the result in the new ``encrypted_blob`` column. The hash + of the key used is also written to the ``key_hash`` column for that specific + credential. This step is done using ``keystone-manage db_sync --migrate``. +3. A contractive schema will remove the ``blob`` column that held the plain + text representations of the credential using ``keystone-manage db_sync + --contract``. This should only be done after all nodes in the deployment are + running Newton. If any Mitaka nodes are running after the database is + contracted, they won't be able to read credentials since they are looking + for the ``blob`` column that no longer exists. + +If performing a rolling upgrade, please note that a limited service outage will +take affect during this migration. When the migration is in place, credentials +will become read-only until the database is contracted. After the contract +phase is complete, credentials will be writeable to the backend. A +``[credential] key_repository`` location must be specified through +configuration and bootstrapped with keys using ``keystone-manage +credential_setup`` prior to migrating any existing credentials. + +Encryption key management +------------------------- + +Key management of ``[credential] key_repository`` is handled with three +``keystone-manage`` commands: + +1. ``keystone-manage credential_setup`` +2. ``keystone-manage credential_rotate`` +3. ``keystone-manage credential_migrate`` + +``keystone-manage credential_setup`` will populate ``[credential] +key_repository`` with new encryption keys. This must be done in order for +credential encryption to work. This step should only be done once. + +``keystone-manage credential_rotate`` will create and rotate a new encryption +key in the ``[credential] key_repository``. This will only be done if all +credential key hashes match the hash of the current primary key. If any +credential has been encrypted with an older key, or secondary key, the rotation +will fail. Failing the rotation is necessary to prevent overrotation, which +would leave some credentials indecipherable since the key used to encrypt it +no longer exists. If this step fails, it is possible to forcibly re-key all +credentials using the same primary key with ``keystone-manage +credential_migrate``. + +``keystone-manage credential_migrate`` will check the backend for credentials +whose key hash doesn't match the hash of the current primary key. Any +credentials with a key hash mismatching the current primary key will be +re-encrypted with the current primary key. The new cipher text and key hash +will be updated in the backend. diff --git a/releasenotes/notes/support_encrypted_credentials_at_rest-93dcb67b3508e91a.yaml b/releasenotes/notes/support_encrypted_credentials_at_rest-93dcb67b3508e91a.yaml new file mode 100644 index 0000000000..57cdc1e341 --- /dev/null +++ b/releasenotes/notes/support_encrypted_credentials_at_rest-93dcb67b3508e91a.yaml @@ -0,0 +1,14 @@ +--- +upgrade: + - Keystone now supports encrypted credentials at rest. + In order to upgrade successfully to Newton, deployers + must encrypt all credentials currently stored before + contracting the database. Deployers must run + `keystone-manage credential_setup` in order to use the + credential API within Newton, or finish the upgrade + from Mitaka to Newton. This will result in a service + outage for the credential API where credentials will + be read-only for the duration of the upgrade process. + Once the database is contracted credentials will be + writeable again. Database contraction phases only + apply to rolling upgrades.