aws-opensearch-cross-account-access-policy
Domain access policy grants es:ESHttp* to a principal in a foreign AWS account, enabling cross-account data access without a role assumption.
match (record)
{
"field": "AccessPolicies",
"resource_type": "AWS::OpenSearchService::Domain"
}
where
access policy Principal.AWS contains a principal in a different account than the domain
the named principal has an Allow for es:ESHttp* actions
emit
| source type | ResourcePolicy |
|---|---|
| target type | Account |
| source | <domain access policy (ResourcePolicy)> |
| target | <foreign account or ExternalIdentity> |
| permissions | es:ESHttpGet es:ESHttpPost es:ESHttpPut es:ESHttpDelete es:ESHttpHead |
| conditions | resource_policy condition_expression |
| state logic | ACTIVE when the domain access policy explicitly allows es:ESHttp* for a principal ARN or account in a different AWS account with no conditions (or conditions the foreign principal can satisfy, e.g. aws:PrincipalOrgID is the same org). CONDITIONAL(condition_expression) when an aws:PrincipalOrgID, aws:SourceIp, or aws:SourceVpc condition restricts the grant. BLOCKED if a corresponding Deny statement at the domain level overrides the Allow. |
Narrative
The domain access policy for {domain.name} grants es:ESHttp* to {foreign_principal.name} in account {foreign_account}, enabling direct data access from that account without a cross-account role assumption - the foreign principal can read/write search indices without entering this account via STS.
Raw rule rules/derived/aws/opensearch.yaml
id: aws-opensearch-cross-account-access-policy
emits: CrossAccountTrust
description: Domain access policy grants es:ESHttp* to a principal in a foreign AWS account, enabling
cross-account data access without a role assumption.
match_record:
resource_type: AWS::OpenSearchService::Domain
field: AccessPolicies
where:
- access policy Principal.AWS contains a principal in a different account than the domain
- the named principal has an Allow for es:ESHttp* actions
emit:
source_type: ResourcePolicy
target_type: Account
source: <domain access policy (ResourcePolicy)>
target: <foreign account or ExternalIdentity>
permissions:
- es:ESHttpGet
- es:ESHttpPost
- es:ESHttpPut
- es:ESHttpDelete
- es:ESHttpHead
conditions:
- resource_policy
- condition_expression
state_logic: ACTIVE when the domain access policy explicitly allows es:ESHttp* for a principal ARN or
account in a different AWS account with no conditions (or conditions the foreign principal can satisfy,
e.g. aws:PrincipalOrgID is the same org). CONDITIONAL(condition_expression) when an aws:PrincipalOrgID,
aws:SourceIp, or aws:SourceVpc condition restricts the grant. BLOCKED if a corresponding Deny statement
at the domain level overrides the Allow.
false_positive_note: "Distinguish account IDs carefully: a principal ARN in the SAME account as the\
\ domain is not cross-account (it is intra-account IAM access). Only emit CrossAccountTrust when the\
\ principal account ID differs from the domain account ID. Honor aws:PrincipalOrgID conditions \u2014\
\ if the condition requires the caller to be in the same AWS Organization, the trust is scoped to\
\ org members (emit CONDITIONAL, not ACTIVE for arbitrary foreign accounts). aws:ResourceAccount is\
\ a receiver-side condition, not a cross-account gate."
narrative: "The domain access policy for {domain.name} grants es:ESHttp* to {foreign_principal.name}\
\ in account {foreign_account}, enabling direct data access from that account without a cross-account\
\ role assumption \u2014 the foreign principal can read/write search indices without entering this\
\ account via STS."