How to Fix a Wildcard AWS IAM Trust Policy
An IAM role's trust policy says who is allowed to assume it. If it uses "Principal": "*", any AWS account on earth can assume the role - a serious backdoor. Here's how to scope it correctly.
Trust policy vs permissions policy
An IAM role has two policies, and people confuse them:
- Permissions policy - what the role can do (S3 read, etc.).
- Trust policy (assume-role policy) - who is allowed to become the role.
A wildcard in the trust policy is the dangerous one: it controls access to the role itself.
The vulnerable policy
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": "*",
"Action": "sts:AssumeRole"
}]
}
"Principal": "*" means any AWS principal, in any account can call
sts:AssumeRole and take on this role's permissions - no credentials in your account
needed. That's a backdoor, and an audit/Access Analyzer will flag it immediately.
The fix: scope the principal to a specific account
Replace the wildcard with the exact account (or role) allowed to assume it:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::123456789012:root"},
"Action": "sts:AssumeRole"
}]
}
:root here means "any principal in that one account" - not the root user. Apply it:
aws iam update-assume-role-policy \
--role-name cross-account-reporter \
--policy-document file://trust.json
Hardening cross-account access further
- ExternalId - for third-party/cross-account roles, require a shared secret to defeat the "confused deputy" problem:
json
"Condition": {"StringEquals": {"sts:ExternalId": "a-shared-secret"}}
- Scope to a specific role, not the whole account, when you can:
"AWS": "arn:aws:iam::123456789012:role/reporter". - Least privilege on the permissions policy too - assuming the role should grant only what's needed.
- Run IAM Access Analyzer - it continuously flags any role with a non-account-scoped principal.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Telling a trust policy apart from a permissions policy
- Scoping a Principal from * to a specific account ARN
- Adding an ExternalId condition for cross-account roles
FAQ
What does "Principal": "*" mean in an IAM trust policy?
It allows any AWS principal in any account to assume the role - effectively a public backdoor into the role's permissions. Scope it to a specific account ARN instead.
What's the difference between an IAM trust policy and a permissions policy?
The permissions policy defines what the role can do; the trust (assume-role) policy defines who is allowed to become the role. A wildcard in the trust policy is the dangerous one.
What is the purpose of an IAM role's trust policy?
The trust policy defines who is allowed to assume the role - which accounts, services, or identities can call sts:AssumeRole to take it on. It controls access to the role itself, separate from what the role can then do.
What is the difference between an IAM role and an IAM policy?
A role is an identity that can be assumed and that carries permissions; a policy is the JSON document that grants those permissions. A role has two policies attached - a trust policy (who can assume it) and one or more permissions policies (what it can do).
How do I restrict who can assume an IAM role?
Set the trust policy's Principal to the specific account or role ARN, and for third-party access add a Condition requiring an sts:ExternalId.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →