TLS証明書認証を使用してリモートクラスターを追加する
TLS証明書認証を使用してリモートクラスターを追加するには:
問題が発生した場合は、トラブルシューティングを参照してください。
前提条件
- 1. Elasticsearchのセキュリティ機能は、両方のクラスターのすべてのノードで有効にする必要があります。セキュリティはデフォルトで有効です。無効になっている場合は、
xpack.security.enabled
をtrue
に設定してください。 一般的なセキュリティ設定を参照してください。 - 2. ローカルクラスターとリモートクラスターのバージョンは互換性がある必要があります。
- 同じメジャーバージョンのノードは、他のノードと通信できます。たとえば、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.15 |
| 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.15 | | | | | | | | | |
Elasticは、これらの構成の一部でのみクロスクラスター検索をサポートしています。サポートされているクロスクラスター検索構成を参照してください。
リモートクラスターとの信頼関係を確立する
リモートクラスターとのクロスクラスター複製またはクロスクラスター検索を安全に使用するには、すべての接続されたクラスターでセキュリティを有効にし、すべてのノードでトランスポート層セキュリティ(TLS)を構成する必要があります。リモートクラスターには、トランスポートインターフェースでTLSセキュリティを構成することが最小限必要です。追加のセキュリティのために、HTTPインターフェースでもTLSを構成してください。
すべての接続されたクラスターは互いに信頼し合い、トランスポートインターフェースでTLSによって相互認証される必要があります。これは、ローカルクラスターがリモートクラスターの証明書機関(CA)を信頼し、リモートクラスターがローカルクラスターのCAを信頼することを意味します。接続を確立する際、すべてのノードは他の側のノードからの証明書を検証します。この相互信頼は、リモートクラスターを安全に接続するために必要です。接続されたすべてのノードは、実質的に単一のセキュリティドメインを形成します。
ユーザー認証はローカルクラスターで行われ、ユーザーとユーザーのロール名はリモートクラスターに渡されます。リモートクラスターは、ユーザーのロール名をローカルロール定義と照合して、ユーザーがアクセスできるインデックスを決定します。
セキュリティが有効なElasticsearchクラスターでクロスクラスター複製またはクロスクラスター検索を使用する前に、次の構成タスクを完了してください:
- 1. 各ノードでトランスポート層セキュリティ(TLS)を構成して、ノード間のトラフィックを暗号化し、ローカルクラスターのノードとすべてのリモートクラスターのノードを認証します。セキュリティを構成するための必要な手順については、Elastic Stackの基本的なセキュリティを設定するを参照してください。
この手順では、すべてのノードの証明書を生成するために同じCAを使用します。あるいは、ローカルクラスターの証明書を各リモートクラスターの信頼されたCAとして追加することもできます。また、リモートクラスターの証明書をローカルクラスターの信頼されたCAとして追加する必要があります。すべてのノードの証明書を生成するために同じCAを使用すると、この作業が簡素化されます。
リモートクラスターに接続する
リモートクラスターに接続するには、manage
クラスターの特権が必要です。
ローカルクラスターは、トランスポートインターフェースを使用してリモートクラスターとの通信を確立します。ローカルクラスターのコーディネートノードは、リモートクラスターの特定のノードと長期間のTCP接続を確立します。Elasticsearchは、接続が長時間アイドル状態であっても、これらの接続が開いたままであることを要求します。
KibanaのStack Managementからリモートクラスターを追加するには:
- 1. サイドナビゲーションからリモートクラスターを選択します。
- 2. リモートクラスターの名前(クラスターエイリアス)を入力します。
- 3. ElasticsearchエンドポイントURL、またはリモートクラスターのIPアドレスまたはホスト名の後にトランスポートポート(デフォルトは
9300
)を指定します。たとえば、cluster.es.eastus2.staging.azure.foundit.no:9300
または192.168.1.1:9300
です。
または、クラスター更新設定APIを使用してリモートクラスターを追加できます。このAPIを使用して、ローカルクラスターのすべてのノードに対してリモートクラスターを動的に構成することもできます。ローカルクラスターの個々のノードにリモートクラスターを構成するには、elasticsearch.yml
で各ノードの静的設定を定義します。
次のリクエストは、cluster_one
というエイリアスを持つリモートクラスターを追加します。このクラスターエイリアスは、リモートクラスターへの接続を表す一意の識別子であり、ローカルインデックスとリモートインデックスを区別するために使用されます。
Python
resp = client.cluster.put_settings(
persistent={
"cluster": {
"remote": {
"cluster_one": {
"seeds": [
"127.0.0.1:{remote-interface-default-port}"
]
}
}
}
},
)
print(resp)
Js
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"
]
}
}
}
}
}
このリモートクラスターのクラスターエイリアスはcluster_one です。 |
|
リモートクラスターのシードノードのホスト名とトランスポートポートを指定します。 |
リモートクラスター情報APIを使用して、ローカルクラスターがリモートクラスターに正常に接続されていることを確認できます:
Python
resp = client.cluster.remote_info()
print(resp)
Ruby
response = client.cluster.remote_info
puts response
Js
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を使用して、クラスター内のすべてのノードでリモート設定を動的に構成します。次のリクエストは、3つのリモートクラスターを追加します:cluster_one
、cluster_two
、cluster_three
。
`````mode`````パラメータは、構成された接続モードを決定し、デフォルトは[`````sniff`````](7781101e63c937c9.md#sniff-mode)です。`````cluster_one`````は`````mode`````を指定していないため、デフォルトを使用します。`````cluster_two`````と`````cluster_three`````は明示的に異なるモードを使用します。
#### Python
``````python
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)
`
Js
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
の圧縮およびピングスケジュール設定を更新します。
圧縮またはピングスケジュール設定が変更されると、すべての既存のノード接続は閉じて再オープンする必要があり、これにより進行中のリクエストが失敗する可能性があります。
Python
resp = client.cluster.put_settings(
persistent={
"cluster": {
"remote": {
"cluster_two": {
"transport.compress": False
},
"cluster_three": {
"transport.compress": True,
"transport.ping_schedule": "60s"
}
}
}
},
)
print(resp)
Ruby
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
Js
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
をそのままにします:
Python
resp = client.cluster.put_settings(
persistent={
"cluster": {
"remote": {
"cluster_two": {
"mode": None,
"seeds": None,
"skip_unavailable": None,
"transport.compress": None
}
}
}
},
)
print(resp)
Ruby
response = client.cluster.put_settings(
body: {
persistent: {
cluster: {
remote: {
cluster_two: {
mode: nil,
seeds: nil,
skip_unavailable: nil,
'transport.compress' => nil
}
}
}
}
}
)
puts response
Js
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
}
}
}
}
}
リモートクラスターを静的に構成する
[クラスター更新設定API](/read/elasticsearch-8-15/a43f4ba05b0b929e.md)を使用して指定されたリモートクラスター設定は、`````elasticsearch.yml`````で個々のノードに指定された設定よりも優先されます。
次の例では、`````cluster_one`````、`````cluster_two`````、`````cluster_three`````は、各クラスターへの接続を表す任意のクラスターエイリアスです。これらの名前は、その後、ローカルインデックスとリモートインデックスを区別するために使用されます。
#### Yaml
``````yaml
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_two に対してオプションです。 |
|
cluster_three に接続するために使用されるプロキシエンドポイントのアドレス。 |
リモートクラスターのロールとユーザーを構成する
リモートクラスターに接続した後、ローカルクラスターとリモートクラスターの両方でユーザーロールを作成し、必要な特権を割り当てます。これらのロールは、クロスクラスター複製とクロスクラスター検索を使用するために必要です。
ローカルクラスターとリモートクラスターの両方で同じロール名を使用する必要があります。たとえば、クロスクラスター複製のための次の構成では、ローカルクラスターとリモートクラスターの両方でremote-replication
ロール名を使用します。ただし、各クラスターで異なるロール定義を指定することもできます。
KibanaのStack Managementからセキュリティ > ロールを選択することで、ユーザーとロールを管理できます。また、ロール管理APIを使用して、ロールを動的に追加、更新、削除、取得できます。native
領域でロールを管理するためにAPIを使用すると、ロールは内部Elasticsearchインデックスに保存されます。
次のリクエストは、ロールの作成または更新APIを使用します。このAPIを使用するには、少なくともmanage_security
クラスターの特権が必要です。
クロスクラスター複製の特権を構成する
クロスクラスター複製ユーザーは、リモートクラスターとローカルクラスターで異なるクラスターおよびインデックスの特権を必要とします。次のリクエストを使用して、ローカルクラスターとリモートクラスターで別々のロールを作成し、必要なロールを持つユーザーを作成します。
リモートクラスター
リーダーインデックスを含むリモートクラスターでは、クロスクラスター複製ロールはread_ccr
クラスターの特権と、リーダーインデックスに対するmonitor
およびread
の特権を必要とします。
リクエストがAPIキーで認証されている場合、APIキーはローカルクラスターで上記の特権を必要とします。
リクエストが他のユーザーの代理で発行される場合、認証ユーザーはリモートクラスターでrun_as
の特権を持っている必要があります。
次のリクエストは、リモートクラスターにremote-replication
ロールを作成します:
Python
resp = client.security.put_role(
name="remote-replication",
cluster=[
"read_ccr"
],
indices=[
{
"names": [
"leader-index-name"
],
"privileges": [
"monitor",
"read"
]
}
],
)
print(resp)
Js
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
ロールを作成します:
Python
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)
Js
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
ロールを割り当てます。たとえば、次のリクエストは、cross-cluster-user
という名前のユーザーにremote-replication
ロールを割り当てます:
Python
resp = client.security.put_user(
username="cross-cluster-user",
password="l0ng-r4nd0m-p@ssw0rd",
roles=[
"remote-replication"
],
)
print(resp)
Js
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
ロールを作成します:
Python
resp = client.security.put_role(
name="remote-search",
indices=[
{
"names": [
"target-indices"
],
"privileges": [
"read",
"read_cross_cluster"
]
}
],
)
print(resp)
Js
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
ロールを作成します:
Python
resp = client.security.put_role(
name="remote-search",
)
print(resp)
Js
const response = await client.security.putRole({
name: "remote-search",
});
console.log(response);
コンソール
POST /_security/role/remote-search
{}
各クラスターでremote-search
ロールを作成した後、ユーザーの作成または更新APIを使用して、ローカルクラスターにユーザーを作成し、remote-search
ロールを割り当てます。たとえば、次のリクエストは、cross-search-user
という名前のユーザーにremote-search
ロールを割り当てます:
Python
resp = client.security.put_user(
username="cross-search-user",
password="l0ng-r4nd0m-p@ssw0rd",
roles=[
"remote-search"
],
)
print(resp)
Js
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" ]
}
このユーザーはローカルクラスターでのみ作成する必要があります。
### クロスクラスター検索とKibanaの特権を構成する
Kibanaを使用して複数のクラスターを検索する場合、2段階の認可プロセスが、ユーザーがリモートクラスターのデータストリームおよびインデックスにアクセスできるかどうかを決定します:
- 最初に、ローカルクラスターがユーザーがリモートクラスターにアクセスする権限があるかどうかを判断します。ローカルクラスターはKibanaが接続されているクラスターです。
- ユーザーが権限を持っている場合、リモートクラスターは次に、ユーザーが指定されたデータストリームおよびインデックスにアクセスできるかどうかを判断します。
Kibanaユーザーにリモートクラスターへのアクセスを付与するには、リモートクラスターのインデックスに対する読み取り特権を持つローカルロールを割り当てます。リモートクラスターのデータストリームおよびインデックスを`````<remote_cluster_name>:<target>`````として指定します。
リモートデータストリームおよびインデックスに対する読み取りアクセスをユーザーに付与するには、適切なデータストリームおよびインデックスへのアクセスを持つ`````read_cross_cluster`````特権を付与するリモートクラスターで一致するロールを作成する必要があります。
たとえば、ローカルクラスターでLogstashデータを積極的にインデックスし、定期的に古い時間ベースのインデックスをリモートクラスターのアーカイブにオフロードすることがあります。両方のクラスターを検索したい場合は、両方のクラスターでKibanaユーザーを有効にする必要があります。
#### ローカルクラスター
ローカルクラスターで、ローカル`````logstash-*`````インデックスに対して`````read`````および`````view_index_metadata`````の特権を付与する`````logstash-reader`````ロールを作成します。
ローカルクラスターをElasticsearchの別のリモートとして構成する場合、ローカルクラスターの`````logstash-reader`````ロールも`````read_cross_cluster`````特権を付与する必要があります。
#### Python
``````python
resp = client.security.put_role(
name="logstash-reader",
indices=[
{
"names": [
"logstash-*"
],
"privileges": [
"read",
"view_index_metadata"
]
}
],
)
print(resp)
`
Js
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ユーザーにアクセスを付与するロールを割り当て、logstash_reader
ロールも割り当てます。たとえば、次のリクエストは、cross-cluster-kibana
ユーザーを作成し、kibana-access
およびlogstash-reader
ロールを割り当てます。
Python
resp = client.security.put_user(
username="cross-cluster-kibana",
password="l0ng-r4nd0m-p@ssw0rd",
roles=[
"logstash-reader",
"kibana-access"
],
)
print(resp)
Js
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-*
インデックスに付与します。
Python
resp = client.security.put_role(
name="logstash-reader",
indices=[
{
"names": [
"logstash-*"
],
"privileges": [
"read_cross_cluster",
"read",
"view_index_metadata"
]
}
],
)
print(resp)
Js
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"
]
}
]
}