table of contents
An AWS IAM trust policy decides who can assume a role. When that trust reaches another account, the blast radius can grow fast, especially if the policy is broad or missing conditions.
Cross-account trust is useful for vendors, shared services, and centralized security teams. It also creates a path for a less-trusted account to step into a more-sensitive one, which is why audits need to focus on the trust policy, not only the permission policy.
Start with the role’s trust document, then compare it with the real access pattern. The gaps usually show up quickly.
Contents
- What AWS IAM trust policies control in cross-account access
- How to read AWS IAM trust policies before you audit them
- Practical steps for auditing trust policies in AWS
- Red flags in AWS IAM trust policies
- Remediating AWS IAM trust policies that are too broad
- Concise audit checklist
- Conclusion
- FAQ
What AWS IAM trust policies control in cross-account access
A trust policy lives on an IAM role. It tells AWS which principals can call sts:AssumeRole and obtain temporary credentials. The permission policy on that role then decides what those temporary credentials can do.
That split matters. A role can have a very tight permission policy and still be risky if the trust policy accepts the wrong principal. A broad trust policy is like handing out a key before checking the lock.
AWS recommends using conditions to narrow access and using IAM Access Analyzer to verify public and cross-account exposure in its IAM best practices guide. That guidance lines up with what auditors see in real environments. The biggest mistakes usually come from vague principals, missing conditions, and roles that survive long after their original purpose.
Cross-account access appears in a few common forms. Sometimes a vendor assumes a role in your account. Sometimes one AWS account in your organization reaches into another. Sometimes a service, such as EventBridge or Lambda, needs to assume a role on your behalf. Each case needs a different trust pattern.
A trust policy that accepts a whole account gives every principal in that account a path to your role.

How to read AWS IAM trust policies before you audit them
A trust policy review starts with three questions. Who is trusted? What action is allowed? Which conditions limit that trust?
A broad trust policy often looks like this:
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::111122223333:root"},"Action":"sts:AssumeRole"}]}
That policy trusts every identity in the external account. It may be acceptable in rare cases, but it should always trigger a deeper review.
A tighter version names one role and adds conditions:
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::111122223333:role/vendor-ci"},"Action":"sts:AssumeRole","Condition":{"StringEquals":{"sts:ExternalId":"ops-72f4","aws:PrincipalOrgID":"o-a1b2c3d4"}}}]}
This is easier to reason about. It ties trust to one role, one external relationship, and one organization boundary.
The details matter. Principal tells you who can try. Action should usually be sts:AssumeRole for role assumption. Condition is where the real limits live. For service-linked access, aws:SourceArn and aws:SourceAccount often matter more than a raw account ID. For federated or vendor access, sts:ExternalId, aws:PrincipalArn, aws:PrincipalOrgID, and aws:PrincipalTag are common control points.
The AWS Security Blog has a useful overview of four ways to grant cross-account access in AWS. That context helps when the same use case could be solved with a role, a resource policy, or a different trust pattern.
| Trust policy element | What to inspect | Red flag |
|---|---|---|
| Principal | One specific role, service, or account? | *, account root, or many unrelated principals |
| Action | Is the role assumed through the expected STS action? | Extra actions or mixed access paths |
| Condition | Are ExternalId, SourceArn, SourceAccount, or PrincipalOrgID present where needed? | Missing or weak condition keys |
| Scope | Does the role serve one job? | Shared use across teams, apps, or vendors |
That table gives you a fast triage path. If the trust names a wide audience and adds few conditions, treat it as high risk.
Practical steps for auditing trust policies in AWS
Start with inventory. Export every IAM role trust policy across all accounts, including roles managed through IaC. If the role only exists in a template, it still matters. Drift and copy-paste often create the worst surprises.
Next, sort roles by who they trust. Put whole-account trusts, third-party trusts, and any Principal: "*", first. Then separate internal cross-account roles from service roles. That simple grouping makes patterns easier to see. If one vendor account appears in 20 roles, you may be looking at role sprawl rather than a true need.
The next pass is about conditions. Check whether each external trust has a reason to exist and a control to match that reason. For vendors, that usually means a unique ExternalId. For service principals, it often means SourceArn and SourceAccount. For trust inside your AWS Organization, aws:PrincipalOrgID can help, but it should not become a substitute for proper role scoping.
Then compare the policy to actual use. CloudTrail AssumeRole events show which accounts and roles are using the trust path. If a role has no activity for 90 days, ask why it still exists. Stale trust is still trust. Unused roles are easy to forget and easy to abuse later.
IAM Access Analyzer is also worth a pass because it finds external access paths you may have missed. AWS calls out analyzer-based review in its IAM best practices documentation, and that fits well with a recurring audit cycle. Use analyzer findings as a starting point, then confirm each one against the business owner and the actual runtime behavior.

