使用 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.17
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.17
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 中的 Stack Management 管理用户和角色。您还可以使用角色管理 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
特权以及 read
和 view_index_metadata
特权,用于 logstash-*
索引。
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" ] } ] }