Link Search Menu Expand Document Documentation Menu

OpenID Connect

安全插件可以与使用 OpenID Connect 标准的身份提供商集成。此功能支持以下特性:

  • 自动配置

    将安全插件指向身份提供商 (IdP) 的元数据,安全插件将使用该数据进行配置。

  • 自动密钥获取

    安全插件会自动从 IdP 的 JSON Web Key Set (JWKS) 端点检索用于验证 JSON Web Token (JWT) 的公钥。您无需在 config.yml 中配置密钥或共享密钥。

  • 密钥滚动

    您可以直接在 IdP 中更改用于签署 JWT 的密钥。如果安全插件检测到未知密钥,它会尝试从 IdP 检索该密钥。这种滚动对用户是透明的。

  • 将 OpenSearch Dashboards 用作单点登录或作为 Dashboards 登录窗口中多种身份验证类型之一。

配置 OpenID Connect 集成

要与 OpenID IdP 集成,请设置身份验证域并选择 openid 作为 HTTP 身份验证类型。JWT 已经包含验证请求所需的所有信息,因此将 challenge 设置为 false,将 authentication_backend 设置为 noop

这是最低配置:

_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    authc:
      openid_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: openid
          challenge: false
          config:
            subject_key: preferred_username
            roles_key: roles
            openid_connect_url: https://keycloak.example.com:8080/auth/realms/master/.well-known/openid-configuration
        authentication_backend:
          type: noop

下表显示了配置参数。

名称 描述
openid_connect_url IdP 的 URL,安全插件可在此处找到 OpenID Connect 元数据/配置设置。此 URL 因 IdP 而异。当使用 OpenID Connect 作为后端时,此项是必需的。
jwt_header 存储令牌的 HTTP 头。通常是带有 Bearer 方案的 Authorization 头:Authorization: Bearer <token>。可选。默认值为 Authorization
jwt_url_parameter 如果令牌不是在 HTTP 头中传输,而是作为 URL 参数传输,请在此处定义参数名称。可选。
subject_key JSON 有效负载中存储用户名的密钥。如果未定义,则使用 subject 注册声明。大多数 IdP 提供商使用 preferred_username 声明。可选。
roles_key JSON 有效负载中存储用户角色的密钥。该值必须是逗号分隔的角色列表。仅当您想在 JWT 中使用角色时才需要此密钥。您可以将 roles_key 配置为列表,以从嵌套的 JWT 声明中提取角色。

OpenID Connect URL

OpenID Connect 指定了各种用于集成目的的端点。最重要的端点是 well-known,它列出了安全插件的端点和其他配置选项。

URL 因 IdP 而异,但通常以 /.well-known/openid-configuration 结尾。

Keycloak 示例

http(s)://<server>:<port>/auth/realms/<realm>/.well-known/openid-configuration

安全插件所需的主要信息是 jwks_uri。此 URI 指定了可以在何处找到 JWKS 格式的 IdP 公钥。例如:

jwks_uri: "https://keycloak.example.com:8080/auth/realms/master/protocol/openid-connect/certs"
{
   keys:[
      {
         kid:"V-diposfUJIk5jDBFi_QRouiVinG5PowskcSWy5EuCo",
         kty:"RSA",
         alg:"RS256",
         use:"sig",
         n:"rI8aUrAcI_auAdF10KUopDOmEFa4qlUUaNoTER90XXWADtKne6VsYoD3ZnHGFXvPkRAQLM5d65ScBzWungcbLwZGWtWf5T2NzQj0wDyquMRwwIAsFDFtAZWkXRfXeXrFY0irYUS9rIJDafyMRvBbSz1FwWG7RTQkILkwiC4B8W1KdS5d9EZ8JPhrXvPMvW509g0GhLlkBSbPBeRSUlAS2Kk6nY5i3m6fi1H9CP3Y_X-TzOjOTsxQA_1pdP5uubXPUh5YfJihXcgewO9XXiqGDuQn6wZ3hrF6HTlhNWGcSyQPKh1gEcmXWQlRENZMvYET-BuJEE7eKyM5vRhjNoYR3w",
         e:"AQAB"
      }
   ]
}

有关 IdP 端点的更多信息,请参阅以下内容:

JWT 验证的时间差异补偿

有时您可能会发现身份验证服务器和 OpenSearch 节点之间的时间没有完全同步。在这种情况下,即使是几秒钟的差异,颁发或接收 JWT 的系统也可能尝试验证 nbf(不早于)和 exp(过期)声明,并因时间差异而无法验证用户身份。

默认情况下,安全插件允许 30 秒的窗口以补偿服务器时钟时间之间可能存在的偏差。要为该功能设置自定义值并覆盖默认值,您可以将 jwt_clock_skew_tolerance_seconds 设置添加到 config.yml