A final check belongs on the caller side. Cross-account access needs two halves. The trust policy on the target role must allow assumption, and the caller must have permission to call sts:AssumeRole. Auditing only one side gives you a false sense of safety.
Red flags in AWS IAM trust policies
Some trust policies need immediate attention. These are the ones that show up again and again in incident reviews and internal audits.
- Wildcard principals:
Principal: "*"is almost always too broad. It opens the door wider than most teams expect. - Account root trust: Trusting
arn:aws:iam::123456789012:rootgives every identity in that account a path to your role. - Missing condition keys: If the role is for a vendor, a service, or a specific org boundary, the policy should usually include a narrowing condition.
- Overly broad ExternalId values: A shared, guessable, or reused
ExternalIdweakens the protection it is supposed to provide. - Confused deputy risk: Third-party access without a unique
ExternalIdlets the vendor’s own credentials get mixed up across customers. - Unused roles: A role that nobody assumes anymore can still be assumed tomorrow if the trust policy stays open.
- Third-party access with no owner: If nobody knows who approved the vendor, the trust path is already out of control.
- Organization boundary issues: Trust that relies on
aws:PrincipalOrgIDwithout checking the role scope can still be wider than it should be.
A helpful way to think about it is simple. If the policy trusts an account, a vendor, or an org without saying why and how, the risk is probably too high.
Broad trust is often invisible until someone maps every principal that can use it.
For a good overview of the ways teams misread cross-account access, see common cross-account trust mistakes. The core lesson is consistent. The trust policy is the control surface, and broad language there deserves scrutiny.
Remediating AWS IAM trust policies that are too broad
Fixing a weak trust policy usually means narrowing the principal, adding conditions, or splitting the role into smaller pieces. The right fix depends on the reason the trust exists in the first place.
| Risk found | Better pattern | What it changes |
|---|---|---|
| Whole-account trust | Trust a specific role ARN | Limits assumption to one known workload |
Vendor access without ExternalId | Require a unique ExternalId per tenant or customer | Reduces confused deputy risk |
| Service principal without source controls | Add aws:SourceArn and aws:SourceAccount | Ties trust to one service resource |
| Org-wide trust with no review | Add aws:PrincipalOrgID and confirm the business need | Keeps trust inside the org boundary |
| Shared role for many uses | Split roles by application, team, or pipeline | Shrinks the blast radius |
| Stale role with no usage | Remove the role or disable the trust path | Cuts dead access paths |
When possible, trust one role instead of one whole account. Use the narrowest condition keys that fit the use case. Keep the role names clear, so future reviewers can see why the trust exists.
AWS Organizations can help here, but it should not hide the risk. An account inside your org is still a separate security boundary. Pair role review with SCP review so a broad trust in one account does not become the easiest path around your controls.
If your estate has inherited vendor access, shared pipelines, and old cross-account roles, a focused review can save a lot of time. Book a Discovery Call with Bud Consulting if you want a second set of eyes on the highest-risk trust paths.
Concise audit checklist
Use this checklist during a review or as part of a recurring control.
- Export every role trust policy from every account.
- Flag any role that trusts another account, a vendor, or a wildcard principal.
- Check whether the
Principalis one role, one account, or many. - Verify the right condition keys are present, such as
ExternalId,PrincipalOrgID,SourceArn, orSourceAccount. - Review CloudTrail
AssumeRoleactivity for the last 30, 60, or 90 days. - Confirm the role is still needed and has a named owner.
- Compare the trust policy with Access Analyzer findings.
- Remove or narrow anything undocumented, unused, or broader than the use case.
If a role fails two or more of those checks, it belongs on the remediation list.
Conclusion
Cross-account trust gets risky when the policy says more than the business need. The most dangerous roles are often the ones that look ordinary, especially when they trust a whole account or skip a key condition.
A good audit checks the trust policy, the caller side, CloudTrail activity, and analyzer findings together. That gives you a clear view of who can assume the role and why.
If you tighten the principal, add the right conditions, and retire stale roles, you cut the risk without slowing down legitimate work. That is the real goal of reviewing AWS IAM trust policies.
FAQ
What is the difference between a trust policy and a permission policy?
A trust policy decides who can assume a role. A permission policy decides what the role can do after assumption. Both matter, because a tight permission policy does not fix a broad trust policy. For cross-account access, the trust side is often where the larger risk lives.
When should sts:ExternalId be required?
Use sts:ExternalId when a third party assumes a role in your account. It helps reduce confused deputy risk by tying the request to a value that the vendor should know, and outsiders should not guess. Each customer or tenant should usually have a unique value.
Is aws:PrincipalOrgID enough for cross-account trust?
No. It helps define an organization boundary, but it can still be too broad if many accounts in the org can assume the role. Combine it with a specific role ARN, a clear business owner, and the smallest permission set you can manage.
How often should trust policies be audited?
Audit them when they are created, when they change, and on a regular schedule after that. Many teams use monthly or quarterly reviews for high-risk roles, plus event-driven reviews after vendor changes, account merges, or org restructures. CloudTrail and Access Analyzer can keep the review cycle honest.
Can IAM Access Analyzer replace manual review?
No. It is a strong first pass, but it won’t tell you whether the access is still business-approved or whether the role should exist at all. Manual review is still needed to confirm intent, document ownership, and retire old trust paths that analyzer can still see.


