

# Cross-Region and cross-account data access
<a name="application-cross-region-cross-account"></a>

OpenSearch UI supports accessing data from OpenSearch domains across different AWS accounts and AWS Regions. You can choose from two approaches depending on your requirements. The following table compares the two approaches.

**Note**  
Both cross-account data access and cross-cluster search work only with OpenSearch domains. Neither approach supports OpenSearch Serverless collections.


| Aspect | Cross-account data access | Cross-cluster search | 
| --- | --- | --- | 
| Feature | Associate domains from other accounts as direct data sources in OpenSearch UI | Query data across connected domains using cross-cluster search connections | 
| Mechanism | Direct access – OpenSearch UI connects directly to the target domain in another account | Indirect access – requires a local domain in the same account as OpenSearch UI to relay requests to remote domains | 
| Cross-account support | Yes | Yes | 
| Cross-Region support | No – source and target domains must be in the same AWS Region | Yes – source and destination domains can be in different AWS Regions | 
| Union data across domains | No – each domain is queried independently as a separate data source | Yes – a single query can aggregate results from multiple connected domains | 
| Authentication methods | IAM and AWS IAM Identity Center | IAM (with fine-grained access control) | 
| Setup complexity | Lower – requires a cross-account IAM role for validation | Higher – requires cross-cluster connections, access policies on both domains, and fine-grained access control | 
| Data source visibility in OpenSearch UI | Each cross-account domain appears as a separate data source | Remote domains are accessed through the local source domain's connection aliases | 
| Write access to remote domain | Yes – controlled by the target domain's access policy | No – cross-cluster search provides read-only access to remote domains | 

**Topics**
+ [Cross-account data access to OpenSearch domains](application-cross-account-data-access-domains.md)
+ [Cross-cluster search](application-cross-cluster-search.md)

# Cross-account data access to OpenSearch domains
<a name="application-cross-account-data-access-domains"></a>

You can configure your OpenSearch UI applications in one account to access OpenSearch domains in different accounts. When you create an OpenSearch UI application with cross-account data sources, you provide an `iamRoleForDataSourceArn` that points to an IAM role in the target account. OpenSearch UI validates the request by assuming this role and calling `es:DescribeDomain` to verify domain accessibility. The cross-account role is used only for control plane validation. Data plane access is controlled separately by the target domain's access policy.

**Sample code**  
The code examples in this topic are for illustration purposes only. They demonstrate basic functionality and may not include error handling, security best practices, or production-ready features. Before using sample code in production, review and modify it to meet your specific requirements, and test thoroughly in your environment.

## Key concepts
<a name="cross-account-key-concepts"></a>

Source account  
The AWS account that hosts your OpenSearch UI application.

Target account  
The AWS account where the OpenSearch domain resides.

Cross-account role  
An IAM role in the target account that is used for control plane validation only. This role requires only the `es:DescribeDomain` permission.

IAM Identity Center application role  
An IAM role in the source account that is used for IAM Identity Center user data plane access.

## Prerequisites
<a name="cross-account-prerequisites"></a>

Before you set up cross-account data access, ensure that you have the following:
+ AWS CLI installed and configured
+ Access to both the source and target AWS accounts
+ For IAM Identity Center flows: An AWS IAM Identity Center organization instance

## Scenarios
<a name="cross-account-scenarios"></a>

Choose the scenario that matches your authentication method and domain configuration:
+ [Scenario 1: IAM user accessing a public domain](#cross-account-scenario-1)
+ [Scenario 2: IAM Identity Center user accessing a public domain](#cross-account-scenario-2)
+ [Scenario 3: IAM user accessing a VPC domain](#cross-account-scenario-3)
+ [Scenario 4: IAM Identity Center user accessing a VPC domain](#cross-account-scenario-4)

## Scenario 1: IAM user accessing a public domain
<a name="cross-account-scenario-1"></a>

### Step 1: Create the cross-account IAM role (target account)
<a name="scenario-1-step-1"></a>

Create an IAM role in the target account that allows the source account to assume it for domain validation.

**To create the cross-account role**

1. Create a trust policy that allows the source account to assume the role:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Principal": {
         "AWS": "arn:aws:iam::source-account-id:root"
       },
       "Action": "sts:AssumeRole"
     }]
   }
   ```

1. Create the role:

   ```
   aws iam create-role \
     --role-name OpenSearchUIAccessRole \
     --assume-role-policy-document file://trust-policy.json
   ```

1. Create a permissions policy with only the `es:DescribeDomain` action:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Action": "es:DescribeDomain",
       "Resource": "arn:aws:es:region:target-account-id:domain/*"
     }]
   }
   ```

1. Attach the permissions policy to the role:

   ```
   aws iam put-role-policy \
     --role-name OpenSearchUIAccessRole \
     --policy-name ValidationOnly \
     --policy-document file://permissions-policy.json
   ```

### Step 2: Create the OpenSearch domain (target account)
<a name="scenario-1-step-2"></a>

Create an OpenSearch domain in the target account with fine-grained access control and encryption enabled:

