From 9beaeab888054d88a9615fb7b0d8440b54367526 Mon Sep 17 00:00:00 2001 From: Alex Kavanagh Date: Fri, 13 Jul 2018 09:16:30 +0200 Subject: [PATCH] Add Fernet token spec Fernet tokens are the successor to UUID tokens, and are the default in rocky and beyond. This changeset add the specification for the implementation of Fernet token support into the keystone charm. Change-Id: I190b6bccba71ea4afac2cc733b0628c270ca34e6 --- .../rocky/approved/keystone-fernet-tokens.rst | 264 ++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 specs/rocky/approved/keystone-fernet-tokens.rst 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.