Merge "External OAuth2.0 Authorization Server Support"

This commit is contained in:
Zuul 2023-06-14 19:35:21 +00:00 committed by Gerrit Code Review
commit 330200b4d8
2 changed files with 352 additions and 2 deletions

View File

@ -79,14 +79,14 @@ keystoneclient approved specs for the Newton release:
keystonemiddleware
------------------
keystonemiddleware approved specs for the Xena release:
keystonemiddleware approved specs for the 2023.1 release:
.. toctree::
:glob:
:maxdepth: 1
specs/keystonemiddleware/xena/*
specs/keystonemiddleware/2023.1/*
Implemented Identity Program Specifications
===========================================
@ -243,6 +243,14 @@ Liberty implemented specs:
keystonemiddleware
------------------
Xena approved specs:
.. toctree::
:glob:
:maxdepth: 1
specs/keystonemiddleware/xena/*
Kilo implemented specs:
.. toctree::

View File

@ -0,0 +1,342 @@
..
This work is licensed under a Creative Commons Attribution 3.0 Unported
License.
http://creativecommons.org/licenses/by/3.0/legalcode
==============================================
External OAuth2.0 Authorization Server Support
==============================================
Provides a capability for the third-party Clients authenticated by an
External Authorization Server via the Client Credentials
Grant in `RFC6749 OAuth 2.0 Authorization Framework` [#oauth2_specification]_
to access the protected OpenStack service directly.
Problem Description
===================
Some OpenStack services allow deploying itself as a standalone service, e.g.,
Tacker, Ironic, etc. In such a situation, users might want to use a third-party
authorization server (such as Keycloak [#keycloak]_). This is theoretically
possible by leveraging OAuth2.0 which has been available from Keystone Zed,
however, is actually not possible yet as the Keystone Middleware only supports
Keystone as an authorization server for the token introspection (a.k.a., the
token validation). Unfortunately, the Keystone Zed doesn't have an effective
way to solve this problem. Thus, to effectively use OAuth2.0, the Keystone
Middleware should support the generic method for token introspection.
Proposed Change
===============
The proposed change is to add a new Keystone Middleware that implements RFC7662
OAuth 2.0 Token Introspection [#token_introspection]_ and allows users to
optionally select that middleware to use an external authorization server.
Terminology
-----------
- *External Authorization Server:* The authorization server that is not
included in OpenStack services and supports OAuth2.0 Client Credentials
Grant. This server handle authentication/authorization for a standalone
OpenStack service instead of Keystone.
- *User:* The Users that have access to the External Authorization Server and
are permitted to create OAuth2.0 clients.
- *Client:* The OAuth2.0 clients that use APIs of the External Authorization
Server. There can be at least two clients: (i) OpenStack clients that obtain
access tokens via the token API to access the protected
OpenStack service on behalf of the user; (ii) Keystone Middleware that
verifies the access token, which is sent from OpenStack clients, on behalf of
OpenStack services.
- *Access Token:* A OAuth2.0 access token used by the Clients to make protected
resource requests with the delegated roles from a User.
- *Client credentials:* The credential used by the application with a grant
type of Client Credentials. With this credential, the application can access
APIs provided by the External Authorization Server.
.. note:: In the Client Credentials Grant, there is no clear distinction
between the Users and Clients. The Users and Clients can be replaced with, for
example, admin users and non-admin users.
Preparation for OAuth2.0 Client Credentials Grant
-------------------------------------------------
.. seqdiag::
seqdiag {
User; AuthServer [label = "External\nAuthorization\nServer"];
User -> AuthServer
[label = "1. create client credentials"];
User <-- AuthServer
[label = "client credentials"];
}
The preparation consists of the following step as illustrated in the above
sequence:
#. A User creates a Client with its credentials, and sets up relevant
information for resource access control, such as roles, groups, scopes,
tokens, certificates, etc.
OAuth2.0 Client Credentials Grant Flow with External Authorization Server
-------------------------------------------------------------------------
.. seqdiag::
seqdiag {
Client; AuthServer [label = "External\nAuthorization\nServer"]; "Keystone Middleware"; "OpenStack Service";
Client -> AuthServer
[label = "POST\n /external-authz-server/token\n with client credentials for the Client"];
Client <-- AuthServer
[label = "Response 200 OK\n with Access Token"];
Client -> "Keystone Middleware"
[label = "2. request\n OpenStack Service endpoint\n with Access Token"];
"Keystone Middleware" -> AuthServer
[label = "3. POST\n /external-authz-server/introspect\n with client credentials for the Keystone Middleware\n and the Access Token"];
"Keystone Middleware" <-- AuthServer
[label = "Response 200 OK\n with Access Token metadata"];
"Keystone Middleware" -> "Keystone Middleware"
[label = "4. parse\n the necessary\n information\n from the metadata"];
"Keystone Middleware" -> "Keystone Middleware"
[label = "5. set\n request.environ\n with the necessary\n information"];
"Keystone Middleware" -> "Keystone Middleware"
[label = "6. cache\n token and metadata (Optional)"];
"OpenStack Service" <-- "Keystone Middleware"
[label = "return request.environ\n with the necessary\n information"];
"OpenStack Service" -> "OpenStack Service"
[label = "7. continue\n OpenStack\n Service\n processing"];
"Client" <-- "OpenStack Service"
[label = "API response"];
}
The flow consists of the following steps as illustrated in the above sequence:
#. The Client authenticates with the External Authorization Server and requests
a new Access Token.
#. The Client uses the Access Token to make requests for OpenStack Service
APIs.
#. The Keystone Middleware intercepts HTTP calls from the Client and calls an
introspection API of the External Authorization Server to verify if the
Access Token is active or not and to obtain the metadata for the Access
Token. If the validation fails, Keystone Middleware sends an error response
to the client, such as ``401 Unauthorized``. Prior to the token
introspection, the Keystone Middleware has to authenticate with the External
Authorization Server. Although RFC7662 mentioned the methods of such
authentication as out of scope, it is natural to assume OAuth2.0 Client
Credentials Grant is used. In this sense, Keystone Middleware needs to
support the multiple authentication methods that is generally supported by
the authorization servers, such as ``tls_client_auth``,
``client_secret_basic``, ``client_secret_post``, ``client_secret_jwt``,
``private_key_jwt``, etc. This step is skipped if unexpired token cache
which is described later is available.
#. The Keystone Middleware uses the mapping definition in the config file to
parse all the necessary information from the metadata. If the parsing fails,
the Keystone Middleware sends an error response such as ``403 Forbidden`` to
the Client. In the case where unexpired token cache which is described later
is available, Keystone Middleware loads metadata from memcache server.
#. Keystone Middleware sets the environment variables in the OpenStack service
HTTP request with the required information.
#. In the case, a memcache server [#memcache]_ is configured, Keystone
Middleware cache a token.
#. After the verification of the access token, the OpenStack service applies
the matching policy according to the request environment variable, and
continues the subsequent business processing. If the environment variable
doesn't match the policy to access the requested resources, OpenStack
Service returns an error response such as ``403 Forbidden``. Finally, it
sends the response to the Client.
.. note::
OAuth2.0 doesn't support users who are associated with multiple tenants like
the project of OpenStack. Therefore, this feature assumes that users
registered on an external authorization server are associated only with a
single tenant (e.g., realms in Keycloack).
.. note::
This feature only support the authorization servers that can provide enough
information for OpenStack services to work correctly. At least,
``user_role``, ``project`` and ``user_domain`` should be included in the
metadata of token introspection.
Alternatives
------------
* The delegated mode in the Keystone Middleware [#delegated_mode]_ can be used
to handle request that needs an external authorization server. In this case,
no changes to the Keystone Middleware are needed and an API server will
perform the token introspection instead. However, the proposed features in
the present document doesn't impair the current Keystone Middleware, but
rather is beneficial feature for the OpenStack users who want to use
OAuth2.0.
* The Keystone already cover the authentication in the stand alone mode service
by supporting the basic authentication in the keystoneauth [#basic]_.
However, the basic authentication is now no longer secure.
Security Impact
---------------
* During the OAuth2.0 Client Credentials Grant flow, some sensitive values are
sent in plain text. Therefore, it is recommended for users configure
keystonemiddleware to use HTTPS-enabled endpoint for the token introspection.
Notifications Impact
--------------------
None
Other End User Impact
---------------------
* Enables the use OAuth2.0 access token for the External Authorization Server
from the settings of Keystone Middleware without using API. These
configurations are shown in the part of Other Deployer Impact.
Performance Impact
------------------
None
Other Deployer Impact
---------------------
Configuration of Keystone Middleware
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To use OAuth2.0 access token for the External Authorization Server, a deployer
has to configure Keystone Middleware by changing ``[filter:authtoken]`` in
``/etc/tacker/api-paste.ini`` as shown below.
::
[filter:authtoken]
paste.filter_factory=keystonemiddleware.external_oauth2_token:filter_factory
.. note:: If the Openstack services require authorization to an external
authorization server through Keystone Middleware, the config for each
service must be changed. This section shows how to set up Tacker as an
example.
In order for Keystone Middleware to access the External Authentication Server
for token verification and to obtain metadata, users has to configure Keystone
Middleware by appending some options in ``/etc/tacker/tacker.conf`` as shown
below. In this example, the Keycloak is the external authorization server.
Regarding the option ``auth_method`` can be the following methods:
``tls_client_auth``, ``client_secret_basic``, ``client_secret_post``,
``client_secret_jwt``, ``private_key_jwt``. The fields named ``mapping_*``
specify the mapping between metadata obtained from External Authorization
Server to OpenStack Services variables. For example, with
``mapping_project_id=tenant_id``, Keystone Middleware retrieves a value with a
key ``tenant_id`` from the metadata returned from the authorization server and
sets that value as an environment variable ``HTTP_X_PROJECT_ID`` in a request.
Also note that a memcache server can be configured with the
``memcached_servers`` attribute in the same way as the current
keystonemiddleware.
::
[keystone_authtoken]
memcached_servers=localhost:11211
introspect_endpoint=https://keycloak/protocol/openid-connect/token/introspect
auth_method=client_secret_basic
client_id=tacker_client_id
client_secret=tacker_client_secret
jwt_key_file=/opt/stack/jwt.pem
jwt_algorithm=S256
# the mapping from metadata obtained from External Authorization Server to OpenStack Services variables
mapping_project_id=tenant_id
mapping_project_name=tenant_name
mapping_project_domain_id=domain_id
mapping_project_domain_name=domain_name
mapping_user_id=user_id
mapping_user_name=username
mapping_user_domain_id=domain_id
mapping_user_domain_name=domain_name
mapping_roles=roles
audience=https://<keycloak_host>:<port>/realms/<realm_name>
jwt_bearer_time_out=3600
# In the case where mTLS OAuth2.0 is used, the following variables also have to be set
# auth_method=tls_client_auth
# cacert=/opt/stack/keycloak_ca.pem
# key=/opt/stack/tacker_client.key
# cert=/opt/stack/tacker_client.pem
Developer Impact
----------------
* Developers should create appropriate mapping rules between user attributes
(such as tenant names) defined in an external authorization server they want
to use and attributes used by OpenStack service for the access control
* There is no impact on other Openstack developers and backend services unless
they want to use OAuth2.0 with an External Authorization Server.
.. warning:: Some OpenStack services might have to change their codes to use
this plugin. The most likely reason for such changes is the lack of a
service catalog. The services using other services APIs have to get the
similar information that service catalog provides in the different way, for
example, getting them from configuration.
Implementation
==============
Assignee(s)
-----------
Primary assignee:
* Hiromu Asahina (hiromu a.k.a h-asahina) <hiromu.asahina.az@hco.ntt.co.jp>
Other contributors:
* Yuta Kazato (yuta-kazato) <yuta.kazato.nw@hco.ntt.co.jp>
* Yusuke Niimi <niimi.yusuke@fujitsu.com>
* Keiichiro Yamakawa <yamakawa.keiich@fujitsu.com>
Work Items
----------
* Add a new Keystone Middleware that can send Introspection Request
in RFC7662 Sec. 2.1 and can retrieve necessary metadata for
an API server from Introspection Response in RFC7662 Sec. 2.2
* Add unit tests for the new Keystone Middleware
* Add integration test cases (e.g., tempest [#tempest]_) for the new Keystone
Middleware
* Change API Keystone Middleware documentation.
Dependencies
============
None
Documentation Impact
====================
* We would need to update API Keystone Middleware documents
and Middleware Architecture.
References
==========
.. [#oauth2_specification] https://tools.ietf.org/html/rfc6749
.. [#keycloak] https://www.keycloak.org/
.. [#token_introspection] https://datatracker.ietf.org/doc/html/rfc7662
.. [#memcache] https://docs.openstack.org/keystonemiddleware/latest/middlewarearchitecture.html#improving-response-time
.. [#delegated_mode] https://docs.openstack.org/keystonemiddleware/latest/middlewarearchitecture.html
.. [#tempest] https://docs.openstack.org/tempest/latest/index.html
.. [#basic] https://docs.openstack.org/keystoneauth/latest/plugin-options.html#http-basic