```
aws opensearch create-domain \
  --domain-name domain-name \
  --engine-version OpenSearch_2.19 \
  --cluster-config InstanceType=m5.large.search,InstanceCount=1 \
  --ebs-options "EBSEnabled=true,VolumeType=gp3,VolumeSize=100" \
  --advanced-security-options '{"Enabled":true,"InternalUserDatabaseEnabled":true,"MasterUserOptions":{"MasterUserName":"admin","MasterUserPassword":"master-password"}}' \
  --node-to-node-encryption-options '{"Enabled":true}' \
  --encryption-at-rest-options '{"Enabled":true}' \
  --domain-endpoint-options '{"EnforceHTTPS":true,"TLSSecurityPolicy":"Policy-Min-TLS-1-2-2019-07"}' \
  --access-policies '{"Version":"2012-10-17",		 	 	 "Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"es:ESHttp*","Resource":"arn:aws:es:region:target-account-id:domain/domain-name/*"}]}' \
  --region region
```

Wait for the domain status to become `Active` before proceeding.

### Step 3: Create the OpenSearch UI application (source account)
<a name="scenario-1-step-3"></a>

Create the application in the source account with the cross-account data source:

```
aws opensearch create-application \
  --region region \
  --name "cross-account-iam-app" \
  --data-sources '[{
    "dataSourceArn":"arn:aws:es:region:target-account-id:domain/domain-name",
    "dataSourceDescription":"Cross-account domain",
    "iamRoleForDataSourceArn":"arn:aws:iam::target-account-id:role/OpenSearchUIAccessRole"
  }]' \
  --app-configs '[{"key":"opensearchDashboards.dashboardAdmin.users","value":"[\"*\"]"}]'
```

### Step 4: Verify and access
<a name="scenario-1-step-4"></a>

Retrieve the application details to get the endpoint URL:

```
aws opensearch get-application \
  --region region \
  --id application-id
```
+ Navigate to the application endpoint URL from the response.
+ Sign in with IAM credentials.
+ The IAM user signs data plane requests with their own credentials.
+ The target domain access policy controls what data the user can access.

## Scenario 2: IAM Identity Center user accessing a public domain
<a name="cross-account-scenario-2"></a>

### Step 1: Create the cross-account IAM role (target account)
<a name="scenario-2-step-1"></a>

Create an IAM role in the target account that allows the source account to assume it for domain validation.

**To create the cross-account role**

1. Create a trust policy that allows the source account to assume the role:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Principal": {
         "AWS": "arn:aws:iam::source-account-id:root"
       },
       "Action": "sts:AssumeRole"
     }]
   }
   ```

1. Create the role:

   ```
   aws iam create-role \
     --role-name OpenSearchUIAccessRole \
     --assume-role-policy-document file://trust-policy.json
   ```

1. Create a permissions policy with only the `es:DescribeDomain` action:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Action": "es:DescribeDomain",
       "Resource": "arn:aws:es:region:target-account-id:domain/*"
     }]
   }
   ```

1. Attach the permissions policy to the role:

   ```
   aws iam put-role-policy \
     --role-name OpenSearchUIAccessRole \
     --policy-name ValidationOnly \
     --policy-document file://permissions-policy.json
   ```

### Step 2: Create the OpenSearch domain (target account)
<a name="scenario-2-step-2"></a>

Create an OpenSearch domain in the target account. Use the same command as [Step 2: Create the OpenSearch domain (target account)](#scenario-1-step-2), but update the access policy to allow the IAM Identity Center application role from the source account:

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::source-account-id:role/NeoIdCAppRole"
    },
    "Action": "es:ESHttp*",
    "Resource": "arn:aws:es:region:target-account-id:domain/domain-name/*"
  }]
}
```

Wait for the domain status to become `Active` before proceeding.

### Step 3: Create the IAM role for IAM Identity Center application (source account)
<a name="scenario-2-step-3"></a>

Create an IAM role in the source account that OpenSearch UI uses for IAM Identity Center user data plane access.

**To create the IAM Identity Center application role**

1. Create a trust policy:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "application.opensearchservice.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       },
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "application.opensearchservice.amazonaws.com"
         },
         "Action": "sts:SetContext",
         "Condition": {
           "ForAllValues:ArnEquals": {
             "sts:RequestContextProviders": "arn:aws:iam::source-account-id:oidc-provider/portal.sso.region.amazonaws.com/apl/application-id"
           }
         }
       }
     ]
   }
   ```

1. Create a permissions policy:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Sid": "OpenSearchDomain",
       "Effect": "Allow",
       "Action": ["es:ESHttp*"],
       "Resource": "*"
     }]
   }
   ```

1. Create the role and attach the policies:

   ```
   aws iam create-role \
     --role-name NeoIdCAppRole \
     --assume-role-policy-document file://neoidc-trust-policy.json
   
   aws iam put-role-policy \
     --role-name NeoIdCAppRole \
     --policy-name NeoIdCAppPermissions \
     --policy-document file://neoidc-permissions-policy.json
   ```

### Step 4: Create the OpenSearch UI application with IAM Identity Center (source account)
<a name="scenario-2-step-4"></a>

```
aws opensearch create-application \
  --region region \
  --name "cross-account-idc-app" \
  --iam-identity-center-options '{
    "enabled":true,
    "iamIdentityCenterInstanceArn":"arn:aws:sso:::instance/ssoins-instance-id",
    "iamRoleForIdentityCenterApplicationArn":"arn:aws:iam::source-account-id:role/NeoIdCAppRole"
  }' \
  --data-sources '[{
    "dataSourceArn":"arn:aws:es:region:target-account-id:domain/domain-name",
    "dataSourceDescription":"Cross-account domain",
    "iamRoleForDataSourceArn":"arn:aws:iam::target-account-id:role/OpenSearchUIAccessRole"
  }]' \
  --app-configs '[{"key":"opensearchDashboards.dashboardAdmin.users","value":"[\"*\"]"}]'
