外部 OAuth2.0 授权服务器支持¶
提供了一种能力,允许通过《RFC6749 OAuth 2.0 授权框架》[1] 中的客户端凭证授权方式,由外部授权服务器认证的第三方客户端访问受保护的 OpenStack 服务。
问题描述¶
一些 OpenStack 服务允许自身作为独立服务部署,例如 Tacker、Ironic 等。在这种情况下,用户可能希望使用第三方授权服务器(例如 Keycloak [2])。从理论上讲,这可以通过利用 Keystone Zed 中提供的 OAuth2.0 来实现,但实际上目前尚不可行,因为 Keystone 中间件仅支持 Keystone 作为令牌内省(又称令牌验证)的授权服务器。不幸的是,Keystone Zed 没有有效的方法来解决这个问题。因此,为了有效地使用 OAuth2.0,Keystone 中间件应该支持通用的令牌内省方法。
提议的变更¶
建议的更改是添加一个新的 Keystone 中间件,该中间件实现 RFC7662 OAuth 2.0 令牌内省 [3],并允许用户选择性地使用该中间件来使用外部授权服务器。
术语¶
外部授权服务器: 不包含在 OpenStack 服务中,并支持 OAuth2.0 客户端凭证授权的授权服务器。该服务器代替 Keystone 为独立的 OpenStack 服务处理身份验证/授权。
用户: 具有访问外部授权服务器权限并被允许创建 OAuth2.0 客户端的用户。
客户端: 使用外部授权服务器 API 的 OAuth2.0 客户端。至少可以有两个客户端:(i)通过令牌 API 获取访问令牌以代表用户访问受保护的 OpenStack 服务的 OpenStack 客户端;(ii)验证从 OpenStack 客户端发送的访问令牌的 Keystone 中间件,代表 OpenStack 服务。
访问令牌: 客户端用于使用来自用户的委托角色对受保护资源提出请求的 OAuth2.0 访问令牌。
客户端凭证: 应用程序使用的,授权类型为客户端凭证的凭证。使用此凭证,应用程序可以访问外部授权服务器提供的 API。
注意
在客户端凭证授权中,用户和客户端之间没有明确的区别。用户和客户端可以替换为例如管理员用户和非管理员用户。
OAuth2.0 客户端凭证授权准备¶
准备过程包括以下步骤,如上图所示
用户创建带有其凭证的客户端,并设置相关信息以进行资源访问控制,例如角色、组、作用域、令牌、证书等。
使用外部授权服务器的 OAuth2.0 客户端凭证授权流程¶
流程包括以下步骤,如上图所示
客户端使用外部授权服务器进行身份验证并请求新的访问令牌。
客户端使用访问令牌对 OpenStack 服务 API 提出请求。
Keystone 中间件拦截来自客户端的 HTTP 调用,并调用外部授权服务器的内省 API,以验证访问令牌是否有效,并获取访问令牌的元数据。如果验证失败,Keystone 中间件将向客户端发送错误响应,例如
401 Unauthorized。在令牌内省之前,Keystone 中间件必须使用外部授权服务器进行身份验证。虽然 RFC7662 提到这种身份验证的方法不在范围内,但自然可以假设使用 OAuth2.0 客户端凭证授权。因此,Keystone 中间件需要支持授权服务器通常支持的多种身份验证方法,例如tls_client_auth、client_secret_basic、client_secret_post、client_secret_jwt、private_key_jwt等。如果可用未过期的令牌缓存(如下所述),则跳过此步骤。Keystone 中间件使用配置文件中的映射定义来解析所有必要的元数据信息。如果解析失败,Keystone 中间件将向客户端发送错误响应,例如
403 Forbidden。如果可用未过期的令牌缓存(如下所述),Keystone 中间件将从 memcache 服务器加载元数据。Keystone 中间件在 OpenStack 服务 HTTP 请求中设置环境变量,其中包含所需的信息。
如果配置了 memcache 服务器 [4],Keystone 中间件会缓存一个令牌。
在验证访问令牌后,OpenStack 服务将根据请求环境变量应用匹配策略,并继续后续业务处理。如果环境变量与访问请求资源的策略不匹配,OpenStack 服务将返回错误响应,例如
403 Forbidden。最后,它将响应发送给客户端。
注意
OAuth2.0 不支持与 OpenStack 项目(例如租户)关联的多个用户。因此,此功能假定在外部授权服务器上注册的用户仅与单个租户(例如 Keycloak 中的领域)关联。
注意
此功能仅支持可以为 OpenStack 服务提供足够信息的授权服务器。至少,令牌内省的元数据中应包含 user_role、project 和 user_domain。
备选方案¶
安全影响¶
在 OAuth2.0 客户端凭证授权流程期间,一些敏感值以明文形式发送。因此,建议用户配置 keystonemiddleware 以使用启用 HTTPS 的端点进行令牌内省。
通知影响¶
无
其他最终用户影响¶
启用从 Keystone 中间件设置中使用的外部授权服务器的 OAuth2.0 访问令牌,而不使用 API。这些配置显示在其他部署者影响部分中。
性能影响¶
无
其他部署者影响¶
Keystone 中间件配置¶
要使用外部授权服务器的 OAuth2.0 访问令牌,部署者必须通过更改 [filter:authtoken] 在 /etc/tacker/api-paste.ini 中配置 Keystone 中间件,如下所示。
[filter:authtoken]
paste.filter_factory=keystonemiddleware.external_oauth2_token:filter_factory
注意
如果 Openstack 服务需要通过 Keystone 中间件向外部授权服务器进行授权,则必须更改每个服务的配置。本节以设置 Tacker 为例。
为了使 Keystone 中间件能够访问外部身份验证服务器进行令牌验证并获取元数据,用户必须通过在 /etc/tacker/tacker.conf 中追加一些选项来配置 Keystone 中间件,如下所示。在本例中,Keycloak 是外部授权服务器。对于 auth_method 选项,可以使用以下方法:tls_client_auth、client_secret_basic、client_secret_post、client_secret_jwt、private_key_jwt。名为 mapping_* 的字段指定外部授权服务器获取的元数据与 OpenStack 服务变量之间的映射。例如,使用 mapping_project_id=tenant_id,Keystone 中间件将从授权服务器返回的元数据中检索具有键 tenant_id 的值,并将该值设置为请求中的环境变量 HTTP_X_PROJECT_ID。 另外请注意,可以使用与当前 keystonemiddleware 相同的方式使用 memcached_servers 属性配置 memcache 服务器。
[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
开发人员影响¶
开发人员应创建适当的映射规则,在他们想要使用的外部授权服务器中定义的用户属性(例如租户名称)与 OpenStack 服务用于访问控制的属性之间。
除非他们希望使用具有外部授权服务器的 OAuth2.0,否则其他 Openstack 开发人员和后端服务不会受到影响。
警告
一些 OpenStack 服务可能需要更改其代码才能使用此插件。这种更改的最可能原因是缺少服务目录。使用其他服务 API 的服务必须以不同的方式获取服务目录提供的类似信息,例如从配置中获取它们。
实现¶
负责人¶
- 主要负责人
朝陽弘 (hiromu a.k.a h-asahina) <hiromu.asahina.az@hco.ntt.co.jp>
- 其他贡献者
風戸和人 (yuta-kazato) <yuta.kazato.nw@hco.ntt.co.jp>
新見雄介 <niimi.yusuke@fujitsu.com>
山川圭一朗 <yamakawa.keiich@fujitsu.com>
工作项¶
添加一个新的 Keystone 中间件,该中间件可以发送 RFC7662 Sec. 2.1 中的内省请求,并可以从 RFC7662 Sec. 2.2 中的内省响应中检索 API 服务器所需的元数据
为新的 Keystone 中间件添加单元测试
为新的 Keystone 中间件添加集成测试用例(例如 tempest [6])
更改 API Keystone 中间件文档。
依赖项¶
无
文档影响¶
我们需要更新 API Keystone 中间件文档和中间件架构。