http_authenticator:
  type: openid
  challenge: false
  config:
    subject_key: preferred_username
    roles_key: roles
    openid_connect_url: https://keycloak.example.com:8080/auth/realms/master/.well-known/openid-configuration
    jwt_clock_skew_tolerance_seconds: 20

获取公钥

当 IdP 生成并签署 JWT 时,它必须将密钥 ID 添加到 JWT 头中。例如:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "V-diposfUJIk5jDBFi_QRouiVinG5PowskcSWy5EuCo"
}

根据 OpenID Connect 规范kid(密钥 ID)是强制性的。如果 IdP 未能将 kid 字段添加到 JWT,则令牌验证将不起作用。

如果安全插件收到带有未知 kid 的 JWT,它会访问 IdP 的 jwks_uri 并检索所有可用且有效的密钥。这些密钥将被使用和缓存,直到通过检索另一个未知密钥 ID 触发刷新。

密钥滚动和多个公钥

安全插件可以同时维护多个有效的公钥。OpenID 规范不为公钥规定有效期,因此密钥在从 IdP 的有效密钥列表中移除并且有效密钥列表被刷新之前,它都是有效的。

如果您想在 IdP 中滚动密钥,请遵循以下最佳实践:

  • 在 IdP 中创建新的密钥对,并赋予新密钥比当前使用的密钥更高的优先级。

    您的 IdP 将使用新密钥而非旧密钥。

  • 当新 kid 首次出现在 JWT 中时,安全插件会刷新密钥列表。

    此时,旧密钥和新密钥都有效。使用旧密钥签署的令牌也仍然有效。

  • 当使用旧密钥签署的最后一个 JWT 超时后,旧密钥可以从 IdP 中删除。

如果您必须立即更改公钥,也可以先删除旧密钥,然后创建一个新密钥。在这种情况下,所有使用旧密钥签署的 JWT 将立即失效。

TLS 设置

为防止中间人攻击,您应该使用 TLS 保护安全插件与 IdP 之间的连接。

启用 TLS

使用以下参数启用与 IdP 连接的 TLS:

config:
  openid_connect_idp:
    enable_ssl: <true|false>
    verify_hostnames: <true|false>
名称 描述
enable_ssl 是否使用 TLS。默认值为 false
verify_hostnames 是否验证 IdP 的 TLS 证书的主机名。默认值为 true

证书验证

要验证 IdP 的 TLS 证书,请配置 IdP 根 CA 的路径或根证书的内容:

config:
  openid_connect_idp:
    enable_ssl: true
    pemtrustedcas_filepath: /full/path/to/trusted_cas.pem
config:
  openid_connect_idp:
    enable_ssl: true
    pemtrustedcas_content: |-
      -----BEGIN CERTIFICATE-----
      MIID/jCCAuagAwIBAgIBATANBgkqhkiG9w0BAQUFADCBjzETMBEGCgmSJomT8ixk
      ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
      bGUgQ29tIEluYy4xITAfBgNVBAsMGEV4YW1wbGUgQ29tIEluYy4gUm9vdCBDQTEh
      ...
      -----END CERTIFICATE-----
名称 描述
pemtrustedcas_filepath 包含 IdP 根 CA 的 PEM 文件的绝对路径。
pemtrustedcas_content IdP 的根 CA 内容。如果设置了 pemtrustedcas_filepath,则不能使用此项。

TLS 客户端身份验证

要使用 TLS 客户端身份验证,请配置安全插件应发送的用于 TLS 客户端身份验证的 PEM 证书和私钥(或其内容):

config:
  openid_connect_idp:
    enable_ssl: true
    pemkey_filepath: /full/path/to/private.key.pem
    pemkey_password: private_key_password
    pemcert_filepath: /full/path/to/certificate.pem
config:
  openid_connect_idp:
    enable_ssl: true
    pemkey_content: |-
      -----BEGIN PRIVATE KEY-----
      MIID2jCCAsKgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBlTETMBEGCgmSJomT8ixk
      ARkWA2NvbTEXMBUGCgmSJomT8ixkARkWB2V4YW1wbGUxGTAXBgNVBAoMEEV4YW1w
      bGUgQ29tIEluYy4xJDAiBgNVBAsMG0V4YW1wbGUgQ29tIEluYy4gU2lnbmluZyBD
      ...
      -----END PRIVATE KEY-----
    pemkey_password: private_key_password
    pemcert_content: |-
      -----BEGIN CERTIFICATE-----
      MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCHRZwzwGlP2FvL
      oEzNeDu2XnOF+ram7rWPT6fxI+JJr3SDz1mSzixTeHq82P5A7RLdMULfQFMfQPfr
      WXgB4qfisuDSt+CPocZRfUqqhGlMG2l8LgJMr58tn0AHvauvNTeiGlyXy0ShxHbD
      ...
      -----END CERTIFICATE-----
名称 描述
enable_ssl_client_auth 是否将客户端证书发送到 IdP 服务器。默认值为 false
pemcert_filepath 客户端证书的绝对路径。
pemcert_content 客户端证书的内容。当设置了 pemcert_filepath 时不能使用。
pemkey_filepath 包含客户端证书私钥的文件的绝对路径。
pemkey_content 客户端证书私钥的内容。当设置了 pemkey_filepath 时,不能使用此项。
pemkey_password 私钥的密码(如果有)。

启用的密码套件和协议

您可以使用以下密钥限制允许的密码套件和 TLS 协议。

名称 描述
enabled_ssl_ciphers 数组。启用的 TLS 密码套件。仅支持 Java 格式。
enabled_ssl_protocols 数组。启用的 TLS 协议。仅支持 Java 格式。

(高级) DoS 保护

为帮助防御拒绝服务 (DoS) 攻击,Security 插件在特定时间跨度内只允许最大数量的新密钥 ID。如果新密钥 ID 的数量超出此阈值,Security 插件将返回 HTTP 状态码 503(服务不可用)并拒绝查询 IdP。默认情况下,Security 插件在 10 秒内不允许超过 10 个未知密钥 ID。下表显示了如何修改这些设置。

名称 描述
refresh_rate_limit_count 该时间范围内未知密钥 ID 的最大数量。默认值为 10。
refresh_rate_limit_time_window_ms 检查未知密钥 ID 最大数量时使用的时间范围,单位为毫秒。默认值为 10000(10 秒)。

OpenSearch Dashboards 单点登录

通过将以下内容添加到 opensearch_dashboards.yml 来激活 OpenID Connect

opensearch_security.auth.type: "openid"

配置

OpenID Connect 提供商通常以 JSON 格式在 元数据 URL 下发布其配置。因此,大多数设置可以自动拉取,从而使 OpenSearch Dashboards 的配置变得最少。最重要的设置如下:

  • 连接 URL
  • 客户端 ID

    每个 IdP 都可以托管多个具有不同设置和身份验证协议的客户端(有时称为应用程序)。启用 OpenID Connect 时,您应该在 IdP 中为 OpenSearch Dashboards 创建一个新客户端。客户端 ID 唯一标识 OpenSearch Dashboards。

  • 客户端密钥

    除了 ID,每个客户端还分配有一个客户端密钥。客户端密钥通常在创建客户端时生成。应用程序只有在提供客户端密钥时才能获取身份令牌。您可以在 IdP 上客户端的设置中找到此密钥。

配置设置

名称 描述
opensearch_security.openid.connect_url IdP 发布 OpenID 元数据的 URL。必填。
opensearch_security.openid.client_id 在 IdP 中配置的 OpenID Connect 客户端的 ID。必填。
opensearch_security.openid.client_secret 在 IdP 中配置的 OpenID Connect 客户端的客户端密钥。必填。
opensearch_security.openid.scope IdP 颁发的身份令牌的 范围。可选。默认值为 openid profile email address phone
opensearch_security.openid.header JWT 令牌的 HTTP 头部名称。可选。默认值为 Authorization
opensearch_security.openid.logout_url IdP 的注销 URL。可选。仅当 IdP 未在其元数据中发布注销 URL 时才需要。
opensearch_security.openid.base_redirect_url 将发送到 IdP 的重定向 URL 的基础。可选。仅当 OpenSearch Dashboards 位于反向代理之后时才需要,在这种情况下,它应与 opensearch_dashboards.yml 中的 server.hostserver.port 不同。
opensearch_security.openid.trust_dynamic_headers 从反向代理 HTTP 头部(X-Forwarded-Host / X-Forwarded-Proto)计算 base_redirect_url。可选。默认值为 false
opensearch_security.openid.root_ca 您的 IdP 证书可以匹配或链向的根 CA(PEM 格式)的路径。可选。
opensearch_security.openid.certificate 从 IdP 获取端点时用于 mTLS 的证书链(PEM 格式)。可选。
opensearch_security.openid.private_key 从 IdP 获取端点时用于 mTLS 的私钥(PEM 格式)。可选。
opensearch_security.openid.passphrase 用于单个 private_keypfx 的密码。可选。
opensearch_security.openid.pfx 从 IdP 获取端点时用于 mTLS 的 PFX 或 PKCS12 编码的私钥和证书链。certificateprivate_key 的替代方案。可选。
opensearch_security.openid.verify_hostnames 是否验证 IdP 的 TLS 证书的主机名。默认值为 true。可选。