```

### Step 5: Create and assign IAM Identity Center users and groups
<a name="scenario-2-step-5"></a>

**Create an IAM Identity Center user**  
Run the following command. Replace the *placeholder values* with your own information.

```
aws identitystore create-user \
  --identity-store-id d-directory-id \
  --user-name user-email \
  --display-name "display-name" \
  --name Formatted=string,FamilyName=last-name,GivenName=first-name \
  --emails Value=user-email,Type=work,Primary=true
```

**Create an IAM Identity Center group and add the user**  
Run the following commands:

```
aws identitystore create-group \
  --identity-store-id d-directory-id \
  --display-name "OpenSearchUsers" \
  --description "Users with OpenSearch access"

aws identitystore create-group-membership \
  --identity-store-id d-directory-id \
  --group-id group-id \
  --member-id UserId=user-id
```

**Assign the user or group to the application**  
Run the following command:

```
aws sso-admin create-application-assignment \
  --application-arn "arn:aws:sso:::source-account-id:application/ssoins-instance-id/apl-application-id" \
  --principal-id user-id-or-group-id \
  --principal-type USER
```

**Configure backend role mapping on the target domain**  
Map the IAM Identity Center group to an OpenSearch security role on the target domain:

```
curl -XPUT "https://domain-endpoint/_plugins/_security/api/rolesmapping/all_access" \
  -u admin:master-password \
  -H 'Content-Type: application/json' \
  -d '{
    "backend_roles": ["group-id"],
    "hosts": [],
    "users": []
  }'
```

### Step 6: Verify and access
<a name="scenario-2-step-6"></a>

```
aws opensearch get-application \
  --region region \
  --id application-id
```
+ Navigate to the application endpoint URL.
+ Sign in with IAM Identity Center user credentials.
+ IAM Identity Center users' data requests are signed with the IAM Identity Center application role, not the cross-account role.
+ Backend role mappings on the domain control data access permissions.

## Scenario 3: IAM user accessing a VPC domain
<a name="cross-account-scenario-3"></a>

### Step 1: Create the cross-account IAM role (target account)
<a name="scenario-3-step-1"></a>

Create an IAM role in the target account that allows the source account to assume it for domain validation.

**To create the cross-account role**

1. Create a trust policy that allows the source account to assume the role:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Principal": {
         "AWS": "arn:aws:iam::source-account-id:root"
       },
       "Action": "sts:AssumeRole"
     }]
   }
   ```

1. Create the role:

   ```
   aws iam create-role \
     --role-name OpenSearchUIAccessRole \
     --assume-role-policy-document file://trust-policy.json
   ```

1. Create a permissions policy with only the `es:DescribeDomain` action:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Action": "es:DescribeDomain",
       "Resource": "arn:aws:es:region:target-account-id:domain/*"
     }]
   }
   ```

1. Attach the permissions policy to the role:

   ```
   aws iam put-role-policy \
     --role-name OpenSearchUIAccessRole \
     --policy-name ValidationOnly \
     --policy-document file://permissions-policy.json
   ```

### Step 2: Set up the VPC (target account)
<a name="scenario-3-step-2"></a>

Skip this step if a VPC already exists in the target account.

```
# Create VPC
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --region region

# Create subnet
aws ec2 create-subnet \
  --vpc-id vpc-id \
  --cidr-block 10.0.1.0/24 \
  --availability-zone regiona \
  --region region

# Create security group
aws ec2 create-security-group \
  --group-name opensearch-vpc-sg \
  --description "Security group for OpenSearch VPC domain" \
  --vpc-id vpc-id \
  --region region

# Allow inbound HTTPS
aws ec2 authorize-security-group-ingress \
  --group-id security-group-id \
  --protocol tcp \
  --port 443 \
  --cidr 10.0.0.0/16 \
  --region region
```

Learn more about [VPC domain creation](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/vpc.html).

### Step 3: Create the VPC domain (target account)
<a name="scenario-3-step-3"></a>

```
aws opensearch create-domain \
  --domain-name vpc-domain-name \
  --engine-version OpenSearch_2.19 \
  --cluster-config InstanceType=m5.large.search,InstanceCount=1 \
  --ebs-options "EBSEnabled=true,VolumeType=gp3,VolumeSize=100" \
  --vpc-options "SubnetIds=subnet-id,SecurityGroupIds=security-group-id" \
  --advanced-security-options '{"Enabled":true,"InternalUserDatabaseEnabled":true,"MasterUserOptions":{"MasterUserName":"admin","MasterUserPassword":"master-password"}}' \
  --node-to-node-encryption-options '{"Enabled":true}' \
  --encryption-at-rest-options '{"Enabled":true}' \
  --domain-endpoint-options '{"EnforceHTTPS":true,"TLSSecurityPolicy":"Policy-Min-TLS-1-2-2019-07"}' \
  --access-policies '{"Version":"2012-10-17",		 	 	 "Statement":[{"Effect":"Allow","Principal":{"AWS":"*"},"Action":"es:ESHttp*","Resource":"arn:aws:es:region:target-account-id:domain/vpc-domain-name/*"}]}' \
  --region region
