在 Elastic Stack 上配置 SAML 单点登录

编辑

在 Elastic Stack 上配置 SAML 单点登录

编辑

Elastic Stack 支持使用 Elasticsearch 作为后端服务的 SAML 单点登录 (SSO) 到 Kibana。在 SAML 术语中,Elastic Stack 作为服务提供商运行。

启用 SAML 单点登录所需的另一个组件是身份提供商,它是一个处理您的凭据并执行用户实际身份验证的服务。

如果您有兴趣配置到 Kibana 的 SSO,那么您需要向 Elasticsearch 提供有关您的身份提供商的信息,并且您需要在该身份提供商中将 Elastic Stack 注册为已知的服务提供商。还需要在 Kibana 中进行一些配置更改才能激活 SAML 身份验证提供程序。

Kibana 中的 SAML 支持是基于预期它将成为该 Kibana 实例用户的主要(或唯一)身份验证方法而设计的。一旦您在 Kibana 中启用 SAML 身份验证,它将影响所有尝试登录的用户。“配置 Kibana”部分提供了有关此工作原理的更多详细信息。

身份提供商

编辑

Elastic Stack 支持 SAML 2.0 Web 浏览器 SSO 和 SAML 2.0 单点注销配置文件,并且可以与任何至少支持 SAML 2.0 Web 浏览器 SSO 配置文件的身份提供商 (IdP) 集成。它已经过许多流行的 IdP 实现的测试,例如Microsoft Active Directory Federation Services (ADFS)Azure Active Directory (AAD)Okta

本指南假设您已经有一个现有的 IdP,并且希望将 Kibana 添加为服务提供商。

Elastic Stack 使用标准的 SAML 元数据文档,该文档采用 XML 格式,定义了您的 IdP 的功能和特性。您应该能够在您的 IdP 管理界面中下载或生成此类文档。

下载 IdP 元数据文档并将其存储在每个 Elasticsearch 节点上的 config 目录中。在本指南中,我们假设您将其存储为 config/saml/idp-metadata.xml

IdP 将被分配一个标识符(在 SAML 术语中为EntityID),它最常用统一资源标识符 (URI) 形式表示。您的管理界面可能会告诉您这是什么,或者您可能需要阅读元数据文档才能找到它 - 查找 EntityDescriptor 元素上的 entityID 属性。

