Skip to content

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"
}
}
}
]
}
  1. Version2012-10-17, the current policy language version.
  2. Principal — who may assume the role. Valid principal types are:
    • An AWS account, as arn:aws:iam::123456789012:root or 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)
  3. EffectAllow or Deny.
  4. Actionsts:AssumeRole for a standard assumption, sts:AssumeRoleWithSAML for SAML federation, sts:AssumeRoleWithWebIdentity for OIDC.
  5. Condition — optional constraints that must hold at the moment of assumption.
  • 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:SourceIp or 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.

Condition keyEffect
sts:ExternalIdRequires a shared secret value, which prevents the confused deputy problem when granting access to a third party
aws:MultiFactorAuthPresentRequires the caller to have authenticated with MFA
aws:PrincipalOrgIDRestricts assumption to principals inside a specific AWS organisation
aws:SourceIpRestricts assumption to a network range
aws:PrincipalTag/*Requires the calling principal to carry a particular tag
sts:RoleSessionNameConstrains the session name, which is what appears in CloudTrail
  • 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

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.