A role is assumed, not used as a permanent login
An IAM role has a permissions policy and a trust policy. The trust policy determines which principal may call sts:AssumeRole; the permissions policy determines what the session's temporary credentials can do.
flowchart LR E["EC2 instance<br/>app code"] --> IP["Instance profile<br/>wraps the role"] IP --> STS["AWS STS<br/>AssumeRole"] STS --> TC["Temporary credentials<br/>expire, auto-rotate"] TC --> S3["Amazon S3<br/>GetObject"] TR["Trust policy<br/>ec2.amazonaws.com"] -.-> STS %% step E: Code on the instance needs to read from S3 without stored keys. %% step IP: An instance profile attaches the role to the instance. %% step STS: STS checks the trust policy: is this principal allowed to assume the role? %% step TC: It returns short-lived credentials, which the SDK picks up from instance metadata and refreshes automatically. %% step S3: Requests are allowed only as far as the role's permissions policy says. %% step TR: The trust policy names who may assume the role, here the EC2 service.
Trust policy
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "ec2.amazonaws.com"},
"Action": "sts:AssumeRole"
}]
}
The Principal can be a service (lambda.amazonaws.com), another account (arn:aws:iam::111122223333:root), a specific role, or a federated identity provider (SAML, OIDC such as GitHub Actions).
Where roles are used
- EC2 uses a role through an instance profile; the SDK reads credentials from the instance metadata service (use IMDSv2).
- Lambda has an execution role; ECS tasks have task roles; CloudFormation can use a service role.
- Cross-account access — account B creates a role trusting account A; users in A call
sts:AssumeRole(or--profilewithrole_arn) to work in B. Add anExternalIdcondition when a third party assumes your role. - Federation — GitHub Actions or Identity Center users assume roles with web identity instead of storing keys.
Temporary credentials rotate automatically, so do not run aws configure to store access keys on an instance. A role session lasts from 15 minutes up to the role's maximum session duration (1 hour by default, up to 12 hours).
Roles versus users and groups
A role is not “added to a user” like a group. A user or service assumes the role to receive a time-limited session, and the session has only the role's permissions, not the caller's. An explicit Deny still overrides the role's Allows, and permissions boundaries or SCPs still apply.
A service-linked role is created and managed by an AWS service for its own needs (for example Auto Scaling); you can view it but its trust is fixed.
| Command | Purpose |
|---|---|
aws iam create-role --role-name ec2-s3-read --assume-role-policy-document file://trust.json |
Create a role with a trust policy |
aws iam attach-role-policy --role-name ec2-s3-read --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess |
Attach a permissions policy |
aws ec2 associate-iam-instance-profile ... |
Attach a role to a running instance |
aws sts assume-role --role-arn ... --role-session-name test |
Assume a role manually |
Traps: storing access keys on EC2 instead of using a role; editing the permissions policy when the error is in the trust policy; expecting the session to keep the caller's own permissions.