diff --git a/specs/rocky/approved/keystone-fernet-tokens.rst b/specs/rocky/approved/keystone-fernet-tokens.rst new file mode 100644 index 0000000..cb81b8d --- /dev/null +++ b/specs/rocky/approved/keystone-fernet-tokens.rst @@ -0,0 +1,264 @@ +.. + Copyright 2017 Canonical LTD + + This work is licensed under a Creative Commons Attribution 3.0 + Unported License. + http://creativecommons.org/licenses/by/3.0/legalcode + +.. + This template should be in ReSTructured text. Please do not delete + any of the sections in this template. If you have nothing to say + for a whole section, just write: "None". For help with syntax, see + http://sphinx-doc.org/rest.html To test out your formatting, see + http://www.tele3.cz/jbar/rest/rest.html + +==================================== +Keystone Fernet Token Implementation +==================================== + +Fernet tokens were added to OpenStack to solve the problem of keystone being +required to persist tokens to the a common database (cluster) like UUID tokens, +and solve the problem of size for PKI or PKIZ tokens. + +From `Fernet - Frequently Asked Questions +`__ + +A fernet token is a bearer token that represents user authentication. Fernet +tokens contain a limited amount of identity and authorization data in a +`MessagePacked`__ payload. The payload is then wrapped as a Fernet message for +transport, where `Fernet`__ provides the required web safe characteristics for +use in URLs and headers. The data inside the fernet token is protected using +symmetric encryption keys, or fernet keys. + +.. _Fernet: https://github.com/fernet/spec +.. _MessagePacked: http://msgpack.org/ + +Task Description +================ + +Keystone has had support for Fernet tokens since Kilo, so all services support +fernet token authorization. In the upcoming Rocky release the sql token driver +and uuid token provider will be removed. The main part of the work on this +task is changing the keystone charm to enable configuration of fernet tokens, +provide the initialisation of fernet tokens, provide rotation of fernet keys +and their subsequent synchronisation to other keystone units. + +There are also some issues around what aspects should be configurable vs +controlled by the charm. The :ref:`proposed-change-label` section provides +more details about this. + +Finally, upgrading an existing OpenStack implementation from another token +system to Fernet tokens is discussed, and the support the charm(s) will need to +implement to support this, along with documentation. + +.. _proposed-change-label: + +Proposed Change +=============== + +Theory of Operation +------------------- + +The keystone-charm will, with the appropriate configuration options, configure +keystone to generate fernet tokens. + +In order to generate tokens, fernet keys are used. These are generated by +keystone and have an expiry date. The key repository is a directory, and each +key is an integer number, with the highest number being the primary key. Key +'0' is the staged key, that will be the next primary. Other keys are secondary +keys. + +New tokens are only ever generated from the primary key, whilst they secondary +keys are used to validate existing tokens. The staging key is not used to +generate tokens, but can be used to validate tokens as the staging key might be +the new primary key on the master due to a rotation and the keys have not yet +been synchronised across all the units. + +Fernet keys need to be rotated at periodic intervals, and the keys need to be +synchronised to each of the other keystone units. Keys should only be rotated +on the master keystone unit, and must be synchronised *before* they are rotated +again. "*Over rotation*" occurs if a unit rotates its keys such that there is +no suitable decoding key on another unit that can decode a token that has been +generated on the master. This happens if two key rotations are done on the +master before a synchronisation has been successfully performed. This should +be avoided. Over rotations can also cause validation keys to be removed +*before* a token's expiration which would result in failed validations. + +There are 3 parts to the **Key Rotation Strategy**: + +1. The rotation frequency +2. The token lifespan (set with ``[token] expiration``) +3. The number of active keys: (set with ``[fernet_tokens] max_active_keys``) + +There needs to be at least 3 keys as a minumum. The actual number of keys is +determined by the *token lifespan* and the *rotation frequency*. The +*max_active_keys* must be one greater than the *token lifespan* / *rotation +frequency* + +To quote from the `FAQ `__: + + The number of max_active_keys for a deployment can be determined by + dividing the token lifetime, in hours, by the frequency of rotation in + hours and adding two. Better illustrated as: + +.. code:: python + + token_expiration = 24 + rotation_frequency = 6 + max_active_keys = (token_expiration / rotation_frequency) + 2 + +In the keystone charm, there is already the config parameter +``token-expiration`` in seconds, and there will be a proposed config item of +``fernet-max-active-keys``. Thus, the *rotation frequence* will be calucated +as: + +.. code:: python + + token_expiration = 24 # actually 3600, as it's in seconds + max_active_keys = 6 + rotation_frequency = token_expiration / (max_active_keys - 2) + +Thus, the fernet-max-active-keys can never be less than 3 (which will be +enforced in the charm), which would make the rotation frequency the *same* as +the token expiration time. + +Upgrading an Existing System +---------------------------- + +To upgrade an existing system to use Fernet tokens, the keystone charm should +be upgraded first. The (new) configuration option ``token-provider`` has a +*no* default value set, which means on a pre-rocky install the token type will +remain as ``UUID``. In order to move a pre-rocky install to Fernet, the +``token-provider`` option should be set to ``fernet``. + +Note that if a pre-rocky system is upgraded to rocky, then the default token +type will be ``fernet``. The rocky cycle removes support for ``UUID`` tokens. +Thus upgrading a system to rocky will automatically use fernet as the only +token type. The ``token-provider`` option is only valid for pre-rocky systems. + +Note that althought the charms enable token cachinng with memcache by default, +this is only for the default of 300 seconds as the ``token_cache_time`` is not +being set (see `(Keystone) Middleware Architecture: Improving response time +`__ +for further details. The impact of this is that some services may try to +re-authenticate during the upgrade, and depending on which keystone unit they +"pick", and what stage the upgrade is at, will determine whether the action +succeeds. As different services may be part of the same action, this might +lead to *odd* failure modes. However, once the system is upgraded, after the +default of 300 seconds, *all* services will continue to operate normally. + +Therefore, there *may* be some percieved outage of the openstack control plane. +Already running instances will not be affected and all services will continue +to operate normally as soon as they request new tokens from keystone. + +Additional Configuration Items +------------------------------ + +The following configuration items will be needed in the keystone charm. + +* **token-provider** - the token system to use: Either 'uuid' or 'fernet'. The + default will not be set. Pre-rocky systems will have a default of ``uuid``. + On rocky systems, the configuration option has no effect. As the default is + ``uuid`` for pre-rocky systems, the token-provider won't change on an upgrade + unless the operator sets the configuration value to ``fernet``. + +* **fernet-max-active-keys** - the maximum active keys configured in keystone. + This controls the key rotation trigger times based on this config item and + the config item *token-expiration*. + +Keystone Actions +---------------- + +The following action will be required: + +* **purge-tokens** -- purge existing tokens from the database. This is used + after upgrading from ``UUID`` to ``Fernet`` tokens, + +Internal Cron Jobs +------------------ + +The charm will set up a cron job to rotate the keys and then synchronise them +to the other peered units. The cron job will call ``juju run`` from within the +charm to rotate the keys and then synchronise the keys to the other peered +units. It will also only perform this action if it is the leader. The cron +job will run on *all* peered units, but only have an effect on the leader. + +Synchronisation of the Fernet keys will be via Juju leader settings. The keys +are small, and "leader settings" provides a convenient and secure mechanism to +synchronise the keys between units without having to explicitly provide +networking for all keystone peered units. The delay in transferring the keys +using hooks is not an issue as the synchronisation does not need to be +immediate; indeed, it could be just before the next key rotation in the worst +case, although, this is extremely unlikely to be the case. + +Alternatives +============ + +In the Openstack rocky release, *fernet* is the only token provider available. +Therefore, there is no alternative. + +Implementation +============== + +Assignee(s) +----------- + +Primary assignee: + ajkavanagh + +Secondary assignees: + fnordahl + +Gerrit Topic +------------ + +Use Gerrit topic "fernet-keystone-charm" for all patches related to this spec. + +.. code-block:: bash + + git-review -t fernet-keystone-charm + +Work Items +---------- + +* Add fernet token functionality to the keystone-charm. This includes: + * setup + * upgrade + * rotate / sync actions + * cron job for automatic rotate / sync. +* Add Fernet token information to the documentation: + * charm-store text for keystone charm + * Notes in the charm guide re: uuid vs Fernet. +* Update tests: + * Amulet/bundle for actions / verify installation. + * Update other bundles to ensure defaults + * Upgrade from uuid to Fernet tokens. + +Repositories +------------ + +No new git repositories required. + +Documentation +------------- + +Documentation will be provided as part of the keystone charm and notes in charm +guide. + +Security +-------- + +A change of token provider does have security implications and well tested and +proved best practices for using the fernet token provider will be implemented. + +Testing +------- + +Unit tests will be developed along with new code. Functional tests will be +implemented. A scenario test for change of token provider will also be +written. + +Dependencies +============ + +No external dependencies.