From 4dd8dfab34863240bd31d8ec70b5f0d33fa58524 Mon Sep 17 00:00:00 2001 From: Hiromu Asahina Date: Mon, 17 Oct 2022 12:11:52 +0900 Subject: [PATCH] External OAuth2.0 Authorization Server Support This spec proposes to to add a new keystone middleware that implements RFC7662 OAuth 2.0 Token Introspection [1] and allows users to optionally use that middleware when using an external authorization server. OpenStack services will be able to validate their OAuth2.0 client with an external authorization server other than Keystone. [1] https://datatracker.ietf.org/doc/html/rfc7662 Change-Id: Ie1066ab2735205fcb534e7697c3b9a5aa2d23eeb --- doc/source/index.rst | 12 +- ...entication_server_oauth2_grant_support.rst | 342 ++++++++++++++++++ 2 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 specs/keystonemiddleware/2023.1/external_authentication_server_oauth2_grant_support.rst diff --git a/doc/source/index.rst b/doc/source/index.rst index ab4e8b3e..f3fba870 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -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 =========================================== @@ -235,6 +235,14 @@ Liberty implemented specs: keystonemiddleware ------------------ +Xena approved specs: + +.. toctree:: + :glob: + :maxdepth: 1 + + specs/keystonemiddleware/xena/* + Kilo implemented specs: .. toctree:: diff --git a/specs/keystonemiddleware/2023.1/external_authentication_server_oauth2_grant_support.rst b/specs/keystonemiddleware/2023.1/external_authentication_server_oauth2_grant_support.rst new file mode 100644 index 00000000..6eac1b87 --- /dev/null +++ b/specs/keystonemiddleware/2023.1/external_authentication_server_oauth2_grant_support.rst @@ -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://:/realms/ + 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) + +Other contributors: + * Yuta Kazato (yuta-kazato) + * Yusuke Niimi + * Keiichiro Yamakawa + +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