```

Wait for the domain status to become `Active` before proceeding.

### Step 4: Authorize the VPC endpoint for the OpenSearch UI service principal (target account)
<a name="scenario-3-step-4"></a>

**Important**  
This is a critical step that is unique to VPC domains. The OpenSearch UI service must be explicitly authorized to access the VPC endpoint.

```
# Authorize the service principal
aws opensearch authorize-vpc-endpoint-access \
  --domain-name vpc-domain-name \
  --service "application.opensearchservice.amazonaws.com" \
  --region region

# Verify authorization
aws opensearch list-vpc-endpoint-access \
  --domain-name vpc-domain-name \
  --region region
```

Expected response:

```
{
  "AuthorizedPrincipalList": [
    {
      "PrincipalType": "AWS_SERVICE",
      "Principal": "application.opensearchservice.amazonaws.com"
    }
  ]
}
```

### Step 5: Create the OpenSearch UI application (source account)
<a name="scenario-3-step-5"></a>

```
aws opensearch create-application \
  --region region \
  --name "cross-account-vpc-iam-app" \
  --data-sources '[{
    "dataSourceArn":"arn:aws:es:region:target-account-id:domain/vpc-domain-name",
    "dataSourceDescription":"Cross-account VPC domain",
    "iamRoleForDataSourceArn":"arn:aws:iam::target-account-id:role/OpenSearchUIAccessRole"
  }]' \
  --app-configs '[{"key":"opensearchDashboards.dashboardAdmin.users","value":"[\"*\"]"}]'
```

### Step 6: Verify and access
<a name="scenario-3-step-6"></a>

Retrieve the application details to get the endpoint URL:

```
aws opensearch get-application \
  --region region \
  --id application-id
```
+ Navigate to the application endpoint URL from the response.
+ Sign in with IAM credentials.
+ The IAM user signs data plane requests with their own credentials.
+ The target domain access policy controls what data the user can access.

## Scenario 4: IAM Identity Center user accessing a VPC domain
<a name="cross-account-scenario-4"></a>

### Step 1: Create the cross-account IAM role (target account)
<a name="scenario-4-step-1"></a>

Create an IAM role in the target account that allows the source account to assume it for domain validation.

**To create the cross-account role**

1. Create a trust policy that allows the source account to assume the role:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Principal": {
         "AWS": "arn:aws:iam::source-account-id:root"
       },
       "Action": "sts:AssumeRole"
     }]
   }
   ```

1. Create the role:

   ```
   aws iam create-role \
     --role-name OpenSearchUIAccessRole \
     --assume-role-policy-document file://trust-policy.json
   ```

1. Create a permissions policy with only the `es:DescribeDomain` action:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Effect": "Allow",
       "Action": "es:DescribeDomain",
       "Resource": "arn:aws:es:region:target-account-id:domain/*"
     }]
   }
   ```

1. Attach the permissions policy to the role:

   ```
   aws iam put-role-policy \
     --role-name OpenSearchUIAccessRole \
     --policy-name ValidationOnly \
     --policy-document file://permissions-policy.json
   ```

### Step 2: Set up the VPC (target account)
<a name="scenario-4-step-2"></a>

Skip this step if a VPC already exists in the target account.

```
# Create VPC
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --region region

# Create subnet
aws ec2 create-subnet \
  --vpc-id vpc-id \
  --cidr-block 10.0.1.0/24 \
  --availability-zone regiona \
  --region region

# Create security group
aws ec2 create-security-group \
  --group-name opensearch-vpc-sg \
  --description "Security group for OpenSearch VPC domain" \
  --vpc-id vpc-id \
  --region region

# Allow inbound HTTPS
aws ec2 authorize-security-group-ingress \
  --group-id security-group-id \
  --protocol tcp \
  --port 443 \
  --cidr 10.0.0.0/16 \
  --region region
```

Learn more about [VPC domain creation](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/vpc.html).

### Step 3: Create the VPC domain (target account)
<a name="scenario-4-step-3"></a>

Use the same command as [Step 3: Create the VPC domain (target account)](#scenario-3-step-3), but update the access policy to allow the IAM Identity Center application role from the source account:

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::source-account-id:role/NeoIdCAppRole"
    },
    "Action": "es:ESHttp*",
    "Resource": "arn:aws:es:region:target-account-id:domain/vpc-domain-name/*"
  }]
}
```

Wait for the domain status to become `Active` before proceeding.

### Step 4: Authorize the VPC endpoint for the OpenSearch UI service principal (target account)
<a name="scenario-4-step-4"></a>

**Important**  
This is a critical step that is unique to VPC domains. The OpenSearch UI service must be explicitly authorized to access the VPC endpoint.

```
# Authorize the service principal
aws opensearch authorize-vpc-endpoint-access \
  --domain-name vpc-domain-name \
  --service "application.opensearchservice.amazonaws.com" \
  --region region

# Verify authorization
aws opensearch list-vpc-endpoint-access \
  --domain-name vpc-domain-name \
  --region region
```

Expected response:

```
{
  "AuthorizedPrincipalList": [
    {
      "PrincipalType": "AWS_SERVICE",
      "Principal": "application.opensearchservice.amazonaws.com"
    }
  ]
}
```

### Step 5: Create the IAM role for IAM Identity Center application (source account)
<a name="scenario-4-step-5"></a>

Create an IAM role in the source account that OpenSearch UI uses for IAM Identity Center user data plane access.

**To create the IAM Identity Center application role**