配置示例

# Enable OpenID authentication
opensearch_security.auth.type: "openid"

# The IdP metadata endpoint
opensearch_security.openid.connect_url: "http://keycloak.example.com:8080/auth/realms/master/.well-known/openid-configuration"

# The ID of the OpenID Connect client in your IdP
opensearch_security.openid.client_id: "opensearch-dashboards-sso"

# The client secret of the OpenID Connect client
opensearch_security.openid.client_secret: "a59c51f5-f052-4740-a3b0-e14ba355b520"

# mTLS Options for obtaining endpoints from IdP
opensearch_security.openid.root_ca: /usr/share/opensearch-dashboards/config/certs/ca.pem
opensearch_security.openid.certificate: /usr/share/opensearch-dashboards/config/certs/cert.pem
opensearch_security.openid.private_key: /usr/share/opensearch-dashboards/config/certs/key.pem

# Use HTTPS instead of HTTP
opensearch.url: "https://<hostname>.com:<http port>"

# Configure the OpenSearch Dashboards internal server user
opensearch.username: "kibanaserver"
opensearch.password: "kibanaserver"

# Disable SSL verification when using self-signed demo certificates
opensearch.ssl.verificationMode: none

# allowlist basic headers and multi-tenancy header
opensearch.requestHeadersAllowlist: ["Authorization", "securitytenant"]

要在 Dashboards 登录窗口中包含 OpenID Connect 及其他身份验证类型,请参阅配置登录选项

使用附加 Cookie 进行会话管理

为改进会话管理——特别是对于分配了多个角色的用户——Dashboards 提供了一个选项,可以将 Cookie 有效载荷拆分为多个 Cookie,并在接收时重新组合这些有效载荷。这有助于防止较大的 OpenID Connect 断言超出每个 Cookie 的大小限制。以下示例中的两个设置允许您为附加 Cookie 设置前缀名称并指定其数量。它们已添加到 opensearch_dashboards.yml 文件中。附加 Cookie 的默认数量为三个

opensearch_security.openid.extra_storage.cookie_prefix: security_authentication_oidc
opensearch_security.openid.extra_storage.additional_cookies: 3

请注意,减少附加 Cookie 的数量可能会导致在更改之前正在使用的一些 Cookie 停止工作。我们建议设置固定数量的附加 Cookie,之后不要更改配置。

如果来自 IdP 的 ID 令牌特别大,OpenSearch 可能会抛出服务器日志身份验证错误,指示 HTTP 头部过大。在这种情况下,您可以增加 opensearch.yml 文件中 http.max_header_size 设置的值。

OpenSearch 安全配置

由于 OpenSearch Dashboards 要求内部 OpenSearch Dashboards 服务器用户可以通过 HTTP 基本身份验证进行身份验证,因此您必须配置两个身份验证域。对于 OpenID Connect,HTTP 基本域必须放在链中的第一位。确保将挑战标志设置为 false

修改并应用 config.yml 中的以下示例设置

_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    authc:
      basic_internal_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: 0
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: internal
      openid_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: openid
          challenge: false
          config:
            subject_key: preferred_username
            roles_key: roles
            openid_connect_url: https://keycloak.example.com:8080/auth/realms/master/.well-known/openid-configuration
        authentication_backend:
          type: noop

使用 Keycloak 的 Docker 示例

以下步骤使用 Docker 和 Keycloak IdP 来设置基本身份验证后端

  1. 下载并解压OpenID Connect 示例 zip 文件
  2. 使用一个强密码更新 .env 文件中的 admin 用户。
  3. config.ymlopensearch_dashboards.yml 中的 {IP} 占位符替换为本地机器的 IP。
  4. 查看以下文件
    • docker-compose.yml 定义了一个 OpenSearch 节点、OpenSearch Dashboards 和 Keycloak 服务器。
    • new-realm.json 指定了 realm 的详细信息。在此示例中,realm 名为 new
    • config.yml 配置了 basic_internal_auth_domainoidc_auth_domain
    • opensearch_dashboards.yml 应指向 Keycloak 进行身份验证。确保 opensearch_security.openid.connect_url 设置指向 realm 的 URL。
  5. 在命令行中,运行 docker compose up
  6. 访问 https://:5601 上的 OpenSearch Dashboards,并使用 new-realm.json 文件中配置的用户名 testuser 和密码 testpassword 登录。

登录后,testuser 会从 Keycloak 收到后端角色 admin,该角色映射到 all_access OpenSearch 角色。这些后端角色可以使用 Keycloak 管理控制台在 https://:8080 进行管理,使用的用户名是 admin,密码是 admin