APIキー認証を使用してリモートクラスターを追加する
APIキー認証により、ローカルクラスターはリモートクラスターと認証を行うことができます。これは、クロスクラスターAPIキーを介して行われます。APIキーはリモートクラスターの管理者によって作成される必要があります。ローカルクラスターは、リモートクラスターへの各リクエストでこのAPIキーを提供するように構成されています。リモートクラスターはAPIキーを検証し、その権限に基づいてアクセスを許可します。
ローカルクラスターからのすべてのクロスクラスターリクエストは、APIキーの権限に制約されます。これは、リクエストに関連付けられたローカルユーザーに関係なく適用されます。たとえば、APIキーがリモートクラスターのmy-index
への読み取りアクセスのみを許可している場合、ローカルクラスターのスーパーユーザーであってもこの制約に制限されます。このメカニズムにより、リモートクラスターの管理者は、誰がどのデータにアクセスできるかを完全に制御できます。リモートクラスターの管理者は、APIキーに明示的に割り当てられたものを超えるアクセスが不可能であることを確信できます。
ローカルクラスター側では、すべてのローカルユーザーがAPIキーによって許可されたすべてのデータにアクセスする必要はありません。ローカルクラスターの管理者は、ローカルユーザーに対して追加の権限制約をさらに構成できるため、各ユーザーは必要なリモートデータにのみアクセスできます。個々のローカルユーザーに対してAPIキーによって許可される権限をさらに減らすことは可能ですが、APIキーによって許可されるものを超えて権限を増やすことは不可能です。
このモデルでは、クロスクラスター操作は、クラスター間の通信のために専用サーバーポート(リモートクラスターインターフェース)を使用します。リモートクラスターは、ローカルクラスターが接続できるようにこのポートを有効にする必要があります。このポートに対してトランスポート層セキュリティ(TLS)を構成してセキュリティを最大化します(リモートクラスターとの信頼を確立するで説明されています)。
ローカルクラスターは、リモートクラスターインターフェースでリモートクラスターを信頼する必要があります。これは、ローカルクラスターがリモートクラスターインターフェースで使用されるサーバー証明書に署名する証明書機関(CA)を信頼することを意味します。接続を確立する際、クロスクラスター通信に参加するローカルクラスターのすべてのノードは、TLS信頼構成に基づいて、他方のノードからの証明書を検証します。
APIキー認証を使用してリモートクラスターを追加するには:
- 1. 前提条件を確認する
- 2. リモートクラスターとの信頼を確立する
- 3. リモートクラスターに接続する
- 4. ロールとユーザーを構成する
問題が発生した場合は、トラブルシューティングを参照してください。
前提条件
- Elasticsearchのセキュリティ機能は、両方のクラスターのすべてのノードで有効にする必要があります。セキュリティはデフォルトで有効です。無効になっている場合は、
xpack.security.enabled
をtrue
に設定します。 一般的なセキュリティ設定を参照してください。 - ローカルクラスターとリモートクラスターのノードは、バージョン8.10以上である必要があります。
- ローカルクラスターとリモートクラスターは、適切なライセンスを持っている必要があります。詳細については、https://www.elastic.co/subscriptionsを参照してください。
リモートクラスターとの信頼を確立する
リモートクラスターがElasticsearchサービスのデプロイメントの一部である場合、デフォルトで有効な証明書があります。したがって、これらの手順における証明書に関連するステップをスキップできます。
リモートクラスターで
- 1. リモートクラスターのすべてのノードでリモートクラスターサーバーを有効にします。
elasticsearch.yml
で:- 1.1.
remote_cluster_server.enabled
をtrue
に設定します。 - 1.2. リモートクラスターサーバートラフィックのバインドおよび公開アドレスを構成します。たとえば、
remote_cluster.host
を使用します。アドレスを構成しないと、リモートクラスターのトラフィックがローカルインターフェースにバインドされ、他のマシンで実行されているリモートクラスターに接続できなくなります。 - 1.3. オプションで、
remote_cluster.port
を使用してリモートサーバーポートを構成します(デフォルトは9443
です)。
- 1.1.
- 2. 次に、証明書機関(CA)とサーバー証明書/キーのペアを生成します。リモートクラスターのノードの1つで、Elasticsearchがインストールされているディレクトリから:
- 2.1. すでにCAを持っていない場合はCAを作成します:
./bin/elasticsearch-certutil ca --pem --out=cross-cluster-ca.zip --pass CA_PASSWORD
CA_PASSWORD
をCAに使用したいパスワードに置き換えます。プロダクション環境にデプロイしない場合は、--pass
オプションとその引数を削除できます。 - 2.2. 生成された
cross-cluster-ca.zip
ファイルを解凍します。この圧縮ファイルには次の内容が含まれています:
- 2.1. すでにCAを持っていない場合はCAを作成します:
テキスト
/ca
|_ ca.crt
|_ ca.key
- 2.3. リモートクラスターのノード用に証明書と秘密鍵のペアを生成します:
./bin/elasticsearch-certutil cert --out=cross-cluster.p12 --pass=CERT_PASSWORD --ca-cert=ca/ca.crt --ca-key=ca/ca.key --ca-pass=CA_PASSWORD --dns=example.com --ip=127.0.0.1
CA_PASSWORD
を前のステップのCAパスワードに置き換えます。CERT_PASSWORD
を生成された秘密鍵に使用したいパスワードに置き換えます。--dns
オプションを使用して、証明書の関連するDNS名を指定します。複数のDNSに対して複数回指定できます。--ip
オプションを使用して、証明書の関連するIPアドレスを指定します。複数のIPアドレスに対して複数回指定できます。- 2.4. リモートクラスターに複数のノードがある場合、次のいずれかを行うことができます:
- すべてのノード用に単一のワイルドカード証明書を作成します。
- または、手動またはサイレントモードで各ノード用に別々の証明書を作成します。
- 3. リモートクラスターのすべてのノードで:
- 3.1. 前のステップで生成された
cross-cluster.p12
ファイルをconfig
ディレクトリにコピーします。ワイルドカード証明書を作成しなかった場合は、正しいノード固有のp12ファイルをコピーすることを確認してください。 - 3.2.
elasticsearch.yml
に次の構成を追加します:
- 3.1. 前のステップで生成された
YAML
xpack.security.remote_cluster_server.ssl.enabled: true
xpack.security.remote_cluster_server.ssl.keystore.path: cross-cluster.p12
- 3.3. SSLキーストアパスワードをElasticsearchキーストアに追加します:
プロンプトが表示されたら、前のステップの./bin/elasticsearch-keystore add xpack.security.remote_cluster_server.ssl.keystore.secure_password
CERT_PASSWORD
を入力します。 - 4. リモートクラスターを再起動します。
- 5. リモートクラスターで、クロスクラスター検索またはクロスクラスター複製に使用するインデックスへのアクセスを提供するクロスクラスターAPIキーを生成します。 クロスクラスターAPIキーを作成する APIまたはKibanaを使用できます。
- 6. エンコードされたキー(応答の
encoded
)を安全な場所にコピーします。後でリモートクラスターに接続するために必要です。
ローカルクラスターで
- 1. ローカルクラスターのすべてのノードで:
- 1.1. リモートクラスターで以前に生成された
ca.crt
ファイルをconfig
ディレクトリにコピーし、ファイル名をremote-cluster-ca.crt
に変更します。 - 1.2.
elasticsearch.yml
に次の構成を追加します:
- 1.1. リモートクラスターで以前に生成された
YAML
xpack.security.remote_cluster_client.ssl.enabled: true
xpack.security.remote_cluster_client.ssl.certificate_authorities: [ "remote-cluster-ca.crt" ]
- 1.3. リモートクラスターで以前に作成されたクロスクラスターAPIキーをキーストアに追加します:
./bin/elasticsearch-keystore add cluster.remote.ALIAS.credentials
ALIAS
を後でリモートクラスターエントリを作成するために使用する同じ名前に置き換えます。プロンプトが表示されたら、リモートクラスターで以前に作成されたエンコードされたクロスクラスターAPIキーを入力します。 - 2. キーストアと設定の変更を読み込むためにローカルクラスターを再起動します。
注意: クロスクラスターAPIキーのみを構成している場合は、クラスターを再起動する代わりにノードのセキュア設定を再読み込み APIを呼び出すことができます。remote_cluster_client
設定をelasticsearch.yml
で構成するには、再起動が必要です。
リモートクラスターに接続する
リモートクラスターに接続するには、manage
クラスター権限が必要です。
ローカルクラスターは、リモートクラスターインターフェースを使用してリモートクラスターとの通信を確立します。ローカルクラスターのコーディネートノードは、リモートクラスターの特定のノードと長期接続のTCP接続を確立します。Elasticsearchは、接続が長時間アイドル状態であっても、これらの接続が開いたままであることを要求します。
Kibanaのスタック管理からリモートクラスターを追加するには:
- 1. サイドナビゲーションからリモートクラスターを選択します。
- 2. リモートクラスターの名前(クラスターエイリアス)を入力します。
- 3. ElasticsearchエンドポイントURL、またはリモートクラスターのIPアドレスまたはホスト名の後にリモートクラスターのポート(デフォルトは
9443
)を指定します。たとえば、cluster.es.eastus2.staging.azure.foundit.no:9443
または192.168.1.1:9443
です。
または、クラスター設定を更新する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:9443"
]
}
}
}
}
}
このリモートクラスターのクラスターエイリアスは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:9443"
],
"connected" : true,
"num_nodes_connected" : 1,
"max_connections_per_cluster" : 3,
"initial_connect_timeout" : "30s",
"skip_unavailable" : true,
"cluster_credentials": "::es_redacted::",
"mode" : "sniff"
}
}
ローカルクラスターが接続されているリモートクラスターのノード数。 | |
クロスクラスター検索を通じて検索された場合、ノードが利用できない場合はリモートクラスターをスキップするかどうかを示します。 | |
存在する場合、リモートクラスターはAPIキー認証を使用して接続されていることを示します。 |
リモートクラスターを動的に構成する
クラスター設定を更新するAPIを使用して、クラスター内のすべてのノードでリモート設定を動的に構成します。次のリクエストは、cluster_one
、cluster_two
、cluster_three
の3つのリモートクラスターを追加します。
`````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:9443"
]
},
"cluster_two": {
"mode": "sniff",
"seeds": [
"127.0.0.1:9444"
],
"transport.compress": true,
"skip_unavailable": true
},
"cluster_three": {
"mode": "proxy",
"proxy_address": "127.0.0.1:9445"
}
}
}
}
}
初期構成後、リモートクラスターの設定を動的に更新できます。次のリクエストは、cluster_two
の圧縮設定とcluster_three
の圧縮およびpingスケジュール設定を更新します。
圧縮またはpingスケジュール設定が変更されると、すべての既存のノード接続は閉じて再オープンする必要があり、これにより進行中のリクエストが失敗する可能性があります。
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:9443
cluster_two:
mode: sniff
seeds: 127.0.0.1:9444
transport.compress: true
skip_unavailable: true
cluster_three:
mode: proxy
proxy_address: 127.0.0.1:9445
`
cluster_two へのリクエストの圧縮が明示的に有効になっています。 |
|
切断されたリモートクラスターはcluster_two に対してオプションです。 |
|
cluster_three に接続するために使用されるプロキシエンドポイントのアドレス。 |
ロールとユーザーを構成する
クロスクラスター複製またはクロスクラスター検索にリモートクラスターを使用するには、ローカルクラスターでリモートインデックス権限を持つユーザーロールを作成する必要があります。
Kibanaのスタック管理から、サイドナビゲーションのセキュリティ > ロールを選択して、ユーザーとロールを管理できます。また、ロール管理APIを使用して、ロールを動的に追加、更新、削除、取得できます。
次の例では、ロールの作成または更新 APIを使用します。このAPIを使用するには、少なくともmanage_security
クラスター権限が必要です。
ローカルクラスターがリモートクラスターに接続するために使用するクロスクラスターAPIキーは、個々のユーザーが必要とするすべてのリモートインデックス権限をカバーするのに十分な権限を持っている必要があります。
クロスクラスター複製のための権限を構成する
リモートクラスターがmy_remote_cluster
という名前で接続されていると仮定すると、次のリクエストは、ローカルクラスターにremote-replication
というロールを作成し、リモートleader-index
インデックスを複製することを許可します:
Python
resp = client.security.put_role(
name="remote-replication",
cluster=[
"manage_ccr"
],
remote_indices=[
{
"clusters": [
"my_remote_cluster"
],
"names": [
"leader-index"
],
"privileges": [
"cross_cluster_replication"
]
}
],
)
print(resp)
Js
const response = await client.security.putRole({
name: "remote-replication",
cluster: ["manage_ccr"],
remote_indices: [
{
clusters: ["my_remote_cluster"],
names: ["leader-index"],
privileges: ["cross_cluster_replication"],
},
],
});
console.log(response);
コンソール
POST /_security/role/remote-replication
{
"cluster": [
"manage_ccr"
],
"remote_indices": [
{
"clusters": [ "my_remote_cluster" ],
"names": [
"leader-index"
],
"privileges": [
"cross_cluster_replication"
]
}
]
}
ローカルremote-replication
ロールを作成した後、ユーザーの作成または更新 APIを使用して、ローカルクラスターにユーザーを作成し、remote-replication
ロールを割り当てます。たとえば、次のリクエストは、remote-replication
ロールをcross-cluster-user
という名前のユーザーに割り当てます:
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" ]
}
このユーザーはローカルクラスターにのみ作成する必要があることに注意してください。
クロスクラスター検索のための権限を構成する
リモートクラスターがmy_remote_cluster
という名前で接続されていると仮定すると、次のリクエストは、ローカルクラスターにremote-search
ロールを作成し、リモートtarget-index
インデックスを検索することを許可します:
Python
resp = client.security.put_role(
name="remote-search",
remote_indices=[
{
"clusters": [
"my_remote_cluster"
],
"names": [
"target-index"
],
"privileges": [
"read",
"read_cross_cluster",
"view_index_metadata"
]
}
],
)
print(resp)
Js
const response = await client.security.putRole({
name: "remote-search",
remote_indices: [
{
clusters: ["my_remote_cluster"],
names: ["target-index"],
privileges: ["read", "read_cross_cluster", "view_index_metadata"],
},
],
});
console.log(response);
コンソール
POST /_security/role/remote-search
{
"remote_indices": [
{
"clusters": [ "my_remote_cluster" ],
"names": [
"target-index"
],
"privileges": [
"read",
"read_cross_cluster",
"view_index_metadata"
]
}
]
}
remote-search
ロールを作成した後、ユーザーの作成または更新 APIを使用して、ローカルクラスターにユーザーを作成し、remote-search
ロールを割り当てます。たとえば、次のリクエストは、remote-search
ロールをcross-search-user
という名前のユーザーに割り当てます:
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" ]
}
このユーザーはローカルクラスターにのみ作成する必要があることに注意してください。