Roles are how instances, functions, containers, CI and other accounts get credentials without any secret to leak.
A role has two policy sides:
- The trust policy (a resource-based policy on the role) says which principals may call
sts:AssumeRole: a service likelambda.amazonaws.com, another account, a specific role, or a federated identity provider such as GitHub Actions OIDC. - Permission policies say what the role can do once assumed.
STS (Security Token Service) returns temporary credentials: an access key ID, secret key and session token, valid by default for one hour (up to the role's maximum session duration, at most 12 hours; role chaining is capped at one hour). Nothing long-lived exists to steal.
How services use roles:
- EC2: an instance profile wraps the role; the SDK fetches rotating credentials from the instance metadata service. Require IMDSv2, which uses session tokens and blocks common SSRF tricks.
- Lambda: the execution role.
- ECS: the task role is what your code uses; the task execution role is what ECS itself uses to pull images and write logs. Mixing them up is a common bug.
Cross-account access: account B creates a role trusting account A; principals in A need permission to call sts:AssumeRole on it. For third-party SaaS that assumes into your account, require an sts:ExternalId condition to prevent the confused-deputy problem.
The CLI and SDKs assume roles automatically when a profile has role_arn and source_profile, refreshing credentials as they expire. CI systems should use OIDC federation (AssumeRoleWithWebIdentity) instead of stored keys.
Example
cat > trust.json <<'EOF'
{"Version": "2012-10-17",
"Statement": [{"Effect": "Allow",
"Principal": {"Service": "lambda.amazonaws.com"},
"Action": "sts:AssumeRole"}]}
EOF
aws iam create-role --role-name orders-fn \
--assume-role-policy-document file://trust.json
aws iam attach-role-policy --role-name orders-fn \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Assume a role in another account by hand
aws sts assume-role --role-arn arn:aws:iam::444455556666:role/Deployer \
--role-session-name alice --query Credentials.Expiration --output text
# 2026-10-17T13:04:11+00:00
# ...or let a profile do it automatically
# [profile prod]
# role_arn = arn:aws:iam::444455556666:role/Deployer
# source_profile = devRemember
- Trust policy = who can assume; permission policy = what it can do
- STS credentials expire (default 1 hour) and carry a session token
- ECS task role is for your code; task execution role is for ECS itself
- Use ExternalId for third parties and OIDC federation for CI
Watch out for
- Putting the permissions a container needs on the ECS task execution role instead of the task role.