大多数 IdP 将提供一个适当的元数据文件,其中包含 Elastic Stack 所需的所有功能,并且只需要执行下面描述的配置步骤。为了完整起见,Elastic Stack 对 IdP 元数据的最低要求是:

  • 一个 <EntityDescriptor>,其 entityID 与 Elasticsearch 配置匹配
  • 一个 <IDPSSODescriptor>,它支持 SAML 2.0 协议 (urn:oasis:names:tc:SAML:2.0:protocol)。
  • 至少一个配置为签名<KeyDescriptor>(即,它具有 use="signing" 或未指定 use
  • 一个 <SingleSignOnService>,其 HTTP-Redirect (urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect) 绑定
  • 如果您希望支持 单点注销,则需要一个带有 HTTP-Redirect (urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect) 绑定的 <SingleLogoutService>

Elastic Stack 要求来自 IdP 的所有消息都必须签名。对于身份验证的 <Response> 消息,签名可以应用于响应本身,也可以应用于各个断言。对于 <LogoutRequest> 消息,消息本身必须签名,并且签名应作为 URL 参数提供,这是 HTTP-Redirect 绑定所要求的。

配置 Elasticsearch 进行 SAML 身份验证

编辑

在 Elasticsearch 中启用 SAML 身份验证有五个配置步骤:

  1. 启用 HTTP 的 SSL/TLS
  2. 启用令牌服务
  3. 创建一个或多个 SAML 领域
  4. 配置角色映射
  5. 生成一个 SAML 元数据文件供您的身份提供商使用(可选)

启用 HTTP 的 TLS

编辑

如果您的 Elasticsearch 集群在生产模式下运行,那么您必须配置 HTTP 接口以使用 SSL/TLS,然后才能启用 SAML 身份验证。

有关更多信息,请参阅加密 Elasticsearch 的 HTTP 客户端通信

启用令牌服务

编辑

Elasticsearch SAML 实现使用 Elasticsearch 令牌服务。如果您在 HTTP 接口上配置了 TLS,则会自动启用此服务,并且可以通过在 elasticsearch.yml 文件中包含以下内容来显式配置此服务:

xpack.security.authc.token.enabled: true

创建一个 SAML 领域

编辑

通过在 Elasticsearch 的身份验证链中配置一个 SAML 领域来启用 SAML 身份验证。

此领域有一些强制设置和许多可选设置。可用设置在安全设置中详细描述。例如,SAML 领域设置SAML 领域签名设置SAML 领域加密设置SAML 领域 SSL 设置。本指南将引导您完成最常见的设置。

通过将以下内容添加到 elasticsearch.yml 配置文件来创建一个领域。下面解释每个配置值。

xpack.security.authc.realms.saml.saml1:
  order: 2
  idp.metadata.path: saml/idp-metadata.xml
  idp.entity_id: "https://sso.example.com/"
  sp.entity_id:  "https://kibana.example.com/"
  sp.acs: "https://kibana.example.com/api/security/saml/callback"
  sp.logout: "https://kibana.example.com/logout"
  attributes.principal: "urn:oid:0.9.2342.19200300.100.1.1"
  attributes.groups: "urn:oid:1.3.6.1.4.1.5923.1.5.1."

SAML 在通过 Kibana 进行身份验证时使用,但它不是直接向 Elasticsearch REST API 进行身份验证的有效方法。因此,我们建议您在身份验证链中至少包含一个额外的领域,例如原生领域,以供 API 客户端使用。

上面示例中使用的配置值是:

xpack.security.authc.realms.saml.saml1
这定义了一个名为“saml1”的新 saml 身份验证领域。有关领域的更多解释,请参阅领域
order
领域在领域链中的顺序。顺序较低的领域具有最高优先级,并且首先被咨询。我们建议将基于密码的领域(如 file、native、LDAP 和 Active Directory)的顺序设为最低(优先级最高),然后是 SSO 领域(如 SAML 和 OpenID Connect)。如果您有多个相同类型的领域,请将访问最频繁的领域的顺序设为最低,以使其首先被咨询。
idp.metadata.path
这是您为身份提供商保存的元数据文件的路径。您在此处输入的路径相对于您的 config/ 目录。Elasticsearch 将自动监视此文件的更改,并在每次更新时重新加载配置。
idp.entity_id
这是您的 IdP 使用的标识符(SAML EntityID)。它应与元数据文件中的 entityID 属性匹配。
sp.entity_id
这是您的 Kibana 实例的唯一标识符,以 URI 形式表示。当您在 IdP 中将 Kibana 添加为服务提供商时,将使用此值。我们建议您使用 Kibana 实例的基本 URL 作为实体 ID。
sp.acs
断言使用者服务 (ACS) 端点是 Kibana 中接受来自 IdP 的身份验证消息的 URL。此 ACS 端点仅支持 SAML HTTP-POST 绑定。它必须是尝试登录 Kibana 的用户的 Web 浏览器可以访问的 URL,不需要 Elasticsearch 或 IdP 直接访问。正确的值可能会因您安装 Kibana 的方式以及是否涉及任何代理而有所不同,但它通常是 ${kibana-url}/api/security/saml/callback,其中 ${kibana-url} 是 Kibana 实例的基本 URL。
sp.logout
这是 Kibana 中接受来自 IdP 的注销消息的 URL。与 sp.acs URL 一样,它必须可以通过 Web 浏览器访问,但不需要 Elasticsearch 或 IdP 直接访问。正确的值可能会因您安装 Kibana 的方式以及是否涉及任何代理而有所不同,但它通常是 ${kibana-url}/logout,其中 ${kibana-url} 是 Kibana 实例的基本 URL。
attributes.principal
请参阅属性映射
attributes.groups
请参阅属性映射

属性映射

编辑

当用户通过您的身份提供商连接到 Kibana 时,身份提供商将提供有关用户的 SAML 断言。该断言将包含一个身份验证声明,指示用户已成功通过 IdP 身份验证,以及一个或多个属性声明,其中将包含用户的属性

这些属性可能包括以下内容:

  • 用户的用户名
  • 用户的电子邮件地址
  • 用户的组或角色

SAML 中的属性使用 URI 命名,例如 urn:oid:0.9.2342.19200300.100.1.1http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn,并且具有一个或多个与之关联的值。

这些属性标识符在 IdP 之间有所不同,大多数 IdP 都提供了自定义 URI 及其关联值的方法。

Elasticsearch 使用这些属性来推断有关已登录用户的信息,并且它们可以用于角色映射(如下)。

为了使这些属性有用,Elasticsearch 和 IdP 需要具有属性名称的公共值。这是通过手动完成的,方法是配置 IdP 和 SAML 领域,以便为每个逻辑用户属性使用相同的 URI 名称。

配置这些 SAML 属性的建议步骤如下:

  1. 请咨询您的 IdP,了解它可以提供哪些用户属性。这在提供商之间差异很大,但您应该能够从文档或当地管理员那里获得列表。
  2. 通读 Elasticsearch 支持的用户属性列表,并确定哪些属性对您有用,并且可以由您的 IdP 提供。至少,需要 principal 属性。
  3. 配置您的 IdP 以将这些属性“发布”到您的 Kibana SAML 服务提供商。此过程因提供商而异 - 有些会为此提供用户界面,而另一些则可能需要您编辑配置文件。通常,IdP(或当地管理员)会对每个属性使用什么 URI 提出建议。您可以简单地接受这些建议,因为 Elasticsearch 服务是完全可配置的,不需要使用任何特定的 URI。
  4. 配置 Elasticsearch 中的 SAML 域,以将 Elasticsearch 用户属性(请参阅下方的列表)与您在 IdP 中配置的 URI 相关联。在上面的示例中,我们配置了 principalgroups 属性。
特殊的属性名称
编辑

通常,Elasticsearch 期望属性的配置值是一个 URI,例如 urn:oid:0.9.2342.19200300.100.1.1,但是也有一些额外的名称可以使用。

nameid
此值使用 SAML NameID 值(删除所有前导和尾随空格),而不是 SAML 属性。SAML NameID 元素是 SAML 断言中的一个可选但经常提供的字段,IdP 可以使用该字段来标识该断言的主题。在某些情况下,NameID 将与用户在 IdP 中的登录标识符(用户名)相关,但在许多情况下,它们将是内部生成的标识符,在 IdP 之外没有明显的含义。
nameid:persistent
此值使用 SAML NameID 值(删除所有前导和尾随空格),但前提是 NameID 格式为 urn:oasis:names:tc:SAML:2.0:nameid-format:persistent。SAML NameID 元素有一个可选的 Format 属性,该属性指示提供的名称的语义。通常,IdP 配置为使用“瞬态”NameID,为每个会话提供新的标识符。由于使用瞬态 NameID 作为属性映射的一部分很少有用,“nameid:persistent”属性名称可以用作安全机制,如果您尝试从没有持久值的 NameID 进行映射,则会导致错误。

身份提供者可以静态配置为发布具有特定格式的 NameID,或者可以配置为尝试符合 SP 的要求。SP 使用名为 NameIDPolicy 的元素在身份验证请求中声明其要求。如果需要,您可以设置相关的设置,名为 nameid_format,以便请求 IdP 发布具有特定格式的 NameID

friendlyName
SAML 属性除了基于 URI 的名称之外,还可以具有一个friendlyName。例如,名称为 urn:oid:0.9.2342.19200300.100.1.1 的属性也可能具有 uid 的 friendlyName。您可以在属性映射中使用这些 friendlyName,但建议您使用基于 URI 的名称,因为 friendlyName 既不是标准化的也不是强制性的。

下面的示例配置了一个域,使用持久的 nameid 作为 principal,并使用 friendlyName 为“roles”的属性作为用户的组。

xpack.security.authc.realms.saml.saml1:
  order: 2
  idp.metadata.path: saml/idp-metadata.xml
  idp.entity_id: "https://sso.example.com/"
  sp.entity_id:  "https://kibana.example.com/"
  sp.acs: "https://kibana.example.com/api/security/saml/callback"
  attributes.principal: "nameid:persistent"
  attributes.groups: "roles"
  nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
Elasticsearch 用户属性
编辑

可以配置 Elasticsearch SAML 域,将 SAML attributes 映射到经过身份验证的用户的以下属性:

principal
(必需)这是将应用于针对此域进行身份验证的用户的用户名principal 出现在 Elasticsearch 审计日志等位置。
groups

(推荐)如果您希望使用 IdP 的组或角色概念作为用户 Elasticsearch 权限的基础,则应使用此属性映射它们。groups 将直接传递到您的角色映射规则

某些 IdP 配置为将 groups 列表作为以逗号分隔的字符串发送。要将此 SAML 属性映射到 Elasticsearch 域中的 attributes.groups 设置,可以使用 attribute_delimiters.group 设置配置字符串分隔符。

例如,在分隔符值为 , 的情况下拆分 SAML 属性值 engineering,elasticsearch-admins,employees 将导致 engineeringelasticsearch-adminsemployees 作为用户的组列表。

name
(可选)用户的全名。
mail
(可选)用户的电子邮件地址。
dn
(可选)用户的 X.500 专有名称
从 SAML 属性中提取部分值
编辑

在某些情况下,IdP 的属性可能包含比您希望在 Elasticsearch 中使用的更多信息。一个常见的例子是 IdP 专门使用电子邮件地址,但您希望用户的 principal 使用电子邮件地址的本地名称部分。例如,如果他们的电子邮件地址是 [email protected],那么您希望他们的 principal 只是 james.wong

这可以使用 Elasticsearch 域中的 attribute_patterns 设置来实现,如下面的域配置所示:

xpack.security.authc.realms.saml.saml1:
  order: 2
  idp.metadata.path: saml/idp-metadata.xml
  idp.entity_id: "https://sso.example.com/"
  sp.entity_id:  "https://kibana.example.com/"
  sp.acs: "https://kibana.example.com/api/security/saml/callback"
  attributes.principal: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
  attribute_patterns.principal: "^([^@]+)@staff\\.example\\.com$"

在这种情况下,用户的 principal 从电子邮件属性映射而来,但在将其分配给用户之前,会对该值应用正则表达式。如果正则表达式匹配,则使用第一组的结果作为有效值。如果正则表达式不匹配,则属性映射失败。

在此示例中,电子邮件地址必须属于 staff.example.com 域,然后本地部分(@ 之前的任何内容)将用作 principal。任何尝试使用不同电子邮件域登录的用户都会失败,因为正则表达式与其电子邮件地址不匹配,因此其强制性的 principal 属性将不会被填充。

这些正则表达式中的小错误可能会导致重大的安全后果。例如,如果我们不小心从上面的示例中遗漏了尾随的 $,那么我们将匹配域名以 staff.example.com 开头的任何电子邮件地址,这将接受 [email protected] 等电子邮件地址。请务必确保您的正则表达式尽可能精确,以便您不会无意中打开用户冒充攻击的途径。

请求特定的身份验证方法

编辑

有时,SAML SP 需要能够对 IdP 中发生的身份验证施加特定的限制,以便评估其对相应身份验证响应的信任程度。这些限制可能与身份验证方法(密码、客户端证书等)、注册期间的用户身份识别方法以及其他详细信息有关。Elasticsearch 实现了 SAML 2.0 身份验证上下文,可以按照 SAML 2.0 核心规范中的定义将其用于此目的。

简而言之,SAML SP 定义了一组身份验证上下文类引用值,这些值描述了将对 IdP 施加的限制,并在身份验证请求中发送这些值。IdP 尝试授予这些限制。如果它不能授予这些限制,则身份验证尝试失败。如果用户身份验证成功,则 SAML 响应的身份验证声明将包含满足的限制的指示。

您可以使用 SAML 域配置中的 req_authn_context_class_ref 选项来定义身份验证上下文类引用值。请参阅SAML 域设置

Elasticsearch 仅支持身份验证上下文的 exact 比较方法。当它收到来自 IdP 的身份验证响应时,Elasticsearch 会检查作为 SAML 断言的身份验证声明的一部分的身份验证上下文类引用的值。如果它与请求的值之一匹配,则认为身份验证成功。否则,身份验证尝试失败。

SAML 注销

编辑

SAML 协议支持单点注销 (SLO) 的概念。对 SLO 的支持程度因身份提供者而异。您应该查阅 IdP 的文档以确定它提供的注销服务。

默认情况下,如果满足以下条件,则 Elastic Stack 将支持 SAML SLO:

  • 您的 IdP 元数据指定 IdP 提供 SLO 服务
  • 您的 IdP 在其为用户颁发的 SAML 断言的主题中发布 NameID
  • 您配置 sp.logout
  • 设置 idp.use_single_logout 不是 false
IdP SLO 服务
编辑

Elasticsearch 从 IdP 的 SAML 元数据中读取的值之一是 <SingleLogoutService>。为了使单点注销与 Elastic Stack 一起工作,Elasticsearch 要求它存在并支持 urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect 的绑定。

Elastic Stack 将根据需要将 <LogoutRequest><LogoutResponse> 消息发送到此服务。

sp.logout 设置
编辑

Elasticsearch 域设置 sp.logout 指定 Kibana 中的 URL,IdP 可以将 <LogoutRequest><LogoutResponse> 消息发送到该 URL。此服务使用 SAML HTTP-Redirect 绑定。

Elasticsearch 将处理 <LogoutRequest> 消息,并执行全局注销,该注销将使与提供的 SAML 会话关联的任何现有 Elasticsearch 安全令牌无效。

如果您未配置 sp.logout 的值,则 Elasticsearch 将拒绝所有 <LogoutRequest> 消息。

IdP 通常要求对 LogoutRequest 消息进行签名,因此您可能需要配置签名凭据

idp.use_single_logout 设置
编辑

如果您的 IdP 提供 <SingleLogoutService> 但您不希望使用它,您可以在 SAML 域中配置 idp.use_single_logout: false,并且 Elasticsearch 将忽略 IdP 提供的 SLO 服务。在这种情况下,当用户注销 Kibana 时,它将使其 Elasticsearch 会话(安全令牌)无效,但不会在 IdP 执行任何注销操作。

使用不带单点注销的 Kibana
编辑

如果您的 IdP 不支持单点注销,或者您选择不使用它,那么 Kibana 将只执行“本地注销”。

这意味着 Kibana 将使它用于与 Elasticsearch 通信的会话令牌失效,但无法执行任何身份提供商会话的失效操作。在大多数情况下,这意味着 Kibana 用户仍然被视为已登录到 IdP。因此,如果用户导航到 Kibana 登录页面,他们将被自动重新认证,并在无需输入任何凭据的情况下开始新的 Kibana 会话。

此问题的可能解决方案是

  • 请您的 IdP 管理员或供应商提供单点注销服务
  • 如果您的 Idp 确实提供了单点注销服务,请确保将其包含在 IdP 元数据文件中,并且不要idp.use_single_logout 设置为 false
  • 建议您的用户在注销 Kibana 后关闭浏览器
  • 在您的 SAML 领域上启用 force_authn 设置。此设置会导致 Elastic Stack 在用户尝试登录 Kibana 时每次都向 IdP 请求新的身份验证。此设置默认为 false,因为它可能会带来更麻烦的用户体验,但它也可以有效地防止用户利用现有的 IdP 会话。

加密和签名

编辑

Elastic Stack 支持生成签名的 SAML 消息(用于身份验证和/或注销)、验证来自 IdP 的签名 SAML 消息(用于身份验证和注销),并且可以处理加密内容。

您可以使用相同或单独的密钥为 Elasticsearch 配置签名、加密或两者都配置。

Elastic Stack 使用带有 RSA 私钥的 X.509 证书进行 SAML 加密。可以使用任何标准 SSL 工具(包括 elasticsearch-certutil 工具)生成这些密钥。

您的 IdP 可能要求 Elastic Stack 具有用于签名 SAML 消息的加密密钥,并且您需要在服务提供商配置中提供相应的签名证书(在 Elastic Stack SAML 元数据文件中或在 IdP 管理界面中手动配置)。虽然大多数 IdP 不期望身份验证请求被签名,但通常情况下注销请求需要签名。您的 IdP 将根据为 Elastic Stack 服务提供商配置的签名证书验证这些签名。

加密证书很少需要,但 Elastic Stack 支持在 IdP 或本地策略强制使用它们的情况下使用。

生成证书和密钥
编辑

Elasticsearch 支持 PEM、PKCS#12 或 JKS 格式的证书和密钥。某些身份提供商对它们支持的格式更具限制性,并且会要求您以特定格式的文件提供证书。您应该查阅 IdP 的文档以确定它们支持哪些格式。由于 PEM 格式是最常用的格式,以下示例将生成该格式的证书。

使用 elasticsearch-certutil 工具,您可以使用以下命令生成签名证书

bin/elasticsearch-certutil cert --self-signed --pem --days 1100 --name saml-sign --out saml-sign.zip

这将

  • 生成证书和密钥对(cert 子命令)
  • 以 PEM 格式创建文件(-pem 选项)
  • 生成有效期为 3 年的证书(-days 1100
  • 将证书命名为 saml-sign-name 选项)
  • 将证书和密钥保存在 saml-sign.zip 文件中(-out 选项)

生成的 zip 存档将包含 3 个文件

  • saml-sign.crt,用于签名的公钥证书
  • saml-sign.key,证书的私钥
  • ca.crt,不需要的 CA 证书,可以忽略。

可以使用相同的过程生成加密证书。

配置 Elasticsearch 进行签名
编辑

默认情况下,如果已配置签名密钥,Elasticsearch 将签名所有传出的 SAML 消息。

如果您希望使用 PEM 格式的密钥和证书进行签名,则应在 SAML 领域上配置以下设置

signing.certificate
PEM 格式证书文件的路径。例如 saml/saml-sign.crt
signing.key
PEM 格式密钥文件的路径。例如 saml/saml-sign.key
signing.secure_key_passphrase
密钥的密码,如果文件已加密。这是一个 安全设置,必须使用 elasticsearch-keystore 工具设置。

如果您希望使用 PKCS#12 格式的文件或 Java 密钥库进行签名,则应在 SAML 领域上配置以下设置

signing.keystore.path
PKCS#12 或 JKS 密钥库的路径。例如 saml/saml-sign.p12
signing.keystore.alias
密钥库中密钥的别名。例如 signing-key
signing.keystore.secure_password
密钥库的密码,如果文件已加密。这是一个 安全设置,必须使用 elasticsearch-keystore 工具设置。

如果您希望签名一些但并非所有传出的 SAML 消息,则应在 SAML 领域上配置以下设置

signing.saml_messages
要签名的消息类型列表。消息类型由用于消息的 XML 元素的本地名称标识。支持的值为:AuthnRequestLogoutRequestLogoutResponse
配置 Elasticsearch 以加密消息
编辑

Elasticsearch 安全功能支持用于消息解密的单个密钥。如果配置了密钥,则 Elasticsearch 会尝试使用它来解密身份验证响应中的 EncryptedAssertionEncryptedAttribute 元素,以及注销请求中的 EncryptedID 元素。

Elasticsearch 拒绝任何包含无法解密的 EncryptedAssertion 的 SAML 消息。

如果 Assertion 同时包含加密和纯文本属性,则无法解密加密属性不会导致自动拒绝。相反,Elasticsearch 会处理可用的纯文本属性(以及任何可以解密的 EncryptedAttributes)。

如果您希望使用 PEM 格式的密钥和证书进行 SAML 加密,则应在 SAML 领域上配置以下设置

encryption.certificate
PEM 格式证书文件的路径。例如 saml/saml-crypt.crt
encryption.key
PEM 格式密钥文件的路径。例如 saml/saml-crypt.key
encryption.secure_key_passphrase
密钥的密码,如果文件已加密。这是一个 安全设置,必须使用 elasticsearch-keystore 工具设置。

如果您希望使用 PKCS#12 格式的文件或 Java 密钥库进行 SAML 加密,则应在 SAML 领域上配置以下设置

encryption.keystore.path
PKCS#12 或 JKS 密钥库的路径。例如 saml/saml-crypt.p12
encryption.keystore.alias
密钥库中密钥的别名。例如 encryption-key
encryption.keystore.secure_password
密钥库的密码,如果文件已加密。这是一个 安全设置,必须使用 elasticsearch-keystore 工具设置。

生成 SP 元数据

编辑

某些身份提供商支持从服务提供商导入元数据文件。这将自动配置 IdP 和 SP 之间的许多集成选项。

Elastic Stack 支持使用 bin/elasticsearch-saml-metadata 命令SAML 服务提供商元数据 API 生成此类元数据文件。

您可以通过向 Elasticsearch 发出 API 请求并使用 jq 等工具将其存储为 XML 文件来生成 SAML 元数据。例如,以下命令为 SAML 领域 realm1 生成元数据,并将其保存到 metadata.xml 文件

curl -u user_name:password  -X GET https://127.0.0.1:9200/_security/saml/metadata/saml1 -H 'Content-Type: application/json' | jq -r '.[]' > metadata.xml

配置角色映射

编辑

当用户使用 SAML 进行身份验证时,他们会被标识到 Elastic Stack,但这不会自动授予他们执行任何操作或访问任何数据的权限。

您的 SAML 用户在被分配角色之前无法执行任何操作。这可以通过 添加角色映射 API 或使用 授权领域来完成。

您不能使用 角色映射文件来授予通过 SAML 进行身份验证的用户的角色。

这是一个简单的角色映射示例,它将 example_role 角色授予针对 saml1 领域进行身份验证的任何用户

resp = client.security.put_role_mapping(
    name="saml-example",
    roles=[
        "example_role"
    ],
    enabled=True,
    rules={
        "field": {
            "realm.name": "saml1"
        }
    },
)
print(resp)
const response = await client.security.putRoleMapping({
  name: "saml-example",
  roles: ["example_role"],
  enabled: true,
  rules: {
    field: {
      "realm.name": "saml1",
    },
  },
});
console.log(response);
PUT /_security/role_mapping/saml-example
{
  "roles": [ "example_role" ], 
  "enabled": true,
  "rules": {
    "field": { "realm.name": "saml1" }
  }
}

example_role 角色不是内置的 Elasticsearch 角色。此示例假定您已创建自己的自定义角色,并且具有对 数据流、索引Kibana 功能的相应访问权限。

通过领域配置映射的属性用于处理角色映射规则,这些规则确定授予用户哪些角色。

提供给角色映射的用户字段派生自 SAML 属性,如下所示

  • usernameprincipal 属性
  • dndn 属性
  • groupsgroups 属性
  • metadata:请参阅 用户元数据

有关详细信息,请参阅 将用户和组映射到角色角色映射

如果您的 IdP 能够向服务提供商提供组或角色,那么您应该将此 SAML 属性映射到 Elasticsearch 领域中的 attributes.groups 设置,然后在角色映射中按以下示例使用它。

此映射将 Elasticsearch finance_data 角色授予通过 saml1 领域使用 finance-team 组进行身份验证的任何用户。

resp = client.security.put_role_mapping(
    name="saml-finance",
    roles=[
        "finance_data"
    ],
    enabled=True,
    rules={
        "all": [
            {
                "field": {
                    "realm.name": "saml1"
                }
            },
            {
                "field": {
                    "groups": "finance-team"
                }
            }
        ]
    },
)
print(resp)
const response = await client.security.putRoleMapping({
  name: "saml-finance",
  roles: ["finance_data"],
  enabled: true,
  rules: {
    all: [
      {
        field: {
          "realm.name": "saml1",
        },
      },
      {
        field: {
          groups: "finance-team",
        },
      },
    ],
  },
});
console.log(response);
PUT /_security/role_mapping/saml-finance
{
  "roles": [ "finance_data" ],
  "enabled": true,
  "rules": { "all": [
        { "field": { "realm.name": "saml1" } },
        { "field": { "groups": "finance-team" } } 
  ] }
}

groups 属性支持使用通配符 (*)。有关详细信息,请参阅创建或更新角色映射 API

如果您的用户也存在于 Elasticsearch 可以直接访问的存储库中(例如 LDAP 目录),那么您可以使用 授权领域而不是角色映射。

在这种情况下,您可以执行以下步骤:1. 在您的 SAML 领域中,通过配置 attributes.principal 设置,分配一个 SAML 属性作为查找用户 ID。2. 创建一个新的领域,该领域可以从您的本地存储库中查找用户(例如,ldap 领域)。3. 在您的 SAML 领域中,将 authorization_realms 设置为您在步骤 2 中创建的领域的名称。

用户元数据

编辑

默认情况下,通过 SAML 进行身份验证的用户将具有一些额外的元数据字段。

  • saml_nameid 将设置为 SAML 身份验证响应中 NameID 元素的值
  • saml_nameid_format 将设置为 NameID 的 format 属性的完整 URI
  • 在身份验证响应中提供的每个 SAML 属性(无论是否映射到 Elasticsearch 用户属性),都将作为元数据字段 saml(name) 添加,其中 "name" 是属性的完整 URI 名称。例如,saml(urn:oid:0.9.2342.19200300.100.1.3)
  • 对于每个具有 friendlyName 的 SAML 属性,也将作为元数据字段 saml_friendlyName 添加,其中 "name" 是属性的完整 URI 名称。例如,saml_mail

可以通过在 SAML 领域中添加 populate_user_metadata: false 作为设置来禁用此行为。

配置 Kibana

编辑

Kibana 中的 SAML 身份验证除了标准的 Kibana 安全配置之外,还需要少量的额外设置。Kibana 安全文档 提供了您可以应用的可用配置选项的详细信息。

特别是,由于您的 Elasticsearch 节点已配置为在 HTTP 接口上使用 TLS,您必须配置 Kibana 使用 https URL 连接到 Elasticsearch,并且您可能需要配置 elasticsearch.ssl.certificateAuthorities 以信任 Elasticsearch 已配置为使用的证书。

Kibana 中的 SAML 身份验证受 kibana.yml 中的以下超时设置的约束

您可能需要根据您的安全要求调整这些超时。

SAML 支持所需的三个额外设置如下所示

xpack.security.authc.providers:
  saml.saml1:
    order: 0
    realm: "saml1"

上面示例中使用的配置值是:

xpack.security.authc.providers
添加 saml 提供程序以指示 Kibana 使用 SAML SSO 作为身份验证方法。
xpack.security.authc.providers.saml.<provider-name>.realm
将其设置为您在 Elasticsearch 领域配置中使用的 SAML 领域的名称,例如:saml1

支持 Kibana 中的 SAML 和基本身份验证

编辑

Kibana 中的 SAML 支持是基于它将成为该 Kibana 实例用户的主要(或唯一)身份验证方法的期望而设计的。但是,可以通过按照下面的示例设置 xpack.security.authc.providers,在单个 Kibana 实例中同时支持 SAML 和基本身份验证。

xpack.security.authc.providers:
  saml.saml1:
    order: 0
    realm: "saml1"
  basic.basic1:
    order: 1

如果 Kibana 以这种方式配置,用户将在登录选择器 UI 中看到一个选择。他们可以使用 SAML 登录,或者提供用户名和密码并依赖 Elasticsearch 中的其他安全领域之一。只有在配置的 Elasticsearch 身份验证领域中拥有用户名和密码的用户才能通过 Kibana 登录表单登录。

或者,当启用 basic 身份验证提供程序时,您可以在 Kibana 前面放置一个反向代理,并配置它为每个请求发送基本身份验证头 (Authorization: Basic ....)。如果此标头存在且有效,Kibana 将不会启动 SAML 身份验证过程。

操作多个 Kibana 实例

编辑

如果您希望有多个针对同一 Elasticsearch 集群进行身份验证的 Kibana 实例,则每个配置为 SAML 身份验证的 Kibana 实例都需要有自己的 SAML 领域。

每个 SAML 领域必须有自己唯一的实体 ID (sp.entity_id) 和自己的断言使用者服务 (sp.acs)。每个 Kibana 实例都将通过查找匹配的 sp.acs 值映射到正确的领域。

这些领域可以使用相同的身份提供程序,但这不是必需的。

以下示例说明了拥有 3 个不同的 Kibana 实例,其中 2 个使用相同的内部 IdP,另一个使用不同的 IdP。

xpack.security.authc.realms.saml.saml_finance:
  order: 2
  idp.metadata.path: saml/idp-metadata.xml
  idp.entity_id: "https://sso.example.com/"
  sp.entity_id:  "https://kibana.finance.example.com/"
  sp.acs: "https://kibana.finance.example.com/api/security/saml/callback"
  sp.logout: "https://kibana.finance.example.com/logout"
  attributes.principal: "urn:oid:0.9.2342.19200300.100.1.1"
  attributes.groups: "urn:oid:1.3.6.1.4.1.5923.1.5.1."
xpack.security.authc.realms.saml.saml_sales:
  order: 3
  idp.metadata.path: saml/idp-metadata.xml
  idp.entity_id: "https://sso.example.com/"
  sp.entity_id:  "https://kibana.sales.example.com/"
  sp.acs: "https://kibana.sales.example.com/api/security/saml/callback"
  sp.logout: "https://kibana.sales.example.com/logout"
  attributes.principal: "urn:oid:0.9.2342.19200300.100.1.1"
  attributes.groups: "urn:oid:1.3.6.1.4.1.5923.1.5.1."
xpack.security.authc.realms.saml.saml_eng:
  order: 4
  idp.metadata.path: saml/idp-external.xml
  idp.entity_id: "https://engineering.sso.example.net/"
  sp.entity_id:  "https://kibana.engineering.example.com/"
  sp.acs: "https://kibana.engineering.example.com/api/security/saml/callback"
  sp.logout: "https://kibana.engineering.example.com/logout"
  attributes.principal: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"

可以有一个或多个使用 SAML 的 Kibana 实例,而其他实例使用针对另一种领域类型(例如原生LDAP)的基本身份验证。

SAML 领域配置的故障排除

编辑

SAML 2.0 规范为标准的实施者提供了许多选项和灵活性,这反过来又增加了复杂性和在服务提供商 (Elastic Stack) 和身份提供商处可用的配置选项的数量。此外,不同的安全域具有不同的安全要求,需要进行特定的配置才能满足。我们已尽力通过合理的默认值和上述详细文档来掩盖这种复杂性,但如果您在配置 SAML 领域时遇到问题,您可以查看我们的 SAML 故障排除文档,其中包含针对常见问题的建议和解决方案。

没有 Kibana 的 SAML

编辑

Elasticsearch 中的 SAML 领域旨在允许用户向 Kibana 验证身份,因此,上面指南的大部分内容都假设使用了 Kibana。本节描述了自定义 Web 应用程序如何使用相关的 SAML REST API,以便使用 SAML 对用户进行 Elasticsearch 身份验证。

本节假设读者熟悉 SAML 2.0 标准,更具体地说,熟悉 SAML 2.0 Web 浏览器单点登录配置文件。

单点登录领域(如 OpenID Connect 和 SAML)利用 Elasticsearch 中的令牌服务,原则上将 SAML 或 OpenID Connect 身份验证响应交换为 Elasticsearch 访问令牌和刷新令牌。访问令牌用作后续调用 Elasticsearch 的凭据。刷新令牌允许用户在当前的 Elasticsearch 访问令牌过期后获取新的 Elasticsearch 访问令牌。

SAML 领域

编辑

您必须创建 SAML 领域并在 Elasticsearch 中进行相应配置。请参阅配置 Elasticsearch 以进行 SAML 身份验证

用于访问 API 的服务帐户用户

编辑

该领域的设计假设需要一个特权实体充当身份验证代理。在这种情况下,自定义 Web 应用程序是身份验证代理,处理最终用户的身份验证(更准确地说,是“委托”身份验证给 SAML 身份提供程序)。SAML 相关 API 需要进行身份验证以及经过身份验证的用户所需的授权级别。因此,您必须创建服务帐户用户,并为其分配一个角色,该角色赋予其 manage_saml 集群特权。在进行身份验证后,必须使用 manage_token 集群特权,以便服务帐户用户可以为了代表经过身份验证的用户刷新访问令牌或随后注销他们而保持访问权限。

resp = client.security.put_role(
    name="saml-service-role",
    cluster=[
        "manage_saml",
        "manage_token"
    ],
)
print(resp)
const response = await client.security.putRole({
  name: "saml-service-role",
  cluster: ["manage_saml", "manage_token"],
});
console.log(response);
POST /_security/role/saml-service-role
{
  "cluster" : ["manage_saml", "manage_token"]
}
resp = client.security.put_user(
    username="saml-service-user",
    password="<somePasswordHere>",
    roles=[
        "saml-service-role"
    ],
)
print(resp)
const response = await client.security.putUser({
  username: "saml-service-user",
  password: "<somePasswordHere>",
  roles: ["saml-service-role"],
});
console.log(response);
POST /_security/user/saml-service-user
{
  "password" : "<somePasswordHere>",
  "roles"    : ["saml-service-role"]
}

处理 SP 发起的身份验证流程

编辑

从高层次上讲,自定义 Web 应用程序需要执行以下步骤才能使用 SAML 对 Elasticsearch 用户进行身份验证

  1. _security/saml/prepare 发出 HTTP POST 请求,以 saml-service-user 用户的身份进行身份验证。使用 Elasticsearch 配置中 SAML 领域的名称或请求正文中断言使用者服务 URL 的值。有关更多详细信息,请参阅SAML 准备身份验证 API

    resp = client.security.saml_prepare_authentication(
        realm="saml1",
    )
    print(resp)
    const response = await client.security.samlPrepareAuthentication({
      realm: "saml1",
    });
    console.log(response);
    POST /_security/saml/prepare
    {
      "realm" : "saml1"
    }
  2. 处理来自 /_security/saml/prepare 的响应。来自 Elasticsearch 的响应将包含 3 个参数:redirectrealmid。自定义 Web 应用程序需要将 id 的值存储在用户的会话中(如果会话信息以这种方式持久化,则在客户端的 cookie 或服务器端)。它还必须将用户的浏览器重定向到 redirect 参数中返回的 URL。id 值不应被忽略,因为它在 SAML 中用作随机数,以减轻重放攻击。
  3. 处理来自 SAML IdP 的后续响应。用户成功通过身份提供程序进行身份验证后,他们将被重定向回断言使用者服务 URL。此 sp.acs 需要定义为自定义 Web 应用程序处理的 URL。当它收到此 HTTP POST 请求时,自定义 Web 应用程序必须对其进行解析,并向 _security/saml/authenticate API 发出 HTTP POST 请求。它必须以 saml-service-user 用户的身份进行身份验证,并传递作为请求正文发送的 Base64 编码的 SAML 响应。它还必须传递之前保存在用户会话中的 id 值。

    有关更多详细信息,请参阅SAML 身份验证 API

    resp = client.security.saml_authenticate(
        content="PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMD.....",
        ids=[
            "4fee3b046395c4e751011e97f8900b5273d56685"
        ],
    )
    print(resp)
    const response = await client.security.samlAuthenticate({
      content:
        "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMD.....",
      ids: ["4fee3b046395c4e751011e97f8900b5273d56685"],
    });
    console.log(response);
    POST /_security/saml/authenticate
    {
      "content" : "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMD.....",
      "ids" : ["4fee3b046395c4e751011e97f8900b5273d56685"]
    }

    Elasticsearch 将对此进行验证,如果一切正确,将以访问令牌作为响应,该访问令牌可以用作后续请求的 Bearer 令牌。它还会提供一个刷新令牌,该刷新令牌可以稍后用于刷新给定的访问令牌,如获取令牌 API中所述。

  4. 调用 /_security/saml/authenticate 的响应将仅包含经过身份验证的用户的用户名。如果您需要获取该用户的 SAML 响应中包含的 SAML 属性的值,则可以使用访问令牌作为 Bearer 令牌来调用身份验证 API /_security/_authenticate/,并且 SAML 属性值将作为用户元数据的一部分包含在响应中。

处理 IdP 发起的身份验证流程

编辑

Elasticsearch 还可以处理 SAML 2 Web 浏览器 SSO 配置文件的 IdP 发起的单点登录流程。在这种情况下,身份验证从来自 SAML 身份提供程序的主动身份验证响应开始。SP 发起的 SSO 的不同之处在于,Web 应用程序需要处理对 sp.acs 的请求,这些请求不会作为对先前重定向的响应出现。因此,它将没有用户的现有会话,并且它将没有任何存储的 id 参数值。在这种情况下,对 _security/saml/authenticate API 的请求将如下所示

resp = client.security.saml_authenticate(
    content="PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMD.....",
    ids=[],
)
print(resp)
const response = await client.security.samlAuthenticate({
  content:
    "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMD.....",
  ids: [],
});
console.log(response);
POST /_security/saml/authenticate
{
  "content" : "PHNhbWxwOlJlc3BvbnNlIHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMD.....",
  "ids" : []
}

处理注销流程

编辑
  1. 在必要时,自定义 Web 应用程序可以通过使用SAML 注销 API 并将访问令牌和刷新令牌作为参数传递来注销用户。例如

    resp = client.security.saml_logout(
        token="46ToAxZVaXVVZTVKOVF5YU04ZFJVUDVSZlV3",
        refresh_token="mJdXLtmvTUSpoLwMvdBt_w",
    )
    print(resp)
    const response = await client.security.samlLogout({
      token: "46ToAxZVaXVVZTVKOVF5YU04ZFJVUDVSZlV3",
      refresh_token: "mJdXLtmvTUSpoLwMvdBt_w",
    });
    console.log(response);
    POST /_security/saml/logout
    {
      "token" : "46ToAxZVaXVVZTVKOVF5YU04ZFJVUDVSZlV3",
      "refresh_token": "mJdXLtmvTUSpoLwMvdBt_w"
    }

    如果 SAML 领域已进行相应配置并且 IdP 支持(请参阅SAML 注销),此请求将触发 SAML SP 发起的单点注销。在这种情况下,响应将包含一个 redirect 参数,指示用户需要重定向到 IdP 以完成注销的位置。

  2. 或者,IdP 可能会在某个时候启动单点注销流程。为了处理这种情况,自定义 Web 应用程序需要处理注销 URL (sp.logout)。用户将重定向到的 URL 的查询部分将包含一个 SAML 注销请求,并且此查询部分需要使用 SAML 使失效 API 中继到 Elasticsearch

    resp = client.security.saml_invalidate(
        query="SAMLRequest=nZFda4MwFIb%2FiuS%2BmviRpqFaClKQdbvo2g12M2KMraCJ9cRR9utnW4Wyi13sMie873MeznJ1aWrnS3VQGR0j4mLkKC1NUeljjA77zYyhVbIE0dR%2By7fmaHq7U%2BdegXWGpAZ%2B%2F4pR32luBFTAtWgUcCv56%2Fp5y30X87Yz1khTIycdgpUW9kY7WdsC9zxoXTvMvWuVV98YyMnSGH2SYE5pwALBIr9QKiwDGpW0oGVUznGeMyJZKFkQ4jBf5HnhUymjIhzCAL3KNFihbYx8TBYzzGaY7EnIyZwHzCWMfiDnbRIftkSjJr%2BFu0e9v%2B0EgOquRiiZjKpiVFp6j50T4WXoyNJ%2FEWC9fdqc1t%2F1%2B2F3aUpjzhPiXpqMz1%2FHSn4A&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=MsAYz2NFdovMG2mXf6TSpu5vlQQyEJAg%2B4KCwBqJTmrb3yGXKUtIgvjqf88eCAK32v3eN8vupjPC8LglYmke1ZnjK0%2FKxzkvSjTVA7mMQe2AQdKbkyC038zzRq%2FYHcjFDE%2Bz0qISwSHZY2NyLePmwU7SexEXnIz37jKC6NMEhus%3D",
        realm="saml1",
    )
    print(resp)
    const response = await client.security.samlInvalidate({
      query:
        "SAMLRequest=nZFda4MwFIb%2FiuS%2BmviRpqFaClKQdbvo2g12M2KMraCJ9cRR9utnW4Wyi13sMie873MeznJ1aWrnS3VQGR0j4mLkKC1NUeljjA77zYyhVbIE0dR%2By7fmaHq7U%2BdegXWGpAZ%2B%2F4pR32luBFTAtWgUcCv56%2Fp5y30X87Yz1khTIycdgpUW9kY7WdsC9zxoXTvMvWuVV98YyMnSGH2SYE5pwALBIr9QKiwDGpW0oGVUznGeMyJZKFkQ4jBf5HnhUymjIhzCAL3KNFihbYx8TBYzzGaY7EnIyZwHzCWMfiDnbRIftkSjJr%2BFu0e9v%2B0EgOquRiiZjKpiVFp6j50T4WXoyNJ%2FEWC9fdqc1t%2F1%2B2F3aUpjzhPiXpqMz1%2FHSn4A&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=MsAYz2NFdovMG2mXf6TSpu5vlQQyEJAg%2B4KCwBqJTmrb3yGXKUtIgvjqf88eCAK32v3eN8vupjPC8LglYmke1ZnjK0%2FKxzkvSjTVA7mMQe2AQdKbkyC038zzRq%2FYHcjFDE%2Bz0qISwSHZY2NyLePmwU7SexEXnIz37jKC6NMEhus%3D",
      realm: "saml1",
    });
    console.log(response);
    POST /_security/saml/invalidate
    {
      "query" : "SAMLRequest=nZFda4MwFIb%2FiuS%2BmviRpqFaClKQdbvo2g12M2KMraCJ9cRR9utnW4Wyi13sMie873MeznJ1aWrnS3VQGR0j4mLkKC1NUeljjA77zYyhVbIE0dR%2By7fmaHq7U%2BdegXWGpAZ%2B%2F4pR32luBFTAtWgUcCv56%2Fp5y30X87Yz1khTIycdgpUW9kY7WdsC9zxoXTvMvWuVV98YyMnSGH2SYE5pwALBIr9QKiwDGpW0oGVUznGeMyJZKFkQ4jBf5HnhUymjIhzCAL3KNFihbYx8TBYzzGaY7EnIyZwHzCWMfiDnbRIftkSjJr%2BFu0e9v%2B0EgOquRiiZjKpiVFp6j50T4WXoyNJ%2FEWC9fdqc1t%2F1%2B2F3aUpjzhPiXpqMz1%2FHSn4A&SigAlg=http%3A%2F%2Fwww.w3.org%2F2001%2F04%2Fxmldsig-more%23rsa-sha256&Signature=MsAYz2NFdovMG2mXf6TSpu5vlQQyEJAg%2B4KCwBqJTmrb3yGXKUtIgvjqf88eCAK32v3eN8vupjPC8LglYmke1ZnjK0%2FKxzkvSjTVA7mMQe2AQdKbkyC038zzRq%2FYHcjFDE%2Bz0qISwSHZY2NyLePmwU7SexEXnIz37jKC6NMEhus%3D",
      "realm" : "saml1"
    }

    然后,自定义 Web 应用程序还需要处理响应,该响应将包含一个 redirect 参数,其中包含 IdP 中的 URL,该 URL 包含 SAML 注销响应。应用程序应将用户重定向到该位置以完成注销。

对于 SP 发起的单点注销,IdP 可能会发回一个注销响应,可以使用 Elasticsearch 的 SAML 完成注销 API 进行验证。