Cross-account data access to OpenSearch domains
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
- 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:DescribeDomainpermission. - IAM Identity Center application role
-
An IAM role in the source account that is used for IAM Identity Center user data plane access.
Prerequisites
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
Choose the scenario that matches your authentication method and domain configuration:
Scenario 1: IAM user accessing a public domain
Step 1: Create the cross-account IAM role (target account)
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
-
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" }] } -
Create the role:
aws iam create-role \ --role-nameOpenSearchUIAccessRole\ --assume-role-policy-document file://trust-policy.json -
Create a permissions policy with only the
es:DescribeDomainaction:{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "es:DescribeDomain", "Resource": "arn:aws:es:region:target-account-id:domain/*" }] } -
Attach the permissions policy to the role:
aws iam put-role-policy \ --role-nameOpenSearchUIAccessRole\ --policy-nameValidationOnly\ --policy-document file://permissions-policy.json
Step 2: Create the OpenSearch domain (target account)
Create an OpenSearch domain in the target account with fine-grained access control and encryption enabled:
aws opensearch create-domain \ --domain-namedomain-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/*"}]}' \ --regionregion
Wait for the domain status to become Active before
proceeding.
Step 3: Create the OpenSearch UI application (source account)
Create the application in the source account with the cross-account data source:
aws opensearch create-application \ --regionregion\ --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
Retrieve the application details to get the endpoint URL:
aws opensearch get-application \ --regionregion\ --idapplication-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
Step 1: Create the cross-account IAM role (target account)
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
-
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" }] } -
Create the role:
aws iam create-role \ --role-nameOpenSearchUIAccessRole\ --assume-role-policy-document file://trust-policy.json -
Create a permissions policy with only the
es:DescribeDomainaction:{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "es:DescribeDomain", "Resource": "arn:aws:es:region:target-account-id:domain/*" }] } -
Attach the permissions policy to the role:
aws iam put-role-policy \ --role-nameOpenSearchUIAccessRole\ --policy-nameValidationOnly\ --policy-document file://permissions-policy.json
Step 2: Create the OpenSearch domain (target account)
Create an OpenSearch domain in the target account. Use the same command as Step 2: Create the OpenSearch domain (target account), 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)
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
-
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" } } } ] } -
Create a permissions policy:
{ "Version": "2012-10-17", "Statement": [{ "Sid": "OpenSearchDomain", "Effect": "Allow", "Action": ["es:ESHttp*"], "Resource": "*" }] } -
Create the role and attach the policies:
aws iam create-role \ --role-nameNeoIdCAppRole\ --assume-role-policy-document file://neoidc-trust-policy.jsonaws iam put-role-policy \ --role-nameNeoIdCAppRole\ --policy-nameNeoIdCAppPermissions\ --policy-document file://neoidc-permissions-policy.json
Step 4: Create the OpenSearch UI application with IAM Identity Center (source account)
aws opensearch create-application \ --regionregion\ --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
Create an IAM Identity Center user
Run the following command. Replace the placeholder
values with your own information.
aws identitystore create-user \ --identity-store-idd-directory-id\ --user-nameuser-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-idd-directory-id\ --display-name "OpenSearchUsers" \ --description "Users with OpenSearch access" aws identitystore create-group-membership \ --identity-store-idd-directory-id\ --group-idgroup-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-iduser-id-or-group-id\ --principal-typeUSER
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" \ -uadmin:master-password\ -H 'Content-Type: application/json' \ -d '{ "backend_roles": ["group-id"], "hosts": [], "users": [] }'
Step 6: Verify and access
aws opensearch get-application \ --regionregion\ --idapplication-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
Step 1: Create the cross-account IAM role (target account)
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
-
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" }] } -
Create the role:
aws iam create-role \ --role-nameOpenSearchUIAccessRole\ --assume-role-policy-document file://trust-policy.json -
Create a permissions policy with only the
es:DescribeDomainaction:{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "es:DescribeDomain", "Resource": "arn:aws:es:region:target-account-id:domain/*" }] } -
Attach the permissions policy to the role:
aws iam put-role-policy \ --role-nameOpenSearchUIAccessRole\ --policy-nameValidationOnly\ --policy-document file://permissions-policy.json
Step 2: Set up the VPC (target account)
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 \ --regionregion# Create subnet aws ec2 create-subnet \ --vpc-idvpc-id\ --cidr-block 10.0.1.0/24 \ --availability-zoneregiona \ --regionregion# Create security group aws ec2 create-security-group \ --group-nameopensearch-vpc-sg\ --description "Security group for OpenSearch VPC domain" \ --vpc-idvpc-id\ --regionregion# Allow inbound HTTPS aws ec2 authorize-security-group-ingress \ --group-idsecurity-group-id\ --protocol tcp \ --port 443 \ --cidr 10.0.0.0/16 \ --regionregion
Learn more about VPC domain creation.
Step 3: Create the VPC domain (target account)
aws opensearch create-domain \ --domain-namevpc-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/*"}]}' \ --regionregion
Wait for the domain status to become Active before
proceeding.
Step 4: Authorize the VPC endpoint for the OpenSearch UI service principal (target account)
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-namevpc-domain-name\ --service "application.opensearchservice.amazonaws.com" \ --regionregion# Verify authorization aws opensearch list-vpc-endpoint-access \ --domain-namevpc-domain-name\ --regionregion
Expected response:
{ "AuthorizedPrincipalList": [ { "PrincipalType": "AWS_SERVICE", "Principal": "application.opensearchservice.amazonaws.com" } ] }
Step 5: Create the OpenSearch UI application (source account)
aws opensearch create-application \ --regionregion\ --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
Retrieve the application details to get the endpoint URL:
aws opensearch get-application \ --regionregion\ --idapplication-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
Step 1: Create the cross-account IAM role (target account)
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
-
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" }] } -
Create the role:
aws iam create-role \ --role-nameOpenSearchUIAccessRole\ --assume-role-policy-document file://trust-policy.json -
Create a permissions policy with only the
es:DescribeDomainaction:{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "es:DescribeDomain", "Resource": "arn:aws:es:region:target-account-id:domain/*" }] } -
Attach the permissions policy to the role:
aws iam put-role-policy \ --role-nameOpenSearchUIAccessRole\ --policy-nameValidationOnly\ --policy-document file://permissions-policy.json
Step 2: Set up the VPC (target account)
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 \ --regionregion# Create subnet aws ec2 create-subnet \ --vpc-idvpc-id\ --cidr-block 10.0.1.0/24 \ --availability-zoneregiona \ --regionregion# Create security group aws ec2 create-security-group \ --group-nameopensearch-vpc-sg\ --description "Security group for OpenSearch VPC domain" \ --vpc-idvpc-id\ --regionregion# Allow inbound HTTPS aws ec2 authorize-security-group-ingress \ --group-idsecurity-group-id\ --protocol tcp \ --port 443 \ --cidr 10.0.0.0/16 \ --regionregion
Learn more about VPC domain creation.
Step 3: Create the VPC domain (target account)
Use the same command as Step 3: Create the VPC domain (target account), 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)
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-namevpc-domain-name\ --service "application.opensearchservice.amazonaws.com" \ --regionregion# Verify authorization aws opensearch list-vpc-endpoint-access \ --domain-namevpc-domain-name\ --regionregion
Expected response:
{ "AuthorizedPrincipalList": [ { "PrincipalType": "AWS_SERVICE", "Principal": "application.opensearchservice.amazonaws.com" } ] }
Step 5: Create the IAM role for IAM Identity Center application (source account)
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
-
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" } } } ] } -
Create a permissions policy:
{ "Version": "2012-10-17", "Statement": [{ "Sid": "OpenSearchDomain", "Effect": "Allow", "Action": ["es:ESHttp*"], "Resource": "*" }] } -
Create the role and attach the policies:
aws iam create-role \ --role-nameNeoIdCAppRole\ --assume-role-policy-document file://neoidc-trust-policy.jsonaws iam put-role-policy \ --role-nameNeoIdCAppRole\ --policy-nameNeoIdCAppPermissions\ --policy-document file://neoidc-permissions-policy.json
Step 6: Create the OpenSearch UI application with IAM Identity Center (source account)
aws opensearch create-application \ --regionregion\ --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
Create an IAM Identity Center user
Run the following command. Replace the placeholder
values with your own information.
aws identitystore create-user \ --identity-store-idd-directory-id\ --user-nameuser-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-idd-directory-id\ --display-name "OpenSearchUsers" \ --description "Users with OpenSearch access" aws identitystore create-group-membership \ --identity-store-idd-directory-id\ --group-idgroup-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-iduser-id-or-group-id\ --principal-typeUSER
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" \ -uadmin:master-password\ -H 'Content-Type: application/json' \ -d '{ "backend_roles": ["group-id"], "hosts": [], "users": [] }'
Step 8: Verify and access
aws opensearch get-application \ --regionregion\ --idapplication-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
Update an application with cross-account data sources
Run the following command. Replace the placeholder
values with your own information.
aws opensearch update-application \ --regionregion\ --idapplication-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 \ --regionregion
Delete an application
Run the following command:
aws opensearch delete-application \ --regionregion\ --idapplication-id
Revoke VPC endpoint access
Run the following command:
aws opensearch revoke-vpc-endpoint-access \ --domain-namevpc-domain-name\ --service "application.opensearchservice.amazonaws.com" \ --regionregion
Quick reference
The following tables summarize the key differences between domain types and authentication methods.
| 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 |
| 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
-
The
iamRoleForDataSourceArnmust be in the same account as thedataSourceArn. -
The
iamRoleForDataSourceArnis only required for cross-account data sources. Omit it for same-account data sources. -
The cross-account role only needs the
es:DescribeDomainpermission. 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
| 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. |