1. Create a trust policy:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "application.opensearchservice.amazonaws.com"
         },
         "Action": "sts:AssumeRole"
       },
       {
         "Effect": "Allow",
         "Principal": {
           "Service": "application.opensearchservice.amazonaws.com"
         },
         "Action": "sts:SetContext",
         "Condition": {
           "ForAllValues:ArnEquals": {
             "sts:RequestContextProviders": "arn:aws:iam::source-account-id:oidc-provider/portal.sso.region.amazonaws.com/apl/application-id"
           }
         }
       }
     ]
   }
   ```

1. Create a permissions policy:

   ```
   {
     "Version": "2012-10-17",		 	 	 
     "Statement": [{
       "Sid": "OpenSearchDomain",
       "Effect": "Allow",
       "Action": ["es:ESHttp*"],
       "Resource": "*"
     }]
   }
   ```

1. Create the role and attach the policies:

   ```
   aws iam create-role \
     --role-name NeoIdCAppRole \
     --assume-role-policy-document file://neoidc-trust-policy.json
   
   aws iam put-role-policy \
     --role-name NeoIdCAppRole \
     --policy-name NeoIdCAppPermissions \
     --policy-document file://neoidc-permissions-policy.json
   ```

### Step 6: Create the OpenSearch UI application with IAM Identity Center (source account)
<a name="scenario-4-step-6"></a>

```
aws opensearch create-application \
  --region region \
  --name "cross-account-vpc-idc-app" \
  --iam-identity-center-options '{
    "enabled":true,
    "iamIdentityCenterInstanceArn":"arn:aws:sso:::instance/ssoins-instance-id",
    "iamRoleForIdentityCenterApplicationArn":"arn:aws:iam::source-account-id:role/NeoIdCAppRole"
  }' \
  --data-sources '[{
    "dataSourceArn":"arn:aws:es:region:target-account-id:domain/vpc-domain-name",
    "dataSourceDescription":"Cross-account VPC domain",
    "iamRoleForDataSourceArn":"arn:aws:iam::target-account-id:role/OpenSearchUIAccessRole"
  }]' \
  --app-configs '[{"key":"opensearchDashboards.dashboardAdmin.users","value":"[\"*\"]"}]'
```

### Step 7: Create and assign IAM Identity Center users and groups
<a name="scenario-4-step-7"></a>

**Create an IAM Identity Center user**  
Run the following command. Replace the *placeholder values* with your own information.

```
aws identitystore create-user \
  --identity-store-id d-directory-id \
  --user-name user-email \
  --display-name "display-name" \
  --name Formatted=string,FamilyName=last-name,GivenName=first-name \
  --emails Value=user-email,Type=work,Primary=true
```

**Create an IAM Identity Center group and add the user**  
Run the following commands:

```
aws identitystore create-group \
  --identity-store-id d-directory-id \
  --display-name "OpenSearchUsers" \
  --description "Users with OpenSearch access"

aws identitystore create-group-membership \
  --identity-store-id d-directory-id \
  --group-id group-id \
  --member-id UserId=user-id
```

**Assign the user or group to the application**  
Run the following command:

```
aws sso-admin create-application-assignment \
  --application-arn "arn:aws:sso:::source-account-id:application/ssoins-instance-id/apl-application-id" \
  --principal-id user-id-or-group-id \
  --principal-type USER
```

**Configure backend role mapping on the target domain**  
Map the IAM Identity Center group to an OpenSearch security role on the target domain:

```
curl -XPUT "https://domain-endpoint/_plugins/_security/api/rolesmapping/all_access" \
  -u admin:master-password \
  -H 'Content-Type: application/json' \
  -d '{
    "backend_roles": ["group-id"],
    "hosts": [],
    "users": []
  }'
```

### Step 8: Verify and access
<a name="scenario-4-step-8"></a>

```
aws opensearch get-application \
  --region region \
  --id application-id
```
+ Navigate to the application endpoint URL.
+ Sign in with IAM Identity Center user credentials.
+ IAM Identity Center users' data requests are signed with the IAM Identity Center application role, not the cross-account role.
+ Backend role mappings on the domain control data access permissions.

## Managing applications
<a name="cross-account-managing-applications"></a>

**Update an application with cross-account data sources**  
Run the following command. Replace the *placeholder values* with your own information.

```
aws opensearch update-application \
  --region region \
  --id application-id \
  --data-sources '[{
    "dataSourceArn":"arn:aws:es:region:target-account-id:domain/domain-1",
    "dataSourceDescription":"First cross-account domain",
    "iamRoleForDataSourceArn":"arn:aws:iam::target-account-id:role/OpenSearchUIAccessRole"
  },{
    "dataSourceArn":"arn:aws:es:region:target-account-id:domain/domain-2",
    "dataSourceDescription":"Second cross-account domain",
    "iamRoleForDataSourceArn":"arn:aws:iam::target-account-id:role/OpenSearchUIAccessRole"
  }]'
```

**Important**  
The update operation replaces the entire data sources array. Include all data sources that you want to keep.

**List applications**  
Run the following command:

```
aws opensearch list-applications \
  --region region
```

**Delete an application**  
Run the following command:

```
aws opensearch delete-application \
  --region region \
  --id application-id
```

**Revoke VPC endpoint access**  
Run the following command:

```
aws opensearch revoke-vpc-endpoint-access \
  --domain-name vpc-domain-name \
  --service "application.opensearchservice.amazonaws.com" \
  --region region
