IAM role trust policies decide who outside your account can become a principal inside it, and a missing external ID or source condition lets a trusted vendor or AWS service be tricked into acting for someone else. This guide is a role-by-role review method for AWS cross-account trust: export every trust policy, classify each trusted principal, check for the conditions AWS recommends against the confused deputy problem, use IAM Access Analyzer to confirm what is reachable from outside, and fix policies without cutting off legitimate integrations. It is for cloud security engineers, platform teams and anyone approving third-party access to AWS. Design patterns for cross-account and cross-tenant access are covered in the Cross-Account and Cross-Tenant Access Guide; this page is the audit.
Key takeaways
- Two different confused deputies: cross-account (a third party with a role in many customer accounts is tricked into using yours) is fixed with
sts:ExternalId; cross-service (an AWS service principal acting for another customer) is fixed withaws:SourceArn,aws:SourceAccount,aws:SourceOrgIDoraws:SourceOrgPaths. - The external ID belongs to the vendor: AWS states it must be generated by the third party, unique per customer, and is not a secret.
- Trusting an account root trusts its admins: AWS notes that using the account ARN does not limit access to the root user; the other account's administrators decide which of their identities can assume your role.
- Wildcard principals are the worst case: AWS strongly recommends against
"*"in role trust policies without restrictive conditions, because they let other principals become principals in your account. - Access Analyzer shows reachability, not intent: it flags roles accessible from outside your zone of trust whether or not they were used, so every finding still needs an owner decision.
When you need this
- Third-party onboarding or renewal: monitoring, cost, backup and security vendors almost always ask for a cross-account role. See the Third-Party Access Guide.
- Periodic access review: roles created for vendors persist long after contracts end, and IAM Access Analyzer external access findings stay Active until you remove the access or archive them.
- After a supplier incident: when a vendor holding roles in many customer accounts is compromised, you need to know exactly which of your roles it can assume and with what permissions.
- Organisation changes: mergers, account moves between organisations and new organisational units change what counts as inside your zone of trust.
- Before relying on service principal access: S3 bucket, SNS, SQS and KMS policies that grant AWS services access are where cross-service confused deputy conditions are most often missing.
Before you start
- Access: read-only IAM in each account (for example a security audit role), plus administrator access to IAM Access Analyzer in the delegated administrator account if you use AWS Organizations.
- Account map: a list of your own account IDs and organisation ID, so you can tell internal from external principals.
- Vendor register: the AWS account IDs your approved vendors publish, with contract owners.
- CloudTrail: organisation trail with management events, so you can see
AssumeRolecalls into each role. - Change process: trust policy edits take effect quickly and can cut off production integrations; agree a window and a vendor contact for each change.
Step-by-step
1. Export every trust policy
- In each account, export roles with their trust policies, for example with
aws iam get-account-authorization-details --filter Role, which returns each role'sAssumeRolePolicyDocument. Save the JSON per account. - Exclude service-linked roles from vendor review (they are managed by AWS) but keep them in the inventory.
- Extract every
Principalvalue and everyConditionblock into a table: account, role name, principal type (AWS,Service,Federated), principal value, conditions present, attached permission policies.
2. Classify each trusted principal
| Principal in trust policy | What it means | Required control |
|---|---|---|
| Your own account or a role in your organisation | Internal cross-account access | Specific role ARNs; consider aws:PrincipalOrgID or path conditions |
External account root (arn:aws:iam::<id>:root or bare account ID) | Any identity the other account's admins permit | sts:ExternalId for vendors; a specific role ARN where the vendor publishes one |
| Specific external role ARN | One role in the other account | sts:ExternalId if the vendor is multi-tenant |
"*" | Anyone in any account | Restrictive conditions at minimum; normally a critical finding |
Service principal (service-name.amazonaws.com) | An AWS service acting on behalf of some resource | aws:SourceArn or aws:SourceAccount where the service supports them |
| Federated (OIDC or SAML provider) | Tokens from an external identity provider | Audience and subject conditions; see How to set up workload identity federation for GitHub Actions to AWS |
Raw principal ID (for example starting AROA) instead of an ARN | The trusted role was deleted; AWS cannot map the ID back | Remove, or replace with the correct ARN if the access is still needed |
The last row matters: AWS converts a role ARN in a trust policy to the role's unique principal ID when you save it, so deleting and recreating the trusted role breaks the trust and leaves an orphaned ID in your policy.
3. Check cross-account trusts for the external ID
- For every external account principal that belongs to a vendor serving many customers, confirm the trust policy has
"StringEquals": {"sts:ExternalId": "..."}. - Confirm the value came from the vendor and is unique to you. AWS recommends one external ID per AWS account in multi-tenant setups, generated by the third party as a random string, and states it must be generated by the vendor and not by customers.
- Check format: AWS requires 2 to 1,224 characters, alphanumeric without white space, plus the symbols
+ = , . @ : / -. - Do not treat it as a secret or rotate it as one. AWS says it is not a secret and anyone who can view the role can see it.
- Ask the vendor whether they test your role both with and without the external ID. AWS advises vendors not to store a customer role ARN if it can be assumed without the correct external ID.
4. Check service principal grants for source conditions
- Search trust policies and resource policies (S3, SNS, SQS, KMS, Lambda) for
"Service":principals. - For each, confirm one of the AWS-recommended keys is present:
aws:SourceArnfor a specific resource (such as one CloudTrail trail),aws:SourceAccountfor a specific account, oraws:SourceOrgIDoraws:SourceOrgPathsfor your organisation. - Check the service's own documentation: AWS notes that support for these keys and any service-specific mechanisms vary by service.
- Where many resources need the same protection, consider resource control policies (RCPs), which AWS describes as a way to apply cross-service confused deputy controls centrally with
aws:SourceOrgIDandaws:SourceOrgPaths.
5. Confirm external reachability with IAM Access Analyzer
- Create an external access analyzer with your organisation (or account) as the zone of trust. For IAM roles, Access Analyzer analyses trust policies and generates a finding for roles that an entity outside the zone of trust can access. Because roles are global, a finding appears in each enabled Region.
- Reconcile findings with your table from step 2. Every external principal should appear in the vendor register.
- Note that findings report access the policy allows regardless of whether it was used; Access Analyzer does not examine access logs.
- Run an unused access analyzer too: it flags roles inactive for a number of days you choose, which identifies vendor roles nobody is using (service-linked roles are not analysed).
- Archive only with a recorded reason, and prefer archive rules scoped to specific vendor account IDs over broad rules.
6. Check actual use and permissions
- Who assumes it: search CloudTrail for
AssumeRoleevents against each role ARN and record the calling account and source IP ranges. - What it can do: read attached permission policies. A vendor read-only role with
iam:PassRole, write access to logging or broad*actions is a finding even if the trust policy is perfect. - Session duration: record the role's maximum session duration and reduce it where the vendor does not need long sessions.
Verify it worked
| Metric | Source | Target |
|---|---|---|
Vendor roles without sts:ExternalId | Trust policy table | Zero for multi-tenant vendors |
| Service principal grants without source conditions | Policy search | Zero where the service supports the keys |
Roles trusting "*" | Trust policy table and Access Analyzer | Zero |
| Active external access findings without an owner | Access Analyzer | Zero |
| Unused external roles | Unused access analyzer | Zero after each review |
| Orphaned principal IDs in trust policies | Trust policy table | Zero |
After each fix, Access Analyzer should move the finding to Resolved (AWS says findings may take up to 30 minutes to update after a policy change). Ask the vendor to run their connection test and check CloudTrail for successful AssumeRole calls from their account.
Rollback and common errors
- Adding an external ID the vendor does not send: their
AssumeRolecalls start failing. Agree the value and the vendor's change date first; rollback is restoring the previous trust policy, so save it before editing. - Using your own value as the external ID: it defeats the control, because uniqueness across the vendor's customers is what prevents the confused deputy. Use the vendor-issued value.
- Replacing account root with a specific role ARN that is later recreated: the trust breaks because the stored principal ID no longer matches. If the vendor recreates roles, AWS documents using
aws:PrincipalArnin a condition, which is not converted to an ID. - Treating service principals as safe: without
aws:SourceArnoraws:SourceAccount, a grant to a service principal can be used by another customer's resource of the same service. - Archiving findings in bulk: a broad archive rule hides new risky trusts to the same account. Scope rules narrowly and review them.
- Fixing trust but ignoring permissions: a correctly trusted role with administrator permissions is still the biggest blast radius in the account.
Hardening afterwards
- Codify trust policies: manage vendor roles in infrastructure as code with a review rule that rejects external principals without
sts:ExternalIdand service principals without source conditions. See the Terraform and IaC Pipeline Credential Security Guide. - Check policies in CI: use Access Analyzer policy validation and custom policy checks such as
CheckNoPublicAccessbefore deployment. - Apply organisation guardrails: resource control policies for service principal access, and service control policies that restrict who can edit role trust policies.
- Alert on trust changes: monitor
UpdateAssumeRolePolicyandCreateRoleevents and new Access Analyzer findings. See the AWS CloudTrail Guide. - Offboard vendors fully: delete the role, not just the contract. See the NHI Offboarding and Decommissioning Guide.
| Framework | Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.AA-05, GV.SC-07 | Least privilege and access review; supplier risk understood and monitored |
| NIST SP 800-53 Rev 5 | AC-2, AC-3, AC-6, SA-9 | Account review, access enforcement, least privilege, external system services |
| CIS Controls v8.1 | Controls 6 and 15 | Access control management and service provider management |
| ISO/IEC 27001:2022 Annex A | A.5.15, A.5.19, A.8.2 | Access control, supplier relationships, privileged access |
| MITRE ATT&CK | T1199, T1078.004, T1484.002 | Trusted relationship, cloud accounts, trust modification |
Practitioner checklist
- Export every role trust policy in every account and tabulate principals and conditions.
- Map each external account ID to an approved vendor and owner.
- Require vendor-issued, per-customer
sts:ExternalIdon every multi-tenant vendor role. - Add
aws:SourceArn,aws:SourceAccountor organisation source keys to service principal grants. - Remove
"*"principals and orphaned principal IDs. - Run external and unused access analyzers and resolve or justify every finding.
- Review the permissions and session duration of each externally trusted role.
- Alert on trust policy changes and new external access findings.
Standards and references
- AWS: The confused deputy problem
- AWS: Access to AWS accounts owned by third parties
- AWS: IAM JSON policy elements, Principal
- AWS: Resource types for IAM Access Analyzer external access
- AWS: How IAM Access Analyzer findings work
- AWS: IAM Access Analyzer custom policy checks
- NIST: SP 800-53 Rev 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Cross-Account and Cross-Tenant Access Guide · Confused Deputy in AI Agents Guide · Third-Party Access Guide · NHI Offboarding and Decommissioning Guide