Repropose JWT specification for Stein
This spec was something we agreed upon as a team during the Queens release. This commit reproposes it for Stein. Major differences between this specification the original proposal from Queens include: - the algorithm targeted for the implementation - the library being used to sign and validate JWTs - the payload data and claim information - asymmetric key rotation details bp json-web-tokens Change-Id: I598faca40a6d81dd58155165d4a323fb437f7a6c
This commit is contained in:
parent
e354333611
commit
c87a0230b3
|
@ -1,197 +0,0 @@
|
|||
..
|
||||
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||
License.
|
||||
|
||||
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||
|
||||
======================================================
|
||||
Add JSON Web Tokens as a Non-persistent Token Provider
|
||||
======================================================
|
||||
|
||||
`bp json-web-tokens <https://blueprints.launchpad.net/keystone/+spec/json-web-tokens>`_
|
||||
|
||||
|
||||
JSON Web Token is a type of non-persistent bearer token similar to the fernet
|
||||
tokens we use today. JWT is an `open standard`_ with `actively maintained
|
||||
libraries`_.
|
||||
|
||||
.. _`open standard`: https://tools.ietf.org/html/rfc7519
|
||||
.. _`actively maintained libraries`: https://jwt.io/#libraries
|
||||
|
||||
Problem Description
|
||||
===================
|
||||
|
||||
We currently support two types of tokens. The UUID persistent token format is
|
||||
the original format. The fernet token format is a non-persistent format based
|
||||
on a spec by Heroku and was made the default token format for keystone.
|
||||
|
||||
The UUID token format suffers a number of performance and maintainability
|
||||
problems. It is already deprecated and we intend to eventually remove it, in
|
||||
favor of non-persistent token formats.
|
||||
|
||||
However, the fernet format has its own problems that make it non-ideal. The
|
||||
`fernet spec`_ is largely abandoned, making it hard to `get changes into it`_
|
||||
and thereby into the `cryptography` implementation of it. Moreover, the fernet
|
||||
spec is not recognized by any standards body and therefore not as closely
|
||||
audited as an IETF standard, making it more susceptable to zero-day
|
||||
vulnerabilities. Addressing these vulnerabilities falls solely on the
|
||||
OpenStack, specifically the keystone, community.
|
||||
|
||||
It would be nice to offer a new type of token that is backed by a widely used
|
||||
standard before we totally remove support for UUID tokens. This also increases
|
||||
interoperability between the OpenStack ecosystem and other communities that
|
||||
support JWT.
|
||||
|
||||
.. _`fernet spec`: https://github.com/fernet/spec/blob/master/Spec.md
|
||||
.. _`get changes into it`: https://github.com/fernet/spec/pull/13
|
||||
|
||||
|
||||
Proposed Change
|
||||
===============
|
||||
|
||||
Create a new non-persistent keystone token backend based on the `JSON Web Token
|
||||
standard`_. These will behave in much the same way as our current fernet tokens
|
||||
do.
|
||||
|
||||
The token will be a nested JWT which is a signed JWT (`JWS`_) as the payload of
|
||||
an encrypted JWT (`JWE`_), meaning the token data is signed and then encrypted.
|
||||
This is the order specifically recommended in the JWT spec due to its use of
|
||||
Authenticated Encryption which eliminates the need to sign after encryption.
|
||||
|
||||
Similar to the fernet, JWTs will require a key repository be set up to use for
|
||||
signing tokens. A new ``keystone-manage`` command will be added to handle
|
||||
secret generation and rotation which will likely re-use much of the utilities
|
||||
in the fernet_setup and fernet_rotate commands. JWE can use symmetric keys for
|
||||
encryption and signing the way fernet does but it is more typical to use an
|
||||
asymmetric key pair to encrypt the Content Encryption Key (which is then used
|
||||
as a symmetric key to encrypt the payload, but this is an implementation detail
|
||||
that will be handled by the chosen library), so the JWT key repository should
|
||||
have asymmetric key pairs which we can use for encryption and signing. The
|
||||
specific algorithms used will depend on the support for them in the chosen
|
||||
library.
|
||||
|
||||
The payload of the JWS will use the following `registered claims`_:
|
||||
|
||||
* the "sub" claim for the subject, i.e. the user. This claim will include the
|
||||
same data that fernet tokens do, such as user information and scope.
|
||||
* the "exp" claim for expiry
|
||||
* the "iat" claim for "issued at", analogous to the timestamp field in the
|
||||
fernet token.
|
||||
|
||||
The `PyJWT library`_ is already present in the requirements repository and so
|
||||
would be a convenient choice to use for this implementation, but it
|
||||
unfortunately `does not yet support JWE`_. We will need to evaluate the
|
||||
`JWCrypto library`_ which does support encryption or consider contributing the
|
||||
feature to PyJWT.
|
||||
|
||||
Users will request and present tokens in exactly the same way they currently do
|
||||
with either UUID or Fernet tokens. There is no need to add or change any APIs.
|
||||
|
||||
.. _`JSON Web Token standard`: https://tools.ietf.org/html/rfc7519
|
||||
.. _`JWS`: https://tools.ietf.org/html/rfc7515
|
||||
.. _`JWE`: https://tools.ietf.org/html/rfc7516
|
||||
.. _`registered claims`: https://tools.ietf.org/html/rfc7519#section-4.1
|
||||
.. _`Python libraries`: https://jwt.io/#libraries
|
||||
.. _`PyJWT library`: https://pyjwt.readthedocs.io/en/latest/
|
||||
.. _`does not yet support JWE`: https://github.com/jpadilla/pyjwt/issues/143
|
||||
.. _`JWCrypto library`: http://jwcrypto.readthedocs.org/
|
||||
|
||||
Alternatives
|
||||
------------
|
||||
|
||||
Not applicable, this is an additive change. The alternative is not to add it or
|
||||
to find a different token format.
|
||||
|
||||
Security Impact
|
||||
---------------
|
||||
|
||||
Since JWT is a widely used web standard, this will have a net positive impact
|
||||
on security. The implementation will use JWE even though it is an optional
|
||||
feature of the JWT spec. While this will not protect against an attacker using
|
||||
a valid token to query keystone for information about the token, it protects
|
||||
against an attacker gaining information from an expired or revoked token. This
|
||||
will ensure that the data within the token is at least as secure as it is in
|
||||
fernet tokens. These will still be bearer tokens and so interception of one
|
||||
must still be guarded against.
|
||||
|
||||
Notifications Impact
|
||||
--------------------
|
||||
|
||||
Notifications for JWTs will behave in the same way that they do for fernet
|
||||
tokens, including for revocation events.
|
||||
|
||||
Other End User Impact
|
||||
---------------------
|
||||
|
||||
This will have no end user impact. They will request and use JWTs in exactly
|
||||
the same way that they currently use fernet or UUID tokens.
|
||||
|
||||
Performance Impact
|
||||
------------------
|
||||
|
||||
Performance will be on-par with fernet tokens.
|
||||
|
||||
Other Deployer Impact
|
||||
---------------------
|
||||
|
||||
This is an optional, opt-in feature that will not be the default, so deployers
|
||||
will not be affected unless they choose to deploy this feature. In that case,
|
||||
deployers will need to set up a key repository before using JWTs. The key
|
||||
repository will contain asymmetric key pairs rather than just secret keys. The
|
||||
deployer will need to take care to sync and rotate keys the way they do with
|
||||
fernet tokens.
|
||||
|
||||
Developer Impact
|
||||
----------------
|
||||
|
||||
The new token type will reuse much of the work already done for fernet tokens
|
||||
and will follow similar code paths, so this will be relatively easy to
|
||||
maintain.
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
Assignee(s)
|
||||
-----------
|
||||
|
||||
TBD: Please update this section when this spec is reproposed to a release.
|
||||
|
||||
Primary assignee:
|
||||
<launchpad-id or None>
|
||||
|
||||
Other contributors:
|
||||
<launchpad-id or None>
|
||||
|
||||
Work Items
|
||||
----------
|
||||
|
||||
* Decide on an implementation library
|
||||
* Refactor the fernet utilities modules to be generic enough to work with JWT
|
||||
or inheritable
|
||||
* Add a ``keystone-manage`` command to set up and rotate JWT signing/encryption
|
||||
keys
|
||||
* Generalize the ``TokenFormatter`` class to support JWT
|
||||
* Refactor the fernet token provider module to be inheritable or generic
|
||||
* Add a keystone doctor command to validate the setup in the same way that
|
||||
fernet is validated
|
||||
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
* A JWT library to be decided on
|
||||
|
||||
|
||||
Documentation Impact
|
||||
====================
|
||||
|
||||
The new ``[token]/provider`` configuration option will need to be documented,
|
||||
as will the new ``keystone-manage`` commands.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
* `JSON Web Token RFC <https://tools.ietf.org/html/rfc7519>`_
|
||||
* `JSON Web Token light introduction <https://jwt.io/introduction/>`_
|
||||
* `History of cryptography's adoption of fernet <https://github.com/pyca/cryptography/issues/2900>`_
|
|
@ -0,0 +1,406 @@
|
|||
..
|
||||
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
||||
License.
|
||||
|
||||
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||
|
||||
======================================================
|
||||
Add JSON Web Tokens as a Non-persistent Token Provider
|
||||
======================================================
|
||||
|
||||
`bp json-web-tokens <https://blueprints.launchpad.net/keystone/+spec/json-web-tokens>`_
|
||||
|
||||
|
||||
JSON Web Token is a type of non-persistent bearer token similar to the fernet
|
||||
tokens we use today. JWT is an `open standard`_ with `actively maintained
|
||||
libraries`_.
|
||||
|
||||
.. _`open standard`: https://tools.ietf.org/html/rfc7519
|
||||
.. _`actively maintained libraries`: https://jwt.io/#libraries
|
||||
|
||||
Problem Description
|
||||
===================
|
||||
|
||||
We currently support one token format called fernet. The fernet token format is
|
||||
a non-persistent format based on a spec by Heroku and was made the default
|
||||
token format for keystone.
|
||||
|
||||
However, the fernet format has its own problems that make it non-ideal. The
|
||||
`fernet spec`_ is largely abandoned, making it hard to `get changes into it`_
|
||||
and thereby into the `cryptography`_ implementation of it. Moreover, the fernet
|
||||
spec is not recognized by any standards body and therefore not as closely
|
||||
audited as an IETF standard, making it more susceptible to zero-day
|
||||
vulnerabilities. Addressing these vulnerabilities falls solely on the
|
||||
OpenStack, specifically the keystone, community.
|
||||
|
||||
It would be nice to offer a new type of token that is backed by a widely used
|
||||
standard. This also increases the chances of interoperability between the
|
||||
OpenStack ecosystem and other communities that support JWT.
|
||||
|
||||
.. _`get changes into it`: https://github.com/fernet/spec/pull/13
|
||||
|
||||
Use Cases
|
||||
---------
|
||||
|
||||
* As a operator, I want to use a non-persistent token provider that isn't
|
||||
coupled to a symmetric encryption or signing implementation. An
|
||||
implementation built on asymmetric signing or encryption allows me to
|
||||
distribute public keys from one node to another instead of syncing a
|
||||
repository of symmetric keys. This makes it easier to deploy keystone nodes
|
||||
with read-only capabilities strictly used for token validation. The
|
||||
specific usecase for this allows me to deploy read-only regions keeping token
|
||||
validation within the region, while having tokens issued from a central
|
||||
identity management system in a separate region.
|
||||
|
||||
* As an operator, I want to be have a token provider to fall back on in the
|
||||
event there is a security vulnerability in the `fernet spec`_ or the
|
||||
`cryptography`_ implementation consumed by keystone.
|
||||
|
||||
* As a user, I want to be able to authenticate for a token that I can use with
|
||||
other pieces of software outside of the OpenStack ecosystem that prove my
|
||||
identity.
|
||||
|
||||
.. _`fernet spec`: https://github.com/fernet/spec/blob/master/Spec.md
|
||||
.. _`cryptography`: https://github.com/pyca/cryptography
|
||||
|
||||
Proposed Change
|
||||
===============
|
||||
|
||||
Create a new non-persistent keystone token backend based on the `JSON Web Token
|
||||
standard`_. These will behave in much the same way as our current fernet tokens
|
||||
do.
|
||||
|
||||
The token will be a signed JWT (`JWS`_) containing the authentication payload.
|
||||
Note that signed tokens are web safe and integrity verified, but token payload
|
||||
is not opaque to its holder. It is possible to decode a token and inspect the
|
||||
payload with `JWS`_ tokens. Using nested `JWE`_ tokens are the JSON Web Token
|
||||
equivalent to Fernet tokens and they are encrypted and signed.
|
||||
|
||||
This implementation reserves the right to change, modify, or remove items in
|
||||
the payload at any point in time and for any reason. Decoding and relying on
|
||||
attributes within the payload is not a supported API, nor should it be assumed
|
||||
as one. Users should use formal APIs to request information from keystone. The
|
||||
development team will not prevent or stall changes to token payloads, which are
|
||||
internal implementation details of the token provider, due to users relying on
|
||||
those attributes in ways they shouldn't. Likewise, deployment that consider
|
||||
information in the token payload sensitive should rely on Fernet to prevent
|
||||
that information from being exposed to users.
|
||||
|
||||
Similar to the Fernet, JWTs will require a key repository be set up to use for
|
||||
signing tokens. A new ``keystone-manage`` command will be added to handle
|
||||
secret generation and rotation which will likely re-use much of the utilities
|
||||
in the ``fernet_setup`` and ``fernet_rotate`` commands. The recommended
|
||||
algorithm to be used is ``ES256``. Keystone should not expose the ability to
|
||||
end users to ask for a specific JWS algorithm. Support should be limited to
|
||||
only supported or trusted algorithms that the end user cannot specify. JWS
|
||||
tokens will be integrity verified with a private key and validated using a
|
||||
corresponding public key. Since the ``ES256`` implementation only uses signing
|
||||
(as opposed to signed encrypted payloads), this adheres to slightly better
|
||||
security practices over fernet because private keys never have to be synced
|
||||
across keystone API nodes. Only public keys need to be transferred to other
|
||||
keystone API servers to validate tokens across a cluster.
|
||||
|
||||
The payload of the JWS will use the following `registered claims`_:
|
||||
|
||||
* the `sub` claim will be a **required** string containing the ID of the user
|
||||
who authenticated for the token
|
||||
* the `exp` claim will be a **required** numeric value for token expiration
|
||||
* the `iat` claim will be a **required** numeric value for the time a token was
|
||||
issued
|
||||
|
||||
The following private claims will be used to relay additional required
|
||||
information and will be prefixed with `openstack` to avoid collisions with
|
||||
future upstream claims:
|
||||
|
||||
* `openstack_methods` will be a **required** claim denoting the authentication
|
||||
methods used to obtain the token
|
||||
* `openstack_audit_ids` will be a **required** claim containing the audit
|
||||
information associated to a token
|
||||
* `openstack_system` will be an **optional** claim only present in
|
||||
system-scoped tokens
|
||||
* `openstack_domain_id` will be an **optional** claim only present in
|
||||
domain-scoped tokens
|
||||
* `openstack_project_id` will be an **optional** claim only present in
|
||||
project-scoped tokens
|
||||
* `openstack_trust_id` will be an **optional** claim only present in
|
||||
trust-scoped tokens
|
||||
* `openstack_app_cred_id` will be an **optional** claim only present in
|
||||
application credential tokens
|
||||
* `openstack_group_ids` will be an **optional** claim only present in federated
|
||||
tokens to carry an ephemeral user's group assignments
|
||||
* `openstack_idp_id` will be an **optional** claim only present in federated
|
||||
tokens to carry the ID of a user's identity provider
|
||||
* `openstack_protocol_id` will be an **optional** claim only present in
|
||||
federated tokens to denote the protocol used by a federated user to
|
||||
authenticate
|
||||
* `openstack_access_token` will be an **optional** claim only present in OAuth
|
||||
tokens
|
||||
|
||||
The `PyJWT library`_ is already present in the requirements repository and
|
||||
would be a convenient choice to use for this implementation. Both the `PyJWT
|
||||
library`_ and the `JWCrypto library`_ implement support for JWS. Since the
|
||||
implementation detailed in this specification is unique to ``ES256``, a library
|
||||
that supports JWE isn't necessary. If supporting another encrypted token type,
|
||||
like fernet, is a requirement in the future, then finding or contributing JWE
|
||||
support to the consuming library would be necessary.
|
||||
|
||||
Users will request and present tokens in exactly the same way they currently do
|
||||
with Fernet tokens. There is no need to add or change any APIs.
|
||||
|
||||
.. _`JSON Web Token standard`: https://tools.ietf.org/html/rfc7519
|
||||
.. _`JWS`: https://tools.ietf.org/html/rfc7515
|
||||
.. _`JWE`: https://tools.ietf.org/html/rfc7516
|
||||
.. _`registered claims`: https://tools.ietf.org/html/rfc7519#section-4.1
|
||||
.. _`Python libraries`: https://jwt.io/#libraries
|
||||
.. _`PyJWT library`: https://pyjwt.readthedocs.io/en/latest/
|
||||
.. _`does not yet support JWE`: https://github.com/jpadilla/pyjwt/issues/143
|
||||
.. _`JWCrypto library`: http://jwcrypto.readthedocs.org/
|
||||
|
||||
Key Setup & Rotation
|
||||
--------------------
|
||||
|
||||
Much like the Fernet implementation, a JWT provider will require a key rotation
|
||||
strategy. Since ``ES256`` relies on asymmetric signing, the suggested rotation
|
||||
strategy will be slightly different than what is known with Fernet.
|
||||
|
||||
The Fernet implementation requires the usage of a staged key, which is just a
|
||||
key with a special name, in order to ensure tokens can be validated during the
|
||||
rotation process. This won't be required with JWT and the following steps
|
||||
should be sufficient to perform key rotation without token invalidation due to
|
||||
missing signing keys. Assume the following steps are being performed on three
|
||||
different API servers, named `K1`, `K2`, and `K3`, that need to validate
|
||||
tokens issued by each other.
|
||||
|
||||
1. A key pair is created for each API server. `K1.private`, `K1.pub` for
|
||||
`K1`, `K2.private`, `K2.pub` for `K2`, and `K3.private`, `K3.pub` for `K3`.
|
||||
2. A copy of each public key is transferred to each API server. `K1`, `K2`, and
|
||||
`K3` all have copies of `K1.pub`, `K2.pub`, and `K3.pub`.
|
||||
|
||||
At this point, tokens issued from any API server can be validated anywhere. In
|
||||
the event a single API server needs to rotate keypairs:
|
||||
|
||||
1. A new key pair is created for `K1` called `K1-new.private` and `K1-new.pub`.
|
||||
`K1` is configured to start signing tokens with both `K1.private` and
|
||||
`K1-new.private.`
|
||||
2. `K1-new.pub` is copied to the public key repository of each API server. So
|
||||
long as `K2` and `K3` have either `K1.pub` or `K1-new.pub` they can validate
|
||||
tokens issued by `K1`.
|
||||
3. After `K2` and `K3` have been updated with copies of `K1-new.pub`,
|
||||
`K1.private` can be removed from `K1` and `K1.pub` can be removed from `K2`
|
||||
and `K3`. Tokens that were signed with only `K1.private` are unable to be
|
||||
verified and `K1.pub` should only be removed after those tokens have expired
|
||||
anyway.
|
||||
|
||||
Traditional asymmetric keys can be revoked using revocation lists. At this time
|
||||
we are not going to support a revocation list implementation for JWT key pairs.
|
||||
The operator has the ability to sync public keys accordingly when they rotate
|
||||
new keys in and out. Keystone will only use the public keys on disk to validate
|
||||
tokens. Is could change in the future, but for now it keeps the key rotation
|
||||
and key utilities with keystone simpler.
|
||||
|
||||
Crypto-Agility & Future Work
|
||||
----------------------------
|
||||
|
||||
This specification is targeting a single algorithm for the initial JWT
|
||||
implementation. If and when keystone decides to expand the implementation to
|
||||
include additional algorithms, we should allow for flexibility between
|
||||
configured algorithms, which will make it easier for operators to switch from
|
||||
one algorithm to another if they need to.
|
||||
|
||||
For example, the validation process using a JWT token provider might support
|
||||
validating multiple blessed algorithms, allowing multiple tokens signed with
|
||||
different algorithms to be validated without require configuration changes
|
||||
except on the signing node.
|
||||
|
||||
Alternatives
|
||||
------------
|
||||
|
||||
Recently, there have been various efforts that help solve authenticated
|
||||
encryption. One of these efforts was sparked by a `concern`_ with JWT, namely
|
||||
the `JOSE`_ header. The issue detailed in the report was specific to users
|
||||
being able to specify algorithms and exploit a validation weakness in various
|
||||
JWT libraries. All python libraries have been patched, but keystone should
|
||||
specifically rely on validating algorithm usage and never assuming algorithms
|
||||
to be supplied by end users. Please see the full `report`_ for details on the
|
||||
vulnerability and why we are going to strictly validate this information.
|
||||
|
||||
There is a proof-of-concept implementation for Platform Agnostic Security
|
||||
Tokens, or `PASETO`_ that takes a more strict stance on algorithm validation
|
||||
and the intended audience of the token. The strict stance of `versioned
|
||||
protocols` with `PASETO`_ is certainly advantageous, but the implementation and
|
||||
idea are still in the incipient stage. It's certainly worth noting that we
|
||||
should keep out eye on this development and re-evaluate it if, or when, it gets
|
||||
more adoption.
|
||||
|
||||
For now, if keystone supplies strict algorithm validation to the JWT
|
||||
implementation, we should be able to offer a comparable backup option to
|
||||
fernet.
|
||||
|
||||
.. _`concern`: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
||||
.. _`report`: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
||||
.. _`JOSE`: https://tools.ietf.org/html/rfc7519#section-5
|
||||
.. _`PASETO`: https://github.com/paragonie/paseto
|
||||
|
||||
Security Impact
|
||||
---------------
|
||||
|
||||
Since JWT is a widely used web standard, this will have a net positive impact
|
||||
on security. The implementation will use asymmetric signing, reducing risk of
|
||||
having to replicate or transfer private keys from one host to another. Since
|
||||
the token payloads are signed, data within the token will be readable to anyone
|
||||
who has the token. The token can only be validated using the corresponding
|
||||
public key of the private key used to sign the token originally. These will
|
||||
still be bearer tokens and so interception of one must still be guarded
|
||||
against.
|
||||
|
||||
Known Vulnerabilities
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
There is a documented `vulnerability`_ that affected several JWT libraries,
|
||||
including one library written in Python.
|
||||
|
||||
In most cases, JSON Web Tokens will have a header, payload, and signature where
|
||||
each section is delimited by a period (``.``). The header contains an important
|
||||
piece of information, which is how the token's integrity is protected. This is
|
||||
stored as the ``alg`` attribute of the header. The library verifying the token
|
||||
uses the algorithm specified in the header to perform an integrity check and
|
||||
compares its results to the signature portion of the token.
|
||||
|
||||
Security concerns have been documented and raised that describe the issues with
|
||||
allowing clients to dictate algorithms used for token verification. This is a
|
||||
concern specifically with applications that support asymmetric and symmetric
|
||||
signing. An attacker could effectively bypass the verification check of a
|
||||
token by using a published, or known, public key to generate a JWT with a
|
||||
symmetric signing algorithm.
|
||||
|
||||
This would be applicable if keystone supported signed tokens and encrypted
|
||||
tokens with the same token provider implementation. This vulnerability has been
|
||||
addressed across various libraries after its discovery, but keystone should be
|
||||
aware of the overall technique that lead to it in the first place. We can
|
||||
mitigate this type of vulnerability in keystone by:
|
||||
|
||||
* Ensuring keystone doesn't blindly allow end users to specify which algorithm
|
||||
is used to verify the integrity of a token (e.g., only implementing support
|
||||
for ``ES256``)
|
||||
* Ensure the ``alg`` supplied in the token header is only ever populated by
|
||||
keystone
|
||||
* Ensure keystone only issues tokens of a single encryption or signing strategy
|
||||
(e.g., not allowing users to get signed token and encrypted tokens from the
|
||||
same server, thus mixing asymmetric and symmetric key usage at runtime)
|
||||
|
||||
Specifics about the `vulnerability`_ can be found in the report.
|
||||
|
||||
.. _`vulnerability`: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
||||
|
||||
Notifications Impact
|
||||
--------------------
|
||||
|
||||
Notifications for JWTs will behave in the same way that they do for fernet
|
||||
tokens, including for revocation events.
|
||||
|
||||
Other End User Impact
|
||||
---------------------
|
||||
|
||||
This will have no end user impact. They will request and use JWTs in exactly
|
||||
the same way that they currently use fernet tokens.
|
||||
|
||||
Performance Impact
|
||||
------------------
|
||||
|
||||
It will be worth investigating performance differences between token providers
|
||||
that use asymmetric signing (JWT) and symmetric encryption (fernet). These
|
||||
difference, if significant, should be published in documentation as it might be
|
||||
useful for operators when choosing a token provider.
|
||||
|
||||
Other Deployer Impact
|
||||
---------------------
|
||||
|
||||
This is an optional, opt-in feature that will not be the default, so deployers
|
||||
will not be affected unless they choose to use JWT. In that case, deployers
|
||||
will need to set up a key repository before using JWTs. The key repository will
|
||||
contain asymmetric key pairs rather than just secret keys. The deployer will
|
||||
need to take care to sync and rotate keys the way they do with fernet tokens.
|
||||
|
||||
Developer Impact
|
||||
----------------
|
||||
|
||||
The new token type will reuse much of the work already done for fernet tokens
|
||||
and will follow similar code paths, so this will be relatively easy to
|
||||
maintain.
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
Assignee(s)
|
||||
-----------
|
||||
|
||||
Primary assignee:
|
||||
Gage Hugo (gagehugo)
|
||||
Lance Bragstad (lbragstad)
|
||||
XiYuan Wang (wxy)
|
||||
|
||||
Work Items
|
||||
----------
|
||||
|
||||
* Refactor the fernet utilities modules to be generic enough to work with JWT
|
||||
or inheritable
|
||||
* Add a ``keystone-manage`` command to set up and rotate JWT signing keys
|
||||
* Generalize the ``TokenFormatter`` class to support JWT
|
||||
* Refactor the fernet token provider module to be inheritable or generic
|
||||
* Add a keystone doctor command to validate the setup in the same way that
|
||||
fernet is validated
|
||||
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
There are three different libraries we can use to implement this functionality.
|
||||
|
||||
1. `PyJWT`_
|
||||
|
||||
This library only supports token signing, or JWS. It does not support JWE,
|
||||
or authenticated encryption, yet. A minimum version of **1.0.1** is
|
||||
`required`_, but this library is already included in OpenStack global
|
||||
requirements repository.
|
||||
|
||||
2. `python-jose`_
|
||||
|
||||
This library only supports token signing, or JWS. It does not support JWE,
|
||||
or authenticated encryption, yet. This library is not included in OpenStack
|
||||
global requirements.
|
||||
|
||||
3. `JWCrypto`_
|
||||
|
||||
This library supports both JWS and JWE, but it is not included in OpenStack
|
||||
global requirements.
|
||||
|
||||
3. `Authlib`_
|
||||
|
||||
This library supports both JWS and JWE, but its licensing is incompatible
|
||||
with OpenStack as it is AGPL.
|
||||
|
||||
Given the fact that the initial implementation of JWT is not going to rely on
|
||||
nested JWT tokens or encrypted payloads, it's safe to assume that signing
|
||||
support will be sufficient. The PyJWT library is already included in global
|
||||
requirements and we don't have a case to not use that specific library, which
|
||||
is compatible with OpenStack licensing.
|
||||
|
||||
.. _`PyJWT`: https://pyjwt.readthedocs.io/en/latest/
|
||||
.. _`required`: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
||||
.. _`python-jose`: https://python-jose.readthedocs.io/en/latest/
|
||||
.. _`JWCrypto`: http://jwcrypto.readthedocs.io/en/latest/
|
||||
.. _`Authlib`: https://docs.authlib.org/en/latest/
|
||||
|
||||
Documentation Impact
|
||||
====================
|
||||
|
||||
The new ``[token]/provider`` configuration option will need to be documented,
|
||||
as will the new ``keystone-manage`` commands.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
* `JSON Web Token RFC <https://tools.ietf.org/html/rfc7519>`_
|
||||
* `JSON Web Token light introduction <https://jwt.io/introduction/>`_
|
||||
* `History of cryptography's adoption of fernet <https://github.com/pyca/cryptography/issues/2900>`_
|
Loading…
Reference in New Issue