```

## Quick reference
<a name="cross-account-quick-reference"></a>

The following tables summarize the key differences between domain types and authentication methods.


**Public domain compared to VPC domain**  

| Aspect | Public domain | VPC domain | 
| --- | --- | --- | 
| VPC endpoint authorization | Not required | Required – must authorize application.opensearchservice.amazonaws.com | 
| Network setup | None | VPC, subnet, security group with HTTPS (443) inbound | 
| IAM access policy | Required | Required | 
| Cross-account role | Required for cross-account | Required for cross-account | 


**IAM user compared to IAM Identity Center user**  

| Aspect | IAM user | IAM Identity Center user | 
| --- | --- | --- | 
| Data plane credentials | User's own IAM credentials | IAM Identity Center application role | 
| Access control | Domain access policy | Domain access policy and backend role mappings | 
| Additional setup | None | IAM Identity Center application role, user/group creation, application assignment, backend role mapping | 
| OpenSearch UI application configuration | No IAM Identity Center options | --iam-identity-center-options required | 

## Important notes
<a name="cross-account-important-notes"></a>
+ The `iamRoleForDataSourceArn` must be in the same account as the `dataSourceArn`.
+ The `iamRoleForDataSourceArn` is only required for cross-account data sources. Omit it for same-account data sources.
+ The cross-account role only needs the `es:DescribeDomain` permission. It is never used for data plane access.
+ For VPC domains, both the IAM policy and VPC endpoint authorization must be configured.
+ Supported engine versions: OpenSearch 1.3 and above.

## Troubleshooting
<a name="cross-account-troubleshooting"></a>


| Issue | Resolution | 
| --- | --- | 
| Application creation fails with "Unable to access domain" | Verify that the cross-account role has the es:DescribeDomain permission and that the trust policy allows the source account. | 
| VPC domain association fails | Ensure that the VPC endpoint is authorized for application.opensearchservice.amazonaws.com. | 
| Data plane access denied for IAM user | Check that the target domain access policy allows the IAM user or role principal. | 
| Data plane access denied for IAM Identity Center user | Verify that the backend role mapping includes the IAM Identity Center group ID, and that the domain policy allows the IAM Identity Center application role. | 
| Account mismatch error | Ensure that iamRoleForDataSourceArn is in the same account as the domain in dataSourceArn. | 

# Cross-cluster search
<a name="application-cross-cluster-search"></a>

Using [Cross-cluster search](cross-cluster-search.md) in Amazon OpenSearch Serverless, you can perform queries and aggregations across multiple connected domains. 

Cross-cluster search in Amazon OpenSearch Serverless uses the concepts of a *source domain * and *destination domain*. A cross-cluster search request originates from a source domain. The destination domain can be in a different AWS account or AWS Region (or both) for the source domain to query from. Using cross-cluster search, you can configure a source domain to associate with your OpenSearch UI in the same account and then create connections to destination domains. As a result, you can use OpenSearch UI with data from the destination domains even if they are in a different account or Region. 

You pay [standard AWS data transfer charges](https://aws.amazon.com/opensearch-service/pricing/) for data transferred in and out of Amazon OpenSearch Service. You are not charged for data transferred between nodes within your OpenSearch Service domain. For more information about data "in" and "out" charges, see [Data Transfer](https://aws.amazon.com/ec2/pricing/on-demand/#Data_Transfer) on the *Amazon EC2 On-Demand Pricing* page.

You can use cross-cluster search as the mechanism for your OpenSearch UI to be associated with clusters in a different account or different Region. The requests between domains are encrypted in transit by default as part of the node-to-node encryption. 

**Note**  
The open source OpenSearch tool also documents [cross-cluster search](https://opensearch.org/docs/latest/search-plugins/cross-cluster-search/). Note that setup for the open source tool differs significantly for open source clusters as compared to managed Amazon OpenSearch Serverless domains.  
Most notably, in Amazon OpenSearch Serverless, you configure cross-cluster connections using the AWS Management Console instead of using `cURL` requests. The managed service uses AWS Identity and Access Management (IAM) for cross-cluster authentication in addition to fine-grained access control.   
Therefore, we recommend using the content in this topic to configure cross-cluster search for your domains instead of the open source OpenSearch documentation.

**Functional differences when using cross-cluster search**  
In comparison to regular domains, destination domains created using Cross-cluster search have the following functional differences and requirements:
+ You can't write to or run `PUT` commands to the remote cluster. Your access to the remote cluster is *read-only*. 
+ Both the source and destination domain must be OpenSearch domains. You can't connect an Elasticsearch domain or self-managed OpenSearch/Elasticsearch clusters for OpenSearch UI.
+ A domain can have a maximum of 20 connections to other domains. This includes both outgoing and incoming connections.
+ The source domain must be on the same or a higher version of OpenSearch than the destination domain. If you want to set up bi-directional connections between two domains, the two domains should be in the same version. We recommend upgrading both domains to the latest version before making the connection. If you need to update domains after setting up the bi-directional connection, you must first delete the connection, and then recreate it afterwards. 
+ You can't use custom dictionaries or SQL with the remote clusters.
+ You can't use CloudFormation to connect domains.
+ You can't use cross-cluster search on M3 or burstable (T2 and T3) instances.
+ Cross-cluster search does not work for Amazon OpenSearch Serverless collections. 

**Cross-cluster search prerequisites for OpenSearch UI**  
Before you set up cross-cluster search with two OpenSearch domains, make sure that your domains meet the following requirements: 
+ Fine-grained access control is enabled for both domains
+ Node-to-node encryption is enabled for both domains

**Topics**
+ [Setting up access permissions for cross-Region and cross-account data access with cross-cluster search](#cross-cluster-search-security)
+ [Creating a connection between domains](#cross-cluster-search-create-connection)
+ [Testing your security setup for cross-Region and cross-account data access with cross-cluster search](#cross-cluster-search-security-testing)
+ [Deleting a connection](#cross-cluster-search-deleting-connection)

## Setting up access permissions for cross-Region and cross-account data access with cross-cluster search
<a name="cross-cluster-search-security"></a>

When you send a cross-cluster search request to the source domain, the domain evaluates that request against its domain access policy. Cross-cluster search requires fine-grained access control. The following is an example with an open access policy on the source domain.

------
#### [ JSON ]

****  

```
{
"Version":"2012-10-17",		 	 	 
"Statement": [
    {
        "Effect": "Allow",
        "Principal": {
          "AWS": [
            "*"
        ]
      },
      "Action": [
        "es:ESHttp*"
      ],
      "Resource": "arn:aws:es:us-east-1:111222333444:domain/src-domain/*"
    }
  ]
}
```

------

**Note**  
If you include remote indexes in the path, you must URL-encode the URI in the domain ARN.  
For example, use the following ARN format:   
`:arn:aws:es:us-east-1:111222333444:domain/my-domain/local_index,dst%3Aremote_index`  
Do not use the following ARN format:  
`arn:aws:es:us-east-1:111222333444:domain/my-domain/local_index,dst:remote_index.`

If you choose to use a restrictive access policy in addition to fine-grained access control, your policy must at minimum allow access to `es:ESHttpGet`. The following is an example:

------
#### [ JSON ]

****  

```
{
"Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": [
          "arn:aws:iam::111222333444:user/john-doe"
        ]
      },
      "Action": "es:ESHttpGet",
      "Resource": "arn:aws:es:us-east-1:111122223333:domain/my-domain/*"
    }
  ]
}
```

------

[Fine-grained access control](fgac.md) on the source domain evaluates the request to determine if it's signed with valid IAM or HTTP basic credentials. If it is, fine-grained access control next evaluates whether the user has permission to perform the search and access the data.

The following are the permission requirements for searches:
+ If the request searches only data on the destination domain (for example, `dest-alias:dest-index/_search)`, permissions are required only on the destination domain. 
+ If the request searches data on both domains (for example, `source-index,dest-alias:dest-index/_search)`, permissions are required on both domains. 
+ To use fine-grained access control, the permission `indices:admin/shards/search_shards` is required in addition to standard read or search permissions for the relevant indexes.

The source domain passes the request to the destination domain. The destination domain evaluates this request against its domain access policy. To support all features in OpenSearch UI, such as indexing documents and performing standard searches, full permissions must be set. The following is an example of our recommended policy on the destination domain:

------
#### [ JSON ]

****  

```
{
"Version":"2012-10-17",		 	 	 
 "Statement": [
    {
       "Effect": "Allow",
       "Principal": {
         "AWS": [
           "*"
        ]
      },
      "Action": [
        "es:ESHttp*"
      ],
      "Resource": "arn:aws:es:us-east-2:111222333444:domain/my-destination-domain/*"
    },
    {
    "Effect": "Allow",
        "Principal": {
    "AWS": "*"
      },
      "Action": "es:ESCrossClusterGet",
      "Resource": "arn:aws:es:us-east-2:111222333444:domain/"
    }
  ]
}
```

------

If you want to perform only basic searches, the minimum policy requirement is for the `es:ESCrossClusterGet` permission to be applied for the destination domain without wildcard support. For example, in the preceding policy, you would specify the domain name as */my-destination-domain* and not */my-destination-domain/\$1*.

In this case, the destination domain performs the search and returns the results to the source domain. The source domain combines its own results (if any) with the results from the destination domain and returns them to you.

## Creating a connection between domains
<a name="cross-cluster-search-create-connection"></a>

A cross-cluster search connection is unidirectional from the source domain to the destination domain. This means that the destination domains (in a different account or Region) can't query the source domain, which is local to the OpenSearch UI. The source domain creates an *outbound* connection to the destination domain. The destination domain receives an *inbound* connection request from the source domain. 

![\[This image illustrates that a cross-cluster search connection is unidirectional from the source domain to the destination domain.\]](http://docs.aws.amazon.com/opensearch-service/latest/developerguide/images/ui-oubound-inbound-connections.png)


**To create a connection between domains**

1. Sign in to the Amazon OpenSearch Service console at [https://console.aws.amazon.com/aos/home](https://console.aws.amazon.com/aos/home).

1. In the left navigation, choose **Domains**.

1. Choose the name of a domain to serve as the source domain, and then choose the **Connections** tab. 

1. In the **Outbound connections** area, choose **Request**. 

1. For **Connection alias**, enter a name for your connection. The connection alias is used in OpenSearch UI for selecting the destination domains. 

1. For **Connection mode**, choose **Direct** for cross-cluster searches or replication.

1. To specify that the connection should skip unavailable clusters during a search, select the **Skip unavailable clusters** box. Choosing this option ensures that your cross-cluster queries return partial results regardless of failures on one or more remote clusters.

1. For **Destination cluster**, choose between **Connect to a cluster in this AWS account** and **Connect to a cluster in another AWS account**. 

1. For **Remote domain ARN**, enter the Amazon Resource Name (ARN) for the cluster. The domain ARN can be located in the **General information** area of the domain's detail page.

   The domain must meet the following requirements:
   + The ARN must be in the format `arn:partition:es:regionaccount-id:type/domain-id`. For example:

     `arn:aws:es:us-east-2:111222333444:domain/my-domain`
   + The domain must be configured to use OpenSearch version 1.0 (or later) or Elasticsearch version 6.7 (or later). 
   + Fine-grained access control must be enabled on the domain.
   + The domain must be running OpenSearch.

1. Choose **Request**.

Cross-cluster search first validates the connection request to make sure the prerequisites are met. If the domains are incompatible, the connection request enters the `Validation failed` state. 

If the connection request is validated successfully, it is sent to the destination domain, where it must be approved. Until this approval is given, the connection remains in a `Pending acceptance` state. When the connection request is accepted at the destination domain, the state changes to `Active` and the destination domain becomes available for queries. 

The domain page shows you the overall domain health and instance health details of your destination domain. Only domain owners have the flexibility to create, view, remove, and monitor connections to or from their domains.

After the connection is established, any traffic that flows between the nodes of the connected domains is encrypted. When you connect a VPC domain to a non-VPC domain and the non-VPC domain is a public endpoint that can receive traffic from the internet, the cross-cluster traffic between the domains is still encrypted and secure.

## Testing your security setup for cross-Region and cross-account data access with cross-cluster search
<a name="cross-cluster-search-security-testing"></a>

After you've set up access permissions for cross-Region and cross-account data access with cross-cluster search, we recommend testing the setup using [https://www.postman.com/](https://www.postman.com/), a third-party platform for collaborative API development.

**To set your security setup using Postman**

1. On the destination domain, index a document. The following is a sample request:

   ```
   POST https://dst-domain.us-east-1.es.amazonaws.com/books/_doc/1
   {
   "Dracula": "Bram Stoker"
   }
   ```

1. To query this index from the source domain, include the connection alias of the destination domain within the query. You can find the connection alias on the Connections tab on your domain dashboard. The following are a sample request and truncated response:

   ```
   GET https://src-domain.us-east-1.es.amazonaws.com/connection_alias:books/_search
   {
   ...
     "hits": [
   {
   "_index": "source-destination:books",
     "_type": "_doc",
     "_id": "1",
     "_score": 1,
     "_source": {
   "Dracula": "Bram Stoker"
     }
   }
     ]
   }
   ```

1. (Optional) You can create a configuration that includes multiple domains in a single search. For example, say that you set up the following:

   A connection between `domain-a` to `domain-b`, with connection alias named `cluster_b`

   A connection between `domain-a` to `domain-c`, with a connection alias named `cluster_c`

   In this case, your searches include the content `domain-a`, `domain-b`, and `domain-c`. The following are a sample request and response:

   Request

   ```
   GET https://src-domain.us-east-1.es.amazonaws.com/local_index,cluster_b:b_index,cluster_c:c_index/_search
   {
     "query": {
   "match": {
     "user": "domino"
   }
     }
   }
   ```

   Response:

   ```
   {
   "took": 150,
     "timed_out": false,
     "_shards": {
   "total": 3,
   "successful": 3,
   "failed": 0,
   "skipped": 0
     },
     "_clusters": {
   "total": 3,
   "successful": 3,
   "skipped": 0
     },
     "hits": {
   "total": 3,
   "max_score": 1,
   "hits": [
     {
   "_index": "local_index",
       "_type": "_doc",
       "_id": "0",
       "_score": 1,
       "_source": {
   "user": "domino",
         "message": "This is message 1",
         "likes": 0
       }
     },
     {
   "_index": "cluster_b:b_index",
       "_type": "_doc",
       "_id": "0",
       "_score": 2,
       "_source": {
   "user": "domino",
         "message": "This is message 2",
         "likes": 0
       }
     },
     {
   "_index": "cluster_c:c_index",
       "_type": "_doc",
       "_id": "0",
       "_score": 3,
       "_source": {
   "user": "domino",
         "message": "This is message 3",
         "likes": 0
       }
     }
   ]
     }
   }
   ```

If you did not choose to skip unavailable clusters in your connection setup, all destination clusters that you search must be available for your search request to run successfully. Otherwise, the whole request fails—even if one of the domains is not available, no search results are returned.

## Deleting a connection
<a name="cross-cluster-search-deleting-connection"></a>

Deleting a connection stops any cross-cluster search operations on the destination domain.

You can perform the following procedure on either the source or destination domain to remove the connection. After you remove the connection, it remains visible with a status of `Deleted` for 15 days.

You can't delete a domain with active cross-cluster connections. To delete a domain, first remove all incoming and outgoing connections from that domain. This ensures you take into account the cross-cluster domain users before deleting the domain.

**To delete a connection**

1. Sign in to the Amazon OpenSearch Service console at [https://console.aws.amazon.com/aos/home](https://console.aws.amazon.com/aos/home).

1. In the left navigation, choose **Domains**.

1. Choose the name of a domain to delete, and then choose the **Connections** tab. 

1. Select the name of a connection to delete.

1. Choose **Delete**, and then confirm the deletion.