Trust Policy
A trust policy is the JSON document attached to an IAM role that defines which principals may assume it. It is a resource-based policy where the resource is the role itself, and every role has exactly one.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com", "AWS": "arn:aws:iam::123456789012:user/DevUser" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "aws:RequestedRegion": "eu-west-2" } } } ]}Components
Section titled “Components”- Version —
2012-10-17, the current policy language version. - Principal — who may assume the role. Valid principal types are:
- An AWS account, as
arn:aws:iam::123456789012:rootor the bare account ID - An IAM role:
arn:aws:iam::123456789012:role/RoleName - An IAM user:
arn:aws:iam::123456789012:user/UserName - A role session or an AWS STS federated user session
- An AWS service:
"Service": "lambda.amazonaws.com" - A federated principal: a SAML provider ARN, an OIDC provider ARN, or one of the built-in
web identity providers (
accounts.google.com,graph.facebook.com,www.amazon.com,cognito-identity.amazonaws.com)
- An AWS account, as
- Effect —
AlloworDeny. - Action —
sts:AssumeRolefor a standard assumption,sts:AssumeRoleWithSAMLfor SAML federation,sts:AssumeRoleWithWebIdentityfor OIDC. - Condition — optional constraints that must hold at the moment of assumption.
What cannot be a principal
Section titled “What cannot be a principal”- An IAM group. Groups are containers for users, not authenticated entities. See IAM roles cannot be attached to IAM groups.
- An EC2 instance ARN. An instance receives credentials through an instance profile, not
by being named in a trust policy. To scope a role to a particular instance, use a condition
on
aws:SourceVpc,aws:SourceIpor a tag, or give the instance its own role. "Service": "*". A service principal must be named.
A wildcard in the Principal element of a role trust policy allows anyone in any AWS account
to assume the role. It is almost never what is intended, and where it appears at all it needs
a Condition that constrains it tightly.
Useful conditions
Section titled “Useful conditions”| Condition key | Effect |
|---|---|
sts:ExternalId | Requires a shared secret value, which prevents the confused deputy problem when granting access to a third party |
aws:MultiFactorAuthPresent | Requires the caller to have authenticated with MFA |
aws:PrincipalOrgID | Restricts assumption to principals inside a specific AWS organisation |
aws:SourceIp | Restricts assumption to a network range |
aws:PrincipalTag/* | Requires the calling principal to carry a particular tag |
sts:RoleSessionName | Constrains the session name, which is what appears in CloudTrail |
Common uses
Section titled “Common uses”- Allowing an EC2 instance to reach other AWS services, through the role in its instance profile
- Allowing AWS Lambda, ECS tasks, CodeBuild and other services to act with a role
- Cross-account access, where a role in one account trusts a principal in another
- Federating an external identity provider — SAML for a corporate directory, OIDC for a CI system such as GitHub Actions
- Letting a service such as CloudFormation or AWS Config operate on your behalf
Pitfalls
Section titled “Pitfalls”A deleted and recreated principal breaks the policy. When a trust policy names a specific role or user ARN, IAM stores the principal’s unique ID rather than the ARN. Deleting and recreating that role or user produces a new ID, the stored one no longer matches, and the policy silently stops applying. The console then shows the raw principal ID instead of an ARN. The fix is to re-save the trust policy with the current ARN.
Account root is broader than it looks. arn:aws:iam::123456789012:root delegates the
decision to that account, whose administrators can then grant the ability to assume the role
to anyone in it. Name the specific role or user where the intent is narrower.