Tools · Cloud security · 06 / 24
AWS IAM roles and AssumeRole explained: trust policies and temporary credentials
Understand the two policies every role has, assume a role from the CLI, add an external ID and MFA condition, and read AssumeRole events in CloudTrail.
Two policies per role
A role has a trust policy that says who may assume it, and permission policies that say what it can do once assumed. Assuming a role through AWS STS returns temporary credentials: an access key, a secret key, and a session token that expire after a set duration, by default one hour.
The trust policy is the part people forget to review. A trust policy that allows "AWS": "*" or an entire foreign account without conditions lets far more principals in than intended.
A careful trust policy
Name exact principals, such as a specific role ARN in another account. For third-party vendors, require sts:ExternalId to prevent the confused-deputy problem, where a vendor is tricked into using your role on behalf of another customer. For humans, require aws:MultiFactorAuthPresent.
Keep maximum session duration short for privileged roles.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::444455556666:role/vendor-scanner" },
"Action": "sts:AssumeRole",
"Condition": { "StringEquals": { "sts:ExternalId": "hb-7f3c2e" } }
}]
}Lab: assume and trace
In a sandbox, create a role that your IAM user may assume only with MFA, with a read-only permission policy. Configure a CLI profile with role_arn, source_profile, and mfa_serial, then run aws sts get-caller-identity with that profile. The ARN shows assumed-role and the session name.
Find the AssumeRole event in CloudTrail. It records the source identity and the role. Later API calls with the temporary credentials show userIdentity.type AssumedRole with sessionContext linking back to it.
# ~/.aws/config
[profile audit]
role_arn = arn:aws:iam::111122223333:role/audit-readonly
source_profile = default
mfa_serial = arn:aws:iam::111122223333:mfa/alice
aws sts get-caller-identity --profile audit
aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole --max-results 5 --query 'Events[].CloudTrailEvent' --output text | jq '{who:.userIdentity.arn, role:.requestParameters.roleArn, time:.eventTime}'Review trust policies
List every role and print its trust policy. Flag Principal "*", entire external accounts without ExternalId, and federated principals without audience conditions. Access Analyzer’s external access findings cover many of these automatically.
Role chaining, where a role assumes another role, is limited to one-hour sessions and is easy to lose track of. Keep chains short.
Diagram
A risky and a careful trust policy
Who can become this role.
Principal. An entire external account, or "*".
Conditions. None.
Effect. Any principal there can assume it.
Principal. One specific role ARN.
Conditions. ExternalId for vendors, MFA for humans.
Effect. Only the intended caller.
Check yourself
1. Which part of a role controls who can assume it?
2. What does requiring sts:ExternalId for a vendor prevent?
3. What userIdentity.type appears for calls made with role credentials?