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.host 和 server.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_key 或 pfx 的密码。可选。 |
opensearch_security.openid.pfx | 从 IdP 获取端点时用于 mTLS 的 PFX 或 PKCS12 编码的私钥和证书链。certificate 和 private_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 来设置基本身份验证后端
- 下载并解压OpenID Connect 示例 zip 文件
- 使用一个强密码更新
.env
文件中的admin
用户。 - 将
config.yml
和opensearch_dashboards.yml
中的{IP}
占位符替换为本地机器的 IP。 - 查看以下文件
docker-compose.yml
定义了一个 OpenSearch 节点、OpenSearch Dashboards 和 Keycloak 服务器。new-realm.json
指定了 realm 的详细信息。在此示例中,realm 名为new
。config.yml
配置了basic_internal_auth_domain
和oidc_auth_domain
。opensearch_dashboards.yml
应指向 Keycloak 进行身份验证。确保opensearch_security.openid.connect_url
设置指向 realm 的 URL。
- 在命令行中,运行
docker compose up
。 - 访问
https://:5601
上的 OpenSearch Dashboards,并使用new-realm.json
文件中配置的用户名testuser
和密码testpassword
登录。
登录后,testuser
会从 Keycloak 收到后端角色 admin
,该角色映射到 all_access
OpenSearch 角色。这些后端角色可以使用 Keycloak 管理控制台在 https://:8080 进行管理,使用的用户名是 admin
,密码是 admin
。