第 9 章 在 RHOSO 中配置多域联邦身份验证
您可以在 OpenShift (RHOSO) Identity 服务(keystone)和 Dashboard (horizon)上配置 Red Hat OpenStack Services,以使用 OpenID Connect (OIDC)作为协议来提供多域联邦身份验证。多域联邦允许用户使用单点登录(SSO)登录 OpenStack 控制面板,并从多个外部身份提供程序(IdP)之一中进行选择。
9.1. 使用多个联邦身份提供程序部署 RHOSO 复制链接链接已复制到粘贴板!
多域联邦允许用户使用单点登录(SSO)登录 OpenShift (RHOSO) Dashboard 上的 Red Hat OpenStack Services,并从多个外部身份提供程序(IdP)中选择。
多个联邦 IdP 的 RHOSO 部署实施 Web SSO 身份验证流,因为 OpenStack CLI 不支持多个 IdP。
先决条件
- 已安装 RHOSO。
- 您在您的环境中配置了多个外部 OpenID Connect (OIDC) IdP。
流程
选择一个名称来唯一标识每个 IdP。
在这个示例中,有两个 IdP,它们的名称被引用为 <
idp_name_1> 和 <idp_name_2>。从每个 IdP 管理员获取以下设置:
-
此流程中引用的每个 IdP 的
FQDN作为 <fqdn_1> 和 <fqdn_2>。 -
此流程中引用的每个 IdP 的 federation
Realm Name作为 <realm_name_1> 和 <realm_name_2>。 -
此流程中引用的每个 IdP
的客户端 ID作为 <client_id_1> 和 <client_id_2>。 -
此流程中引用的每个 IdP
的客户端 Secret,作为 <client_secret_1> 和 <client_secret_2>。 -
此流程中引用的每个 IdP 的
Provider Metadata URL作为 <provider_metadata_url_1> 和 <provider_metadata_url_2>。
-
此流程中引用的每个 IdP 的
检索 Identity 服务(keystone)公共端点:
$ oc get keystoneapis.keystone.openstack.org -o json | jq '.items[0].status.apiEndpoints.public'此流程中将这个身份服务端点引用为 <
keystone_url>。为 IdP 管理员提供以下信息:
Web origin:
https://<keystone_url>重定向 URI:
https://<keystone_url>/v3/auth/OS-FEDERATION/websso/openid为每个 IdP 提供包含其唯一 IdP 名称的 URI,该名称必须以尾随
/结尾。您必须将每个 URI 发送到其对应的 IdP 管理员:https://<keystone_url>/v3/auth/OS-FEDERATION/identity_providers/<idp_name_1>/protocols/openid/websso/ https://<keystone_url>/v3/auth/OS-FEDERATION/identity_providers/<idp_name_2>/protocols/openid/websso/- 每个联邦客户端都必须启用 Implicit 流,而不是授权代码流。
为名为
keystone-httpd-override的 secret 创建自定义资源(CR)文件:apiVersion: v1 kind: Secret metadata: name: keystone-httpd-override namespace: openstack type: Opaque stringData: federation.conf: | # Example OIDC directives for the *public* endpoint OIDCClaimPrefix "OIDC-" OIDCResponseType "id_token" OIDCScope "openid email profile" OIDCClaimDelimiter ";" OIDCPassUserInfoAs "claims" OIDCPassClaimsAs "both" OIDCCryptoPassphrase "<crypto_pass>" OIDCRedirectURI "<keystone_url>/v3/redirect_uri/" OIDCMetadataDir "/var/lib/httpd/metadata" OIDCAuthRequestParams "prompt=login" <IfModule headers_module> <Location "/v3/local-logout/clear"> Header always add Set-Cookie "mod_auth_openidc_session=deleted; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=None" </Location> </IfModule> RewriteEngine On RewriteRule ^/v3/auth/OS-FEDERATION/identity_providers/(<idp_name_1>|<idp_name_2>)/protocols/openid/websso$ \ /v3/local-logout/clear [R=302,L] RewriteRule ^/v3/local-logout/clear$ \ /v3/auth/OS-FEDERATION/websso/openid [R=302,L,QSA,NE] <Location "/v3/auth/OS-FEDERATION/websso/openid"> AuthType openid-connect Require valid-user </Location> <Location "/v3/redirect_uri"> AuthType openid-connect Require valid-user </Location>重要OIDCRedirectURI参数的完整值必须以尾随/结尾。-
将
<crypto_pass> 替换为在加密 OpenID Connect 握手数据时要使用的用户定义的密码短语。 -
将
<keystone_url> 替换为在第 3 步中获取的 Identity 服务端点值。 -
将
<idp_name_1> 和 <idp_name_2> 替换为在第 1 步中指定的唯一 IdP 名称。 以下 OIDC 参数和相关 Apache 配置旨在提供支持多个 IdP 登录用户的最故障安全解决方案。因此,以前的会话不会被保存,用户必须在从仪表板注销后重新验证自己:
OIDCAuthRequestParams "prompt=login" <IfModule headers_module> <Location "/v3/local-logout/clear"> Header always add Set-Cookie "mod_auth_openidc_session=deleted; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=None" </Location> </IfModule> RewriteEngine On RewriteRule ^/v3/auth/OS-FEDERATION/identity_providers/(<idp_name_1>|<idp_name_2>)/protocols/openid/websso$ \ /v3/local-logout/clear [R=302,L] RewriteRule ^/v3/local-logout/clear$ \ /v3/auth/OS-FEDERATION/websso/openid [R=302,L,QSA,NE]如果您的多个联邦 IdP 部署中的用户不属于多个 IdP,则您可以允许用户重新打开仪表板,而无需提供任何身份验证。在这种情况下,您必须删除此 OIDC 参数,并提供不同的 Apache
LocationMatch配置来保存之前的会话。
-
将
创建
keystone-httpd-overridesecret:$ oc create -f keystone-httpd-override.yaml检索仪表板的 URL:
$ oc get horizons.horizon.openstack.org -o json | jq -r '.items[0].status.endpoint'使用以下 Ansible playbook 创建名为
federation-realm-data的 secret:- name: Download realm1 OpenID configuration ansible.builtin.uri: url: "<provider_metadata_url_1>" method: GET return_content: true validate_certs: false register: openid_wellknown_config1 - name: Download realm2 OpenID configuration ansible.builtin.uri: url: "<provider_metadata_url_2>" method: GET return_content: true validate_certs: false register: openid_wellknown_config2 - name: Set federation_config_items ansible.builtin.set_fact: federation_config_items: - filename: "<fqdn_1>%2Fauth%2Frealms%2F<realm_name_1>.conf" contents: | { "scope" : "openid email profile" } - filename: "<fqdn_1>%2Fauth%2Frealms%2F<realm_name_1>.client" contents: "{{ {'client_id': <client_id_1>, 'client_secret': <client_secret_1> } | to_json }}" - filename: "<fqdn_1>%2Fauth%2Frealms%2F<realm_name_1>.provider" contents: | {{ openid_wellknown_config1.content }} - filename: "<fqdn_2>%2Fauth%2Frealms%2F<realm_name_2>.conf" contents: | { "scope" : "openid email profile" } - filename: "<fqdn_2>%2Fauth%2Frealms%2F<realm_name_2>.client" contents: "{{ {'client_id': <client_id_2>, 'client_secret': <client_secret_2>} | to_json }}" - filename: "<fqdn_2>%2Fauth%2Frealms%2F<realm_name_2>.provider" contents: | {{ openid_wellknown_config2.content }} - name: Generate the final federation_config.json string (as a dictionary) ansible.builtin.set_fact: _raw_federation_config_json_value: | { {% for item in federation_config_items %} "{{ item.filename }}": {{ item.contents }}{% if not loop.last %},{% endif %} {% endfor %} } - name: Final JSON string for Secret stringData ansible.builtin.set_fact: federation_config_json_string: "{{ _raw_federation_config_json_value }}" - name: Create a Kubernetes Secret with federation metadata kubernetes.core.k8s: state: present definition: apiVersion: v1 kind: Secret type: Opaque metadata: name: federation-realm-data namespace: openstack stringData: federation-config.json: "{{ federation_config_json_string }}"- 将 IdP 变量替换为在第 2 步中从 IdP 管理员获取的值。
-
在工作站上打开
OpenStackControlPlane自定义资源(CR)文件openstack_control_plane.yaml。 编辑 OpenStackControlPlane CR 的
keystone部分:keystone: template: customServiceConfig: | [federation] trusted_dashboard=<horizon_endpoint>/dashboard/auth/websso/ [openid] remote_id_attribute=HTTP_OIDC_ISS [auth] methods = password,token,oauth1,mapped,application_credential,openid httpdCustomization: customConfigSecret: keystone-httpd-override federatedRealmConfig: federation-realm-data-
将
<horizon_endpoint> 替换为在第 7 步中获取的 Dashboard URL。 -
从
方法 =分隔列表中删除外部。 -
在
httpdCustomization下添加customConfigSecret参数,并将此值设置为在第 5 步中keystone-httpd-override.yamlCR 文件中创建的键。 -
添加
federatedRealmConfig参数,并将此值设置为第 8 步中 Ansible Playbook 创建的federation-realm-datasecret。
-
将
编辑
OpenStackControlPlaneCR 的horizon部分:horizon: template: customServiceConfig: | # Point horizon to the keystone public endpoint OPENSTACK_KEYSTONE_URL = "<keystone_endpoint>/v3" # Enable WebSSO in horizon WEBSSO_ENABLED = True # Provide login options in the horizon dropdown menu WEBSSO_CHOICES = ( ("credentials", _("Keystone Credentials")), ("OIDC1", _("OpenID Connect IdP1")), ("OIDC2", _("OpenID Connect IdP2")), ) # Map the "OIDC" choice of horizon to the keystone IDP and protocol WEBSSO_IDP_MAPPING = { "OIDC1": ("<idp_name1>", "openid"), "OIDC2": ("<idp_name2>", "openid"), }更新 control plane:
$ oc apply -f openstack_control_plane.yaml -n openstack