使用 TLS 证书认证添加远程集群
编辑使用 TLS 证书认证添加远程集群
编辑要使用 TLS 证书认证添加远程集群:
如果您遇到任何问题,请参考 故障排除。
先决条件
编辑- 需要在两个集群的每个节点上启用 Elasticsearch 安全功能。默认情况下启用安全性。如果已禁用,请在
elasticsearch.yml
中将xpack.security.enabled
设置为true
。请参考 常规安全设置。 -
本地和远程集群的版本必须兼容。
- 任何节点都可以与相同主版本的另一个节点通信。例如,7.0 可以与任何 7.x 节点通信。
- 只有特定主版本的最后一个次要版本的节点才能与下一个主版本的节点通信。在 6.x 系列中,6.8 可以与任何 7.x 节点通信,而 6.7 只能与 7.0 通信。
-
版本兼容性是对称的,这意味着如果 6.7 可以与 7.0 通信,则 7.0 也可以与 6.7 通信。下表描述了本地和远程节点之间的版本兼容性。
版本兼容性表
本地集群
远程集群
5.0–5.5
5.6
6.0–6.6
6.7
6.8
7.0
7.1–7.16
7.17
8.0–8.16
5.0–5.5
5.6
6.0–6.6
6.7
6.8
7.0
7.1–7.16
7.17
8.0–8.16
Elastic 仅支持这些配置中的一个子集上的跨集群搜索。请参阅 支持的跨集群搜索配置。
与远程集群建立信任关系
编辑为了安全地使用跨集群复制或跨集群搜索远程集群,请在所有连接的集群上启用安全性并在每个节点上配置传输层安全性 (TLS)。在传输接口上配置 TLS 安全性是远程集群的最低要求。为了提高安全性,也可以在 HTTP 接口 上配置 TLS。
所有连接的集群都必须相互信任,并在传输接口上使用 TLS 进行相互认证。这意味着本地集群信任远程集群的证书颁发机构 (CA),而远程集群信任本地集群的 CA。建立连接时,所有节点都将验证来自另一侧节点的证书。这种相互信任对于安全连接远程集群是必需的,因为所有连接的节点实际上形成了一个单一的安全域。
用户身份验证在本地集群上执行,并将用户及其角色名称传递到远程集群。远程集群会根据其本地角色定义检查用户的角色名称,以确定用户允许访问哪些索引。
在使用安全 Elasticsearch 集群进行跨集群复制或跨集群搜索之前,请完成以下配置任务:
-
在每个节点上配置传输层安全性 (TLS) 以加密节点间流量并在本地集群中的节点与所有远程集群中的节点之间进行身份验证。有关配置安全性的必要步骤,请参考 为 Elastic Stack 设置基本安全性。
此过程使用相同的 CA 为所有节点生成证书。或者,您可以将本地集群的证书添加到每个远程集群中作为受信任的 CA。您还必须将远程集群的证书添加到本地集群中作为受信任的 CA。使用相同的 CA 为所有节点生成证书可以简化此任务。
连接到远程集群
编辑您必须具有 manage
集群权限才能连接远程集群。
本地集群使用 传输接口 与远程集群建立通信。本地集群中的协调节点与远程集群中的特定节点建立 长期 TCP 连接。Elasticsearch 要求这些连接保持打开状态,即使连接在较长时间内处于空闲状态。
要在 Kibana 的 Stack Management 中添加远程集群:
- 从侧边导航中选择 远程集群。
- 输入远程集群的名称(集群别名)。
- 指定 Elasticsearch 端点 URL,或远程集群的 IP 地址或主机名,后跟传输端口(默认为
9300
)。例如,cluster.es.eastus2.staging.azure.foundit.no:9300
或192.168.1.1:9300
。
或者,使用 集群更新设置 API 添加远程集群。您还可以使用此 API 动态配置本地集群中每个节点的远程集群。要在本地集群中的各个节点上配置远程集群,请为每个节点在 elasticsearch.yml
中定义静态设置。
以下请求添加了一个别名为 cluster_one
的远程集群。此集群别名是表示与远程集群连接的唯一标识符,用于区分本地和远程索引。
resp = client.cluster.put_settings( persistent={ "cluster": { "remote": { "cluster_one": { "seeds": [ "127.0.0.1:{remote-interface-default-port}" ] } } } }, ) print(resp)
const response = await client.cluster.putSettings({ persistent: { cluster: { remote: { cluster_one: { seeds: ["127.0.0.1:{remote-interface-default-port}"], }, }, }, }, }); console.log(response);
PUT /_cluster/settings { "persistent" : { "cluster" : { "remote" : { "cluster_one" : { "seeds" : [ "127.0.0.1:9300" ] } } } } }
您可以使用 远程集群信息 API 验证本地集群是否已成功连接到远程集群。
resp = client.cluster.remote_info() print(resp)
response = client.cluster.remote_info puts response
const response = await client.cluster.remoteInfo(); console.log(response);
GET /_remote/info
API 响应指示本地集群已连接到集群别名为 cluster_one
的远程集群。
{ "cluster_one" : { "seeds" : [ "127.0.0.1:9300" ], "connected" : true, "num_nodes_connected" : 1, "max_connections_per_cluster" : 3, "initial_connect_timeout" : "30s", "skip_unavailable" : true, "mode" : "sniff" } }
动态配置远程集群
编辑使用 集群更新设置 API 动态配置集群中每个节点上的远程设置。以下请求添加三个远程集群:cluster_one
、cluster_two
和 cluster_three
。
seeds
参数指定远程集群中种子节点的主机名和 传输端口(默认为 9300
)。
mode
参数确定配置的连接模式,默认为 sniff
。cluster_one
没有指定 mode
,因此它使用默认值。cluster_two
和 cluster_three
都明确使用不同的模式。
resp = client.cluster.put_settings( persistent={ "cluster": { "remote": { "cluster_one": { "seeds": [ "127.0.0.1:{remote-interface-default-port}" ] }, "cluster_two": { "mode": "sniff", "seeds": [ "127.0.0.1:{remote-interface-default-port-plus1}" ], "transport.compress": True, "skip_unavailable": True }, "cluster_three": { "mode": "proxy", "proxy_address": "127.0.0.1:{remote-interface-default-port-plus2}" } } } }, ) print(resp)
const response = await client.cluster.putSettings({ persistent: { cluster: { remote: { cluster_one: { seeds: ["127.0.0.1:{remote-interface-default-port}"], }, cluster_two: { mode: "sniff", seeds: ["127.0.0.1:{remote-interface-default-port-plus1}"], "transport.compress": true, skip_unavailable: true, }, cluster_three: { mode: "proxy", proxy_address: "127.0.0.1:{remote-interface-default-port-plus2}", }, }, }, }, }); console.log(response);
PUT _cluster/settings { "persistent": { "cluster": { "remote": { "cluster_one": { "seeds": [ "127.0.0.1:9300" ] }, "cluster_two": { "mode": "sniff", "seeds": [ "127.0.0.1:9301" ], "transport.compress": true, "skip_unavailable": true }, "cluster_three": { "mode": "proxy", "proxy_address": "127.0.0.1:9302" } } } } }
您可以在初始配置后动态更新远程集群的设置。以下请求更新 cluster_two
的压缩设置,以及 cluster_three
的压缩和 ping 计划设置。
当压缩或 ping 计划设置更改时,所有现有节点连接都必须关闭并重新打开,这可能会导致正在进行的请求失败。
resp = client.cluster.put_settings( persistent={ "cluster": { "remote": { "cluster_two": { "transport.compress": False }, "cluster_three": { "transport.compress": True, "transport.ping_schedule": "60s" } } } }, ) print(resp)
response = client.cluster.put_settings( body: { persistent: { cluster: { remote: { cluster_two: { 'transport.compress' => false }, cluster_three: { 'transport.compress' => true, 'transport.ping_schedule' => '60s' } } } } } ) puts response
const response = await client.cluster.putSettings({ persistent: { cluster: { remote: { cluster_two: { "transport.compress": false, }, cluster_three: { "transport.compress": true, "transport.ping_schedule": "60s", }, }, }, }, }); console.log(response);
PUT _cluster/settings { "persistent": { "cluster": { "remote": { "cluster_two": { "transport.compress": false }, "cluster_three": { "transport.compress": true, "transport.ping_schedule": "60s" } } } } }
您可以通过为每个远程集群设置传递 null
值来从集群设置中删除远程集群。以下请求从集群设置中删除 cluster_two
,保留 cluster_one
和 cluster_three
。
resp = client.cluster.put_settings( persistent={ "cluster": { "remote": { "cluster_two": { "mode": None, "seeds": None, "skip_unavailable": None, "transport.compress": None } } } }, ) print(resp)
response = client.cluster.put_settings( body: { persistent: { cluster: { remote: { cluster_two: { mode: nil, seeds: nil, skip_unavailable: nil, 'transport.compress' => nil } } } } } ) puts response
const response = await client.cluster.putSettings({ persistent: { cluster: { remote: { cluster_two: { mode: null, seeds: null, skip_unavailable: null, "transport.compress": null, }, }, }, }, }); console.log(response);
PUT _cluster/settings { "persistent": { "cluster": { "remote": { "cluster_two": { "mode": null, "seeds": null, "skip_unavailable": null, "transport.compress": null } } } } }
静态配置远程集群
编辑如果您在 elasticsearch.yml
中指定设置,则只有具有这些设置的节点才能连接到远程集群并服务远程集群请求。
使用 集群更新设置 API 指定的远程集群设置优先于您为各个节点在 elasticsearch.yml
中指定的设置。
在以下示例中,cluster_one
、cluster_two
和 cluster_three
是表示与每个集群连接的任意集群别名。这些名称随后用于区分本地和远程索引。
为远程集群配置角色和用户
编辑在 连接远程集群 后,您需要在本地和远程集群上创建用户角色并分配必要的权限。这些角色是使用跨集群复制和跨集群搜索所必需的。
您必须在本地和远程集群上使用相同的角色名称。例如,以下跨集群复制配置在本地和远程集群上都使用 remote-replication
角色名称。但是,您可以在每个集群上指定不同的角色定义。
您可以通过 Kibana 的堆栈管理,选择侧边导航栏中的安全 > 角色来管理用户和角色。您也可以使用角色管理 API动态添加、更新、删除和检索角色。当您使用 API 管理native
领域中的角色时,这些角色将存储在 Elasticsearch 的内部索引中。
以下请求使用创建或更新角色 API。您必须至少拥有manage_security
集群权限才能使用此 API。
配置跨集群复制的权限
编辑跨集群复制用户需要在远程集群和本地集群上拥有不同的集群和索引权限。使用以下请求在本地和远程集群上创建单独的角色,然后创建一个具有所需角色的用户。
远程集群
编辑在包含领导者索引的远程集群上,跨集群复制角色需要read_ccr
集群权限,以及领导者索引上的monitor
和read
权限。
如果请求使用API 密钥进行身份验证,则 API 密钥需要在本地集群上拥有上述权限,而不是远程集群。
如果请求是代表其他用户发出的,则身份验证用户必须在远程集群上拥有run_as
权限。
以下请求在远程集群上创建一个remote-replication
角色
resp = client.security.put_role( name="remote-replication", cluster=[ "read_ccr" ], indices=[ { "names": [ "leader-index-name" ], "privileges": [ "monitor", "read" ] } ], ) print(resp)
const response = await client.security.putRole({ name: "remote-replication", cluster: ["read_ccr"], indices: [ { names: ["leader-index-name"], privileges: ["monitor", "read"], }, ], }); console.log(response);
POST /_security/role/remote-replication { "cluster": [ "read_ccr" ], "indices": [ { "names": [ "leader-index-name" ], "privileges": [ "monitor", "read" ] } ] }
本地集群
编辑在包含跟随者索引的本地集群上,remote-replication
角色需要manage_ccr
集群权限,以及跟随者索引上的monitor
、read
、write
和manage_follow_index
权限。
以下请求在本地集群上创建一个remote-replication
角色
resp = client.security.put_role( name="remote-replication", cluster=[ "manage_ccr" ], indices=[ { "names": [ "follower-index-name" ], "privileges": [ "monitor", "read", "write", "manage_follow_index" ] } ], ) print(resp)
const response = await client.security.putRole({ name: "remote-replication", cluster: ["manage_ccr"], indices: [ { names: ["follower-index-name"], privileges: ["monitor", "read", "write", "manage_follow_index"], }, ], }); console.log(response);
POST /_security/role/remote-replication { "cluster": [ "manage_ccr" ], "indices": [ { "names": [ "follower-index-name" ], "privileges": [ "monitor", "read", "write", "manage_follow_index" ] } ] }
在每个集群上创建remote-replication
角色后,使用创建或更新用户 API在本地集群上创建一个用户并分配remote-replication
角色。例如,以下请求将remote-replication
角色分配给名为cross-cluster-user
的用户
resp = client.security.put_user( username="cross-cluster-user", password="l0ng-r4nd0m-p@ssw0rd", roles=[ "remote-replication" ], ) print(resp)
const response = await client.security.putUser({ username: "cross-cluster-user", password: "l0ng-r4nd0m-p@ssw0rd", roles: ["remote-replication"], }); console.log(response);
POST /_security/user/cross-cluster-user { "password" : "l0ng-r4nd0m-p@ssw0rd", "roles" : [ "remote-replication" ] }
您只需要在本地集群上创建此用户。
然后,您可以配置跨集群复制以跨数据中心复制您的数据。
配置跨集群搜索的权限
编辑跨集群搜索用户需要在远程集群和本地集群上拥有不同的集群和索引权限。以下请求在本地和远程集群上创建单独的角色,然后创建一个具有所需角色的用户。
远程集群
编辑在远程集群上,跨集群搜索角色需要目标索引的read
和read_cross_cluster
权限。
如果请求使用API 密钥进行身份验证,则 API 密钥需要在本地集群上拥有上述权限,而不是远程集群。
如果请求是代表其他用户发出的,则身份验证用户必须在远程集群上拥有run_as
权限。
以下请求在远程集群上创建一个remote-search
角色
resp = client.security.put_role( name="remote-search", indices=[ { "names": [ "target-indices" ], "privileges": [ "read", "read_cross_cluster" ] } ], ) print(resp)
const response = await client.security.putRole({ name: "remote-search", indices: [ { names: ["target-indices"], privileges: ["read", "read_cross_cluster"], }, ], }); console.log(response);
POST /_security/role/remote-search { "indices": [ { "names": [ "target-indices" ], "privileges": [ "read", "read_cross_cluster" ] } ] }
本地集群
编辑在本地集群(用于启动跨集群搜索的集群)上,用户只需要remote-search
角色。角色权限可以为空。
以下请求在本地集群上创建一个remote-search
角色
resp = client.security.put_role( name="remote-search", ) print(resp)
const response = await client.security.putRole({ name: "remote-search", }); console.log(response);
POST /_security/role/remote-search {}
在每个集群上创建remote-search
角色后,使用创建或更新用户 API在本地集群上创建一个用户并分配remote-search
角色。例如,以下请求将remote-search
角色分配给名为cross-search-user
的用户
resp = client.security.put_user( username="cross-search-user", password="l0ng-r4nd0m-p@ssw0rd", roles=[ "remote-search" ], ) print(resp)
const response = await client.security.putUser({ username: "cross-search-user", password: "l0ng-r4nd0m-p@ssw0rd", roles: ["remote-search"], }); console.log(response);
POST /_security/user/cross-search-user { "password" : "l0ng-r4nd0m-p@ssw0rd", "roles" : [ "remote-search" ] }
您只需要在本地集群上创建此用户。
拥有remote-search
角色的用户可以跨集群搜索。
配置跨集群搜索和 Kibana 的权限
编辑当使用 Kibana 跨多个集群搜索时,一个两步授权流程决定用户是否可以访问远程集群上的数据流和索引。
- 首先,本地集群确定用户是否有权访问远程集群。本地集群是 Kibana 连接到的集群。
- 如果用户已授权,则远程集群将确定用户是否可以访问指定的数据流和索引。
要授予 Kibana 用户访问远程集群的权限,请为其分配一个本地角色,该角色具有对远程集群上索引的读取权限。您将远程集群中的数据流和索引指定为<remote_cluster_name>:<target>
。
要授予用户对远程数据流和索引的读取权限,您必须在远程集群上创建一个匹配的角色,该角色授予具有访问相应数据流和索引权限的read_cross_cluster
权限。
例如,您可能正在本地集群上积极索引 Logstash 数据,并定期将较旧的基于时间的索引卸载到远程集群上的存档中。您希望跨两个集群进行搜索,因此必须在两个集群上启用 Kibana 用户。
本地集群
编辑在本地集群上,创建一个logstash-reader
角色,该角色授予本地logstash-*
索引上的read
和view_index_metadata
权限。
如果您将本地集群配置为 Elasticsearch 中的另一个远程集群,则本地集群上的logstash-reader
角色也需要授予read_cross_cluster
权限。
resp = client.security.put_role( name="logstash-reader", indices=[ { "names": [ "logstash-*" ], "privileges": [ "read", "view_index_metadata" ] } ], ) print(resp)
const response = await client.security.putRole({ name: "logstash-reader", indices: [ { names: ["logstash-*"], privileges: ["read", "view_index_metadata"], }, ], }); console.log(response);
POST /_security/role/logstash-reader { "indices": [ { "names": [ "logstash-*" ], "privileges": [ "read", "view_index_metadata" ] } ] }
为您的 Kibana 用户分配一个角色,该角色授予对 Kibana 的访问权限,以及您的logstash_reader
角色。例如,以下请求创建cross-cluster-kibana
用户并分配kibana-access
和logstash-reader
角色。
resp = client.security.put_user( username="cross-cluster-kibana", password="l0ng-r4nd0m-p@ssw0rd", roles=[ "logstash-reader", "kibana-access" ], ) print(resp)
const response = await client.security.putUser({ username: "cross-cluster-kibana", password: "l0ng-r4nd0m-p@ssw0rd", roles: ["logstash-reader", "kibana-access"], }); console.log(response);
PUT /_security/user/cross-cluster-kibana { "password" : "l0ng-r4nd0m-p@ssw0rd", "roles" : [ "logstash-reader", "kibana-access" ] }
远程集群
编辑在远程集群上,创建一个logstash-reader
角色,该角色授予read_cross_cluster
权限以及logstash-*
索引的read
和view_index_metadata
权限。
resp = client.security.put_role( name="logstash-reader", indices=[ { "names": [ "logstash-*" ], "privileges": [ "read_cross_cluster", "read", "view_index_metadata" ] } ], ) print(resp)
const response = await client.security.putRole({ name: "logstash-reader", indices: [ { names: ["logstash-*"], privileges: ["read_cross_cluster", "read", "view_index_metadata"], }, ], }); console.log(response);
POST /_security/role/logstash-reader { "indices": [ { "names": [ "logstash-*" ], "privileges": [ "read_cross_cluster", "read", "view_index_metadata" ] } ] }