Cross-cluster search
When accessing a remote cluster from a coordinating cluster using cross-cluster search:
- The security plugin authenticates the user on the coordinating cluster.
- The security plugin fetches the user’s backend roles on the coordinating cluster.
- The call, including the authenticated user, is forwarded to the remote cluster.
- The user’s permissions are evaluated on the remote cluster.
You can have different authentication and authorization configurations on the remote and coordinating cluster, but we recommend using the same settings on both.
To query indices on remote clusters, users need to have the following permissions for the index, in addition to or SEARCH
permissions:
Sample roles.yml configuration
humanresources:
cluster:
- CLUSTER_COMPOSITE_OPS_RO
indices:
'humanresources':
'*':
- READ
- indices:admin/shards/search_shards # needed for CCS
Sample role in OpenSearch Dashboards
Save this file as docker-compose.yml
and run docker-compose up
to start two single-node clusters on the same network:
version: '3'
services:
opensearch-ccs-node1:
image: opensearchproject/opensearch:2.1.0
container_name: opensearch-ccs-node1
environment:
- cluster.name=opensearch-ccs-cluster1
- discovery.type=single-node
- bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- opensearch-data1:/usr/share/opensearch/data
ports:
- 9200:9200
networks:
- opensearch-net
opensearch-ccs-node2:
image: opensearchproject/opensearch:2.1.0
environment:
- cluster.name=opensearch-ccs-cluster2
- discovery.type=single-node
- bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
- "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- opensearch-data2:/usr/share/opensearch/data
ports:
- 9250:9200
- 9700:9600 # required for Performance Analyzer
networks:
- opensearch-net
volumes:
opensearch-data1:
opensearch-data2:
networks:
opensearch-net:
curl -XGET -u 'admin:admin' -k 'https://localhost:9200'
{
"cluster_name" : "opensearch-ccs-cluster1",
...
}
{
"cluster_name" : "opensearch-ccs-cluster2",
...
}
Both clusters run on localhost
, so the important identifier is the port number. In this case, use port 9200 () as the remote cluster, and port 9250 (opensearch-ccs-node2
) as the coordinating cluster.
To get the IP address for the remote cluster, first identify its container ID:
Then get that container’s IP address:
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 6fe89ebc5a8e
172.31.0.3
On the coordinating cluster, add the remote cluster name and the IP address (with port 9300) for each “seed node.” In this case, you only have one seed node:
curl -k -XPUT -H 'Content-Type: application/json' -u 'admin:admin' 'https://localhost:9250/_cluster/settings' -d '
{
"persistent": {
"cluster.remote": {
"opensearch-ccs-cluster1": {
"seeds": ["172.31.0.3:9300"]
}
}
}
}'
On the remote cluster, index a document:
curl -XPUT -k -H 'Content-Type: application/json' -u 'admin:admin' 'https://localhost:9200/books/_doc/1' -d '{"Dracula": "Bram Stoker"}'
To continue testing, create a new user on both clusters:
curl -XPUT -k -u 'admin:admin' 'https://localhost:9200/_plugins/_security/api/internalusers/booksuser' -H 'Content-Type: application/json' -d '{"password":"password"}'
curl -XPUT -k -u 'admin:admin' 'https://localhost:9250/_plugins/_security/api/internalusers/booksuser' -H 'Content-Type: application/json' -d '{"password":"password"}'
Then run the same search as before with booksuser
:
curl -XGET -k -u booksuser:password 'https://localhost:9250/opensearch-ccs-cluster1:books/_search?pretty'
{
"error" : {
"root_cause" : [
{
"type" : "security_exception",
"reason" : "no permissions for [indices:admin/shards/search_shards, indices:data/read/search] and User [name=booksuser, roles=[], requestedTenant=null]"
}
],
"type" : "security_exception",
"reason" : "no permissions for [indices:admin/shards/search_shards, indices:data/read/search] and User [name=booksuser, roles=[], requestedTenant=null]"
},
"status" : 403
}
Note the permissions error. On the remote cluster, create a role with the appropriate permissions, and map booksuser
to that role:
curl -XPUT -k -u 'admin:admin' -H 'Content-Type: application/json' 'https://localhost:9200/_plugins/_security/api/roles/booksrole' -d '{"index_permissions":[{"index_patterns":["books"],"allowed_actions":["indices:admin/shards/search_shards","indices:data/read/search"]}]}'
curl -XPUT -k -u 'admin:admin' -H 'Content-Type: application/json' 'https://localhost:9200/_plugins/_security/api/rolesmapping/booksrole' -d '{"users" : ["booksuser"]}'
Both clusters must have the user, but only the remote cluster needs the role and mapping; in this case, the coordinating cluster handles authentication (i.e. “Does this request include valid user credentials?”), and the remote cluster handles authorization (i.e. “Can this user access this data?”).
Finally, repeat the search: