AWS STS AssumeRole and Temporary Credentials
AWS STS AssumeRole lets an authenticated AWS caller obtain short-lived credentials that act as a particular IAM role. The caller proves who it is, AWS checks whether that caller is trusted by the role, and STS returns a temporary access key, secret key, session token, and expiration time.
The problem AssumeRole solves
Without role assumption, software would need its own long-lived AWS access keys. Those keys are difficult to distribute safely, are easy to copy into source code or deployment settings, and remain useful until someone rotates or revokes them.
AssumeRole replaces that arrangement with a handoff:
- A caller authenticates to AWS using existing credentials.
- The caller asks STS to assume a named role.
- STS checks whether the caller is allowed to assume it.
- STS issues credentials that expire, commonly after one hour.
- The application uses those credentials for AWS API requests.
The caller might be a human using an IAM user, an EC2 instance using its instance role, a GitHub Actions deployment identity, or a role in another AWS account.
The resulting credentials are not the caller's original credentials with extra permissions. They identify a temporary role session.
A role has two separate security questions
An IAM role has a trust policy, which is a resource-based policy stating who or what may assume the role. It commonly names another AWS account, an IAM role, an OIDC identity provider, or an AWS service. It can also require conditions such as a particular external ID or MFA.
The role also has permissions policies, which state what the role session may do after assumption. These might allow reading from an S3 bucket, publishing to an SNS topic, or describing EC2 instances.
These policies answer different questions:
| Policy | Question it answers |
|---|---|
| Trust policy | Who may obtain credentials for this role? |
| Permissions policy | What may those credentials do? |
A trust policy that allows a deployment account to assume a role does not give that account permission to read S3. It only makes the handoff possible. Conversely, a role with permission to delete a database is not automatically assumable by everyone: its trust policy still has to trust the caller.
In a typical cross-account setup, the caller also needs an identity policy allowing sts:AssumeRole on the target role, while the target role's trust policy must trust the caller. AWS evaluates both sides before issuing credentials. Other controls, such as an organization policy or permissions boundary, can further restrict the result.
What happens during the call
The caller sends a signed HTTPS request to AWS Security Token Service (STS). The request identifies the role by ARN and supplies a session name. In code using the AWS SDK for Python (Boto3), the core call looks like this:
import boto3
sts = boto3.client("sts")
result = sts.assume_role(
RoleArn="arn:aws:iam::123456789012:role/DeployRole",
RoleSessionName="build-1842",
)
credentials = result["Credentials"]
The SDK signs this request with the caller's current credentials. STS authenticates that caller, then authorizes the request against the caller's ability to call sts:AssumeRole and the role's trust policy. Conditions in the trust policy may inspect details such as the caller's identity, an external ID, source account, or whether MFA was used.
If the request succeeds, the response contains:
AccessKeyId: the temporary access-key identifierSecretAccessKey: the matching secret used to sign requestsSessionToken: an additional token required for temporary credentialsExpiration: the time at which the credentials stop working
The application then configures its AWS SDK with all three credential values. Omitting the session token is a common source of confusing authentication failures: temporary credentials require it, unlike many long-lived access-key configurations.
Subsequent requests are evaluated as the role session. The effective permissions generally come from the role's permissions policies, reduced by any session policy supplied to AssumeRole, permissions boundary, organization service-control policy, or other applicable restriction. A session policy can narrow what the session may do; it cannot expand the role's permissions.
The session is also visible in logs. CloudTrail records the original caller and the assumed-role session, so the session name—such as build-1842—can help connect API activity to a job or operator.
Refreshing credentials
Temporary credentials do not renew themselves merely because an application keeps using them. Once Expiration passes, AWS rejects requests made with them. The application must obtain a new set by calling AssumeRole again with credentials that are still valid.
AWS SDKs usually hide this cycle. Their credential providers track expiration, refresh before it, and replace the in-memory credentials used by later requests. An application that manually copies the returned values into environment variables or a configuration file must implement the refresh itself—or restart the process with newly obtained credentials.
Refreshing requires a still-valid source identity. For example, an EC2 application can repeatedly assume a role using credentials supplied by the instance's own role. A deployment system can use its external identity to request a fresh session for each job. If the source credentials expire or lose permission, refresh fails even if the old role session has not yet expired.
There is an important limit when one role assumes another: role chaining, in which temporary role credentials are used to assume a second role, is limited to a maximum session duration of one hour. Repeatedly calling AssumeRole does not create an indefinitely renewable chain; each new call still depends on the current source credentials and the applicable session-duration rules.
When an error says that an access key is expired, it usually concerns the credentials used for the API request, not necessarily the role's policy. When AssumeRole itself is denied, inspect the caller's sts:AssumeRole permission, the target role's trust policy, and its conditions separately. That distinction is the central model: trust controls the handoff; permissions control the work performed after the handoff; expiration controls how long the resulting session remains usable.