Almost every Security Specialty scenario ends with someone holding temporary credentials. A developer switches into a production role, a pipeline assumes a deployment role in another account, a SAML user lands in a permission set, an attacker lifts keys from a compromised instance. The exam assumes you know that these are all AWS Security Token Service (AWS STS) sessions. What it actually tests is the layer underneath: how long each kind of session can live, what can be attached to it when it is created, what survives when one role assumes another, and how you kill a session that has already been issued.
The current exam guide is explicit about this. In the AWS Certified Security - Specialty (SCS-C03) guide, Domain 4 (Identity and Access Management) carries 20% of scored content, the largest share of any domain. Skill 4.1.2 reads, verbatim: “Configure mechanisms to issue temporary credentials (for example, AWS STS, Amazon S3 presigned URLs).” Skill 4.2.1 names “IAM role trust policies”, and Skill 4.2.3 names “permission boundaries, session policies”. Revoking a session is also an incident-response action, so the same material shows up in Domain 2.
This article is the mechanics layer that the broader guides skip. The IAM deep dive explains policy evaluation, trust policies and the external ID. The identity federation guide explains IAM Identity Center, SAML and OIDC at the architecture level. Neither is repeated here. Instead, this guide covers the session itself. Every limit and behaviour below was checked against the IAM User Guide and the STS API reference in November 2026.
What a session actually is
A call to an STS credential operation returns three values: an access key ID, a secret access key and a session token. All three must be presented together. Four properties of that bundle drive most exam answers.
- The access key prefix tells you what you are looking at. Long-term IAM user keys start with
AKIA. Temporary keys start withASIA. In an incident, anASIAkey in a log means a session, and the fix is a session-level control, not key rotation. - The principal is the session, not the role. After
AssumeRole, the caller’s ARN becomesarn:aws:sts::111122223333:assumed-role/RoleName/SessionName. The unique ID (theaws:useridvalue) is the role ID, a colon, and the session name, for exampleAROAEXAMPLEID:alice. - Permissions are not baked in. AWS evaluates the role’s policies on every request made with the session. Changing or removing a policy on the role affects sessions that were issued earlier. This is the property that makes revocation possible.
- A session cannot be extended or individually deleted. There is no API that invalidates one set of temporary credentials. You wait for expiry, or you attach a policy that denies them.
Keep the last two points together in your head. Temporary credentials are valid until they expire, and the only lever you have in the meantime is authorization.
The STS API family
The exam expects you to tell the credential-issuing operations apart by who can call them, how long the result lives, and what the result is not allowed to do.
| Operation | Who can call it | Lifetime (min / max / default) | MFA parameters | Session policies | Restrictions on the resulting credentials |
|---|---|---|---|---|---|
AssumeRole | IAM user, or a role session | 15 min / role’s maximum session duration / 1 hour | Yes | Yes | Cannot call GetFederationToken or GetSessionToken |
AssumeRoleWithSAML | Anyone holding a valid SAML response from a trusted IdP | 15 min / role’s maximum session duration / 1 hour | No | Yes | Cannot call GetFederationToken or GetSessionToken |
AssumeRoleWithWebIdentity | Anyone holding a valid OIDC token from a trusted IdP | 15 min / role’s maximum session duration / 1 hour | No | Yes | Cannot call GetFederationToken or GetSessionToken |
GetSessionToken | IAM user or root user | IAM user: 15 min / 36 hours / 12 hours. Root: 15 min / 1 hour / 1 hour | Yes | No | Cannot call IAM APIs unless MFA was included. Cannot call STS APIs except AssumeRole and GetCallerIdentity |
GetFederationToken | IAM user or root user | IAM user: 15 min / 36 hours / 12 hours. Root: 15 min / 1 hour / 1 hour | No | Yes | Cannot call IAM APIs from the CLI or API. Cannot call STS APIs except GetCallerIdentity |
AssumeRoot | IAM user or role in the Organizations management account or the IAM delegated administrator account | Up to 15 minutes | No | A task policy is mandatory | Scoped to one privileged task on a member account |
Several details in that table are worth isolating.
The two federation operations are unsigned. AssumeRoleWithSAML and AssumeRoleWithWebIdentity do not require AWS credentials. The SAML assertion or the JWT is the proof. That is why the role’s trust policy, with its Federated principal and its audience and subject conditions, is the entire security boundary for federated access.
GetSessionToken needs no permission. Its purpose is to authenticate an IAM user with MFA, and AWS states plainly that you cannot use policies to control it. You can write sts:GetSessionToken in a policy, but it has no effect. The credentials it returns carry exactly the permissions of the calling user.
GetFederationToken is the legacy custom-broker call. An application holding an IAM user’s long-term keys vends credentials for a named federated user. The session’s permissions are the intersection of the IAM user’s policies and the session policy you pass, so a federated user with no session policy can do nothing unless a resource-based policy names it. It is also the only operation with a 36-hour ceiling, which is why older “long-running job” answers mention it. On a modern exam, the preferred answer for workforce access is still IAM Identity Center or role federation.
Never call either token operation as root. Permissions on root-derived temporary credentials cannot be changed afterwards, so you cannot restrict them in an incident. AWS recommends not doing it at all.
Three helper operations round out the family:
GetCallerIdentityreturns the account, ARN and user ID of whoever signed the request. It requires no permission and still works when an explicit deny names it.DecodeAuthorizationMessageturns the encoded blob in an authorization failure into readable JSON. It does requirests:DecodeAuthorizationMessage.GetAccessKeyInforeturns the account that owns an access key ID, which is useful when a key turns up in a public repository.
Session duration: three numbers that get confused
Duration questions are among the easiest marks to lose, because three separate settings interact.
DurationSecondsis what the caller requests. The minimum is 900 seconds. If it is omitted on anAssumeRole*call, the session lasts one hour.- Maximum session duration (
MaxSessionDuration) is a property of the role. It can be set from 1 hour to 12 hours and defaults to 1 hour. A request for a longerDurationSecondsfails; it is not silently truncated. - The role-chaining cap is a hard one hour, and it overrides the role setting. More on that below.
Two caveats complete the picture. First, the maximum session duration does not limit sessions that AWS services assume on your behalf, and credentials delivered to an EC2 instance through its instance profile are not subject to it either. Second, console behaviour differs slightly: an IAM user’s console session lasts 12 hours by default, and a user who switches roles in the console gets the role’s maximum session duration or the remaining time in their own session, whichever is less.
# Raise the ceiling on the role (1 to 12 hours)
aws iam update-role --role-name DataExport --max-session-duration 14400
# Request a four-hour session against that ceiling
aws sts assume-role \
--role-arn arn:aws:iam::111122223333:role/DataExport \
--role-session-name nightly-export \
--duration-seconds 14400
A long session is a security trade-off. The longer the lifetime, the longer stolen credentials stay useful, which is exactly why the revocation procedure later in this article exists.
Trust policy mechanics that the exam layers on top
The two-sided authorization model (trust policy on the role plus an identity policy on the caller) and the external ID are covered in the IAM deep dive. These are the extra mechanics that session questions depend on.
- Same account is more forgiving than cross-account. If a trust policy names a specific IAM user or role ARN in the same account, that statement is enough on its own, subject to any permissions boundary or session policy on the caller. If it names the account (the
:rootprincipal), the caller also needs an identity policy allowingsts:AssumeRole. Across accounts, both sides are always required. - Role ARNs in
Principalare stored as IDs. When you save a trust policy that names a role ARN, IAM resolves it to the role’s unique ID. Delete and recreate that role with the same name and the trust silently breaks, because the new role has a new ID. This is deliberate: it stops someone from recreating a deleted role to inherit its access. - No partial wildcards in
Principal. To trust a pattern of roles, trust the account and add a condition onaws:PrincipalArn. - A role does not trust itself by default. If a session needs to assume its own role again, the trust policy must name that role or its account explicitly.
- Service principals need their own confused-deputy guard. For a role assumed by an AWS service, the equivalent of the external ID is a condition on
aws:SourceArnandaws:SourceAccount. - The trust policy has a size quota. It defaults to 2,048 characters and can be raised to 8,192.
The trust policy is also where every session attribute in the next three sections is controlled, through a small set of condition keys:
| Condition key | Evaluated when | Typical use in a trust policy |
|---|---|---|
sts:ExternalId | AssumeRole | Third-party confused-deputy protection (2 to 1,224 characters) |
sts:RoleSessionName | AssumeRole | Force the session name to equal ${aws:username} so logs are attributable |
sts:SourceIdentity | Any AssumeRole* that sets a source identity | Require or constrain the source identity value |
aws:RequestTag/key, aws:TagKeys | Any call that passes session tags | Require specific tags, restrict allowed values |
sts:TransitiveTagKeys | Any call that marks tags transitive | Limit which tags may persist through role chaining |
aws:MultiFactorAuthPresent, aws:MultiFactorAuthAge | AssumeRole | Require recent MFA before the role can be assumed |
aws:PrincipalOrgID | AssumeRole | Limit trust to principals inside your organization |
For organization-wide enforcement, remember that AWS STS is one of the services supported by resource control policies, so the “only identities from my organization may assume roles in my accounts” requirement can be enforced centrally. The data perimeter guide walks through that pattern.
Session policies: narrowing a role at assume time
A session policy is a policy passed as a parameter when the session is created. It applies to that one session and never grants anything; it only filters.
The rules to memorise:
- The session’s permissions are the intersection of the role’s identity-based policies and the session policies. An explicit deny anywhere still wins.
- You can pass one inline JSON document with the
Policyparameter and up to 10 managed policy ARNs withPolicyArns. - The inline document and all managed policy ARN characters combined cannot exceed 2,048 characters.
- Session policies and session tags are packed into the session token, which has its own size limit. The
SessionTokenUtilizationresponse element shows the percentage used. The olderPackedPolicySizeelement is deprecated. Exceeding the limit fails the call with a packed-policy-too-large error. - A permissions boundary on the role still applies, so the effective set is the intersection of identity policy, boundary and session policy.
aws sts assume-role \
--role-arn arn:aws:iam::111122223333:role/ReportsReader \
--role-session-name tenant-4471 \
--policy '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::reports-bucket/tenant-4471/*"}]}'
That is the classic multi-tenant vending pattern: one broadly scoped role, and a broker that hands each tenant a session restricted to its own prefix. No role per tenant is needed.
The resource-policy trap
How a session policy interacts with a resource-based policy depends on which ARN the resource policy names. This distinction is a favourite at specialty level.
| The resource-based policy names | Is the grant limited by the session policy? | Result |
|---|---|---|
The role ARN (arn:aws:iam::...:role/ReportsReader) | Yes | The grant is added to the role’s permissions first, then the session policy filters the total |
The session ARN (arn:aws:sts::...:assumed-role/ReportsReader/tenant-4471) | No | The grant is added after the session is created and bypasses the session policy |
The same asymmetry applies to permissions boundaries: a boundary does not limit permissions that a resource-based policy grants directly to the session ARN. If a scenario says a session “can still read the bucket even though the session policy does not allow it”, look for a bucket policy that names the assumed-role session ARN.
Session tags: attributes that travel with the session
Session tags are key-value pairs attached to a session when it is created. On every later request they appear as aws:PrincipalTag/key, which is what attribute-based access control (ABAC) policies match against. The identity federation guide covers ABAC design; these are the mechanics.
A session’s principal tags come from three places: tags passed on the call, transitive tags inherited from an earlier session in a chain, and tags attached to the IAM role itself.
| Rule | Detail |
|---|---|
| Maximum number | 50 session tags |
| Key and value size | Key up to 128 characters, value up to 256 characters |
| Values | One value per tag. Multi-valued session tags are not supported |
| Supported operations | AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity, GetFederationToken |
| Console | The Switch Role feature cannot pass session tags |
| Required permission | sts:TagSession, a permissions-only action |
| Conflict with a role tag | The session tag overrides a role tag with the same key, regardless of character case |
| Lifetime | Valid only for the current session unless marked transitive |
Three behaviours cause most of the wrong answers.
sts:TagSession must be in the trust policy. When an identity provider starts passing tags, every role connected to that provider needs sts:TagSession in its trust policy. A role without it does not ignore the tags. The assume call fails. If you cannot update every role at once, AWS suggests a separate IdP instance for the tag-passing configuration.
Tags from an IdP arrive in a specific shape. In SAML, each tag is an attribute named https://aws.amazon.com/SAML/Attributes/PrincipalTag: followed by the tag key, and the transitive list is the attribute https://aws.amazon.com/SAML/Attributes/TransitiveTagKeys. In OIDC, tags sit under the https://aws.amazon.com/tags claim namespace, in either a nested format or a flattened format for providers that cannot emit nested claims.
Tags are dropped at the next hop unless marked transitive. By default STS does not pass tags to a later session in a role chain. Marking a key as transitive (the TransitiveTagKeys parameter) makes it persist. Transitive tags then cannot be overridden: trying to pass a different value for an inherited transitive key fails the call, and an inherited transitive tag wins over a matching tag on the next role. Role tags themselves can never be marked transitive, and GetFederationToken does not support transitive tags because its credentials cannot assume a role.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Federated": "arn:aws:iam::111122223333:saml-provider/Corp" },
"Action": ["sts:AssumeRoleWithSAML", "sts:TagSession"],
"Condition": {
"StringEquals": { "SAML:aud": "https://signin.aws.amazon.com/saml" },
"StringLike": { "aws:RequestTag/Project": "*" },
"ForAllValues:StringEquals": { "sts:TransitiveTagKeys": ["Project"] }
}
}
]
}
That trust policy requires a Project tag and allows only that tag to be made transitive. An attacker who compromises a downstream role cannot invent a different project, because the value is fixed at the first hop.
Source identity: the one attribute nobody can change
Shared roles create an attribution problem. Ten engineers assume ProdAdmin, and CloudTrail shows ten sessions of the same role. The role session name helps, but the caller chooses it and can choose a different one at every hop. Source identity exists to close that gap.
A source identity is a string set when a role is first assumed. From then on:
- It cannot be changed for the life of the session.
- It persists through role chaining. Each later session carries the same value, and an attempt to set a different one is denied.
- It is recorded in CloudTrail, in
requestParameters.sourceIdentityon the assume event and inuserIdentity.sessionContext.sourceIdentityon every action the session takes.
The rules that the exam turns into distractors:
| Rule | Detail |
|---|---|
| Required permission | sts:SetSourceIdentity, a permissions-only action |
| Where it must be allowed | In the role’s trust policy. For role chaining and cross-account use, also in the caller’s permissions policy |
| IdP-connected roles | Every role connected to an IdP that passes a source identity needs the permission in its trust policy, or AssumeRole* fails |
| Format | 2 to 64 characters: alphanumerics, underscore, and . , + = @ -. It cannot begin with aws: |
| Supported operations | AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity |
| Console | You cannot switch to a role in the console if that role requires a source identity |
| Condition keys | sts:SourceIdentity is present on the call that sets it. aws:SourceIdentity is present on every later request |
| Blind spot | It is not captured when an AWS service or service-linked role acts on the identity’s behalf |
AWS does not validate the value. If users can type anything, the attribute is worthless, so constrain it in the trust policy. For IAM users, "sts:SourceIdentity": "${aws:username}" forces the value to match the caller. For federation, have the IdP assert it (the SAML attribute is https://aws.amazon.com/SAML/Attributes/SourceIdentity) and restrict sts:SetSourceIdentity to the provider principal.
Session name, session tags or source identity
| Attribute | Who sets it | Changeable at each hop | Survives role chaining | Best for |
|---|---|---|---|---|
| Role session name | The caller | Yes | No, each hop picks a new name | Telling sessions of one role apart |
| Session tags | The caller or the IdP | Yes, unless transitive | Only transitive tags | ABAC decisions |
| Source identity | The caller or the IdP, once | No | Always | Attribution and per-person deny rules |
When a question asks how to “identify the original user after several role assumptions”, the answer is source identity. When it asks how to “grant access based on the user’s department”, the answer is session tags.
Role chaining: what the one-hour cap really means
Role chaining is using one role’s session to assume another role. It can happen through the CLI, the API or console role switching. Three facts define it.
- A chained session lasts at most one hour. This applies regardless of the target role’s maximum session duration.
- Asking for more fails. A chained
AssumeRolewithDurationSecondsabove 3,600 returns an error. It does not quietly cap the session. - The first hop is not chaining. An IAM user assuming a role with long-term credentials can request up to the role’s maximum. The cap starts when a role session assumes a role.
That third point has a practical consequence. An application running on EC2 uses its instance profile role. When it assumes a second role, for example in another account, that is role chaining, and the second session is limited to one hour. A scenario describing “a job on EC2 that assumes a cross-account role fails when requesting a 4-hour session, although the role allows 12 hours” is describing this cap. The fixes are to refresh credentials within the hour (the SDK’s assume-role credential providers do this automatically) or to grant the instance role access directly through a resource-based policy.
| What carries into the next session | What does not |
|---|---|
| Transitive session tags | Non-transitive session tags |
| Source identity | Role session name |
| The previous role’s own tags (unless re-passed as session tags) | |
| Session policies from the earlier hop |
Tracing a chain in CloudTrail
Each AssumeRole event records the caller in userIdentity and the new temporary access key in responseElements.credentials.accessKeyId. To walk a chain backwards, take the ASIA key that performed the suspicious action, find the AssumeRole event that issued it, read the userIdentity.accessKeyId on that event, and repeat. For cross-account assumptions the event is delivered to both accounts with the same sharedEventID, so the trusted and trusting accounts can be joined. Source identity removes most of this work, which is the argument for requiring it. The logging and monitoring guide covers the wider CloudTrail design.
MFA and sessions
MFA-protected API access relies on two condition keys.
aws:MultiFactorAuthPresentis true when the temporary credentials were issued after an MFA check.aws:MultiFactorAuthAgeis the number of seconds since that check, which lets you demand recent MFA, for example within 3,600 seconds.
There are two ways to get MFA into the picture. An IAM user can call GetSessionToken with the SerialNumber and TokenCode parameters and then use those credentials. Or a role’s trust policy can require MFA, and the user passes the same two parameters to AssumeRole.
The traps:
- The key is absent on long-term credentials.
aws:MultiFactorAuthPresentexists only for temporary credentials. A deny statement written with"Bool": {"aws:MultiFactorAuthPresent": "false"}does not match a request signed with plain access keys, because the key is missing, not false. To deny everything that lacks MFA, useBoolIfExists. - For cross-account roles, enforce MFA in the trust policy. AWS documents that credentials returned by
AssumeRoledo not carry MFA information in their context, so you cannot re-check MFA on individual actions afterwards. The check happens at the door. - Federation does not count.
AssumeRoleWithSAMLandAssumeRoleWithWebIdentitytake no MFA parameters, because AWS cannot verify what the external provider did. MFA for federated users is enforced at the IdP. - Root and some device types are excluded. MFA-protected API access cannot be used with root user credentials or with U2F security keys.
Regional endpoints, the global endpoint and token versions
STS has a global endpoint, https://sts.amazonaws.com, and a Regional endpoint in every Region, such as https://sts.eu-west-1.amazonaws.com. AWS recommends Regional endpoints for lower latency, fault isolation and wider token validity. The details have changed recently, so older study notes are often wrong here.
The global endpoint is no longer always us-east-1. Historically every global-endpoint request was served from US East (N. Virginia). AWS has changed this for Regions that are enabled by default: a request to the global endpoint is now served in the Region where it originates, provided the DNS lookup is handled by the Amazon DNS server in a VPC. Requests from opt-in Regions, or resolved through any other DNS resolver, are still served from US East (N. Virginia).
To avoid breaking existing controls, several things were held constant:
- CloudTrail events for global-endpoint requests are still delivered to US East (N. Virginia).
- CloudTrail STS events now include
endpointTypeandawsServingRegionfields that show which endpoint and Region actually served the request. aws:RequestedRegionisus-east-1for global-endpoint requests, regardless of the serving Region.- The global endpoint does not share its request quota with Regional endpoints. The default STS quota is 600 requests per second, per account, per Region.
Token versions decide where a session works. Session tokens issued by a Regional endpoint are valid in all Regions. Tokens issued by the global endpoint are, by default, version 1 tokens that are valid only in Regions enabled by default. Use one in an opt-in Region such as Asia Pacific (Hong Kong) and the request is rejected. The fix is either to call a Regional endpoint or to switch the account’s global-endpoint tokens to version 2, which requires iam:SetSecurityTokenServicePreferences. Version 2 tokens are longer, which can matter to systems that store them.
aws iam set-security-token-service-preferences --global-endpoint-token-version v2Token
Activation is per account and per Region. In Regions enabled by default you can deactivate the STS endpoint in IAM account settings. In opt-in Regions, STS is activated automatically when the Region is enabled and cannot be deactivated on its own. For a cross-account call to an opt-in Region’s endpoint, it is the target account, the one that owns the role, that must have the Region enabled. An active Region is usable by every principal in the account, so per-principal restriction is done with aws:RequestedRegion.
Revoking sessions during an incident
This is the part of STS most likely to appear in a Domain 2 question. Temporary credentials cannot be deleted, so every technique is some form of deny. Choose the one whose blast radius matches the incident.
| Goal | Technique | Effect |
|---|---|---|
| Kill every existing session of a role, let new ones through | Revoke active sessions in the console, or an inline deny on aws:TokenIssueTime | Denies all actions for credentials issued before a timestamp |
| Kill one named session | Deny on aws:userid equal to the role ID, a colon, and the session name | Other sessions of the role keep working |
| Kill everything a specific person started, across chained roles | Deny on aws:SourceIdentity | Follows the person through every hop |
| Freeze the role completely | Attach the AWSDenyAll managed policy | No session, old or new, can act |
| Stop access granted by a bucket, key or queue policy | Explicit deny in the resource-based policy on aws:PrincipalArn or aws:SourceIdentity | Needed because identity-side changes do not remove resource-side grants |
How “Revoke active sessions” works
The console button attaches an inline policy named AWSRevokeOlderSessions to the role:
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"DateLessThan": { "aws:TokenIssueTime": "2026-11-09T09:30:00Z" }
}
}
}
Know these properties:
aws:TokenIssueTimeexists only on requests signed with temporary credentials, so the same statement on an IAM user would not affect that user’s long-term keys.- The console sets the timestamp roughly 30 seconds in the future to cover policy propagation. Sessions created after that are unaffected.
- You need
iam:PutRolePolicyon the role to perform it. - It affects every session of the role, including legitimate ones. Applications recover by assuming the role again. The AWS CLI caches assume-role credentials under
~/.aws/cli/cache, so the cache may need clearing. - It cannot be applied to a service-linked role.
- Roles created from IAM Identity Center permission sets cannot be edited in IAM. Revoke the user’s active permission-set session from Identity Center instead.
What revocation does not do
Revocation only invalidates credentials that already exist. If the attacker still holds whatever was used to obtain them (an IAM user’s access keys, a foothold on an instance, a federated account), they simply assume the role again and receive a session with a new issue time. A complete response therefore has three parts: revoke existing sessions, close the path that issued them, and add explicit denies on any resource policy that grants the principal access directly. For the instance-credential variant of this procedure, see the IMDSv2 and credential exfiltration guide, and for the wider playbook the threat detection and incident response guide.
AssumeRoot and centralized root access
AssumeRoot is the newest STS credential operation and the mechanism behind centralized root access in AWS Organizations. It lets a central team perform a short list of root-only tasks on a member account without that account having root credentials at all.
- It is called from the management account or the delegated administrator account for IAM, by an IAM user or role that has been explicitly granted
sts:AssumeRoot. Root credentials cannot call it. - Each call must name a task policy that scopes the session to one job. The AWS managed task policies are
IAMAuditRootUserCredentials,IAMCreateRootUserPassword,IAMDeleteRootUserCredentials,S3UnlockBucketPolicyandSQSUnlockQueuePolicy. - The session lasts at most 900 seconds.
- The global endpoint is not supported. The call must go to a Regional STS endpoint.
- The condition key
sts:TaskPolicyArnlets you restrict which tasks a given administrator may run.
aws sts assume-root \
--target-principal 111122223333 \
--task-policy-arn arn=arn:aws:iam::aws:policy/root-task/S3UnlockBucketPolicy \
--duration-seconds 900
The exam cue is a member account locked out by its own policy: “a bucket policy denies all principals, including administrators”. Historically that needed the member account’s root user. With centralized root access the answer is a privileged session using S3UnlockBucketPolicy. The multi-account governance guide covers where this sits among organization-level controls.
Two adjacent mechanisms named by the same skill
S3 presigned URLs. Skill 4.1.2 lists them next to STS because a presigned URL is a temporary credential in URL form. The session-related fact to carry: a presigned URL signed with temporary credentials stops working when those credentials expire, even if the URL’s own expiry is later. A URL meant to last hours must not be signed by a one-hour chained session. The SDK and presigned URL guide covers the rest.
Outbound identity federation. STS can now also issue tokens in the other direction. A workload calls GetWebIdentityToken and receives a short-lived, signed JWT that asserts its AWS identity to an external service, which verifies it against AWS’s OIDC discovery endpoint. It removes stored API keys for third-party services. It is newer than the SCS-C03 guide, so treat it as awareness, not a likely question.
Troubleshooting toolkit
| Symptom | Likely cause | What to check |
|---|---|---|
AccessDenied on sts:AssumeRole | One of the two sides is missing | Trust policy principal and conditions, then the caller’s identity policy, then SCPs and RCPs |
| Assume call fails only when the IdP starts sending attributes | Missing sts:TagSession or sts:SetSourceIdentity in the trust policy | Add the permissions-only action for that provider principal |
| ”DurationSeconds exceeds the MaxSessionDuration” | Request is above the role setting | Raise the role’s maximum, or request less |
| Duration error although the role allows 12 hours | Role chaining | The caller is itself a role session. Cap is one hour |
| Packed policy too large | Session policies plus tags exceed the token limit | Shorten the policy, use fewer tags, read SessionTokenUtilization |
| Credentials work in Frankfurt but fail in Hong Kong | Version 1 token from the global endpoint | Use a Regional endpoint or set version 2 tokens |
ExpiredToken in a long job | Session ended | Use SDK credential providers that refresh, or shorten the job per session |
| Trust worked yesterday, role was “recreated” today | Principal stored as role ID | Re-save the trust policy with the new role |
| Console “Switch Role” refused | Role requires a source identity or session tags | Use the CLI or API |
| Who am I, really? | Unknown credential source | aws sts get-caller-identity |
| Encoded authorization failure message | Service returned an opaque blob | aws sts decode-authorization-message |
Scenario drills
| Scenario phrase | Discriminator | Answer |
|---|---|---|
| ”Engineers share an admin role. Auditors must see which person performed each action, even after assuming a second role.” | Immutable, survives chaining | Require source identity, constrained in the trust policy |
| ”Grant access to S3 prefixes by the user’s department from the corporate directory.” | Attribute-based | SAML PrincipalTag attributes plus aws:PrincipalTag in policies, with sts:TagSession in the trust policy |
| ”Department tag must still apply after the user assumes a cross-account role.” | Persistence across hops | Mark the tag transitive |
| ”A broker issues per-customer credentials from one role.” | Scope at issue time | Session policy passed on AssumeRole |
| ”Session can read a bucket the session policy does not allow.” | Resource policy names the session ARN | Change the bucket policy to name the role ARN, or add a deny |
| ”EC2 job assumes a cross-account role and needs 6 hours. Role maximum is 12 hours. Call fails.” | Chaining cap | One-hour limit. Refresh automatically, or use a resource-based policy |
| ”Leaked role credentials valid for 12 hours. Stop them now without deleting the role.” | Existing sessions only | Revoke active sessions (aws:TokenIssueTime deny) |
| “Only one contractor’s session must be cut off.” | Single session | Deny on aws:userid with the role ID and session name |
| ”Policy denies actions without MFA, but access-key requests still succeed.” | Key absent on long-term credentials | Use BoolIfExists on aws:MultiFactorAuthPresent |
| ”CLI user must delete objects only after MFA.” | MFA for long-term keys | GetSessionToken with serial number and token code |
| ”Require MFA for cross-account administrators.” | Checked at assume time | aws:MultiFactorAuthPresent in the role’s trust policy |
| ”Workloads in a newly enabled opt-in Region get invalid token errors.” | Token version | Regional STS endpoint, or version 2 global tokens |
”Security team alarms on aws:RequestedRegion. Global STS calls from eu-west-1 show us-east-1.” | Held constant by design | Expected. Use awsServingRegion in CloudTrail for the real Region |
| ”Member account’s bucket policy locks everyone out. No root credentials exist.” | Root-only task | AssumeRoot with S3UnlockBucketPolicy from the management or delegated admin account |
| ”Vendor must access our account. Prevent another of the vendor’s customers from using our role.” | Confused deputy | sts:ExternalId in the trust policy |
| ”An AWS service assumes our role. Prevent cross-service confused deputy.” | Service principal | aws:SourceArn and aws:SourceAccount conditions |
| ”Only principals in our organization may assume any role in our accounts.” | Organization-wide | Resource control policy on sts:AssumeRole with aws:PrincipalOrgID |
| ”Temporary credentials for an app’s end users signed in with a social provider.” | OIDC, no AWS credentials on the client | AssumeRoleWithWebIdentity, usually through Amazon Cognito identity pools |
| ”Found an access key ID in a public repository. Which account owns it?” | Key lookup | GetAccessKeyInfo |
| ”Session revoked, but the attacker is back within a minute.” | Source credentials still valid | Close the issuing path as well as revoking |
Common mistakes
- Treating the role’s maximum session duration as the only limit. Role chaining caps the session at one hour, and the request fails if you ask for more.
- Assuming temporary credentials can be deleted. They can only be denied. Deleting the role works but takes every legitimate user down too.
- Forgetting that revocation is role-wide.
AWSRevokeOlderSessionshits all sessions of the role. For one session, useaws:useridoraws:SourceIdentity. - Thinking session policies can add permissions. They only intersect. The single exception that looks like an addition is a resource policy naming the session ARN.
- Adding session tags or a source identity at the IdP before updating trust policies. Roles without
sts:TagSessionorsts:SetSourceIdentitystart failing immediately. - Using the role session name for attribution. The caller chooses it and it changes at every hop. Source identity is the durable attribute.
- Writing MFA denies with
Bool. Long-term credentials do not carry the key at all. - Calling
GetSessionTokenorGetFederationTokenas root. The resulting credentials cannot be restricted later. - Assuming the global endpoint always means us-east-1, or that its tokens work everywhere. Neither is true any more without checking the DNS path and the token version.
Practising session questions
STS questions rarely announce themselves. They describe an audit gap, a job that fails after an hour, or a breach with a 12-hour window, and expect you to recognise the session mechanic behind the story. That recognition comes from repetition on realistically worded scenarios. Sailor.sh’s AWS Certified Security - Specialty Mock Exam Bundle includes full-length mock exams whose identity and incident-response scenarios are written in that indirect style, with explanations that say why the distractors fail. It works well as a readiness check once the mechanics in this guide feel familiar. For free warm-up material first, the Security Specialty practice questions are a good start.
Frequently Asked Questions
What is the difference between AssumeRole, GetSessionToken and GetFederationToken?
AssumeRole gives the caller a different identity, a role session with the role’s permissions, for 15 minutes up to the role’s maximum session duration. GetSessionToken returns temporary credentials for the same IAM user with the same permissions, mainly to add MFA context, for up to 36 hours. GetFederationToken lets an IAM user vend credentials for a named federated user, scoped by the session policy passed on the call (without one, the federated user can do nothing unless a resource-based policy names it), also for up to 36 hours.
Why is my role session limited to one hour when the role allows twelve?
Because the session was created by role chaining. When a role session assumes another role, the new session is capped at one hour regardless of the target role’s maximum session duration, and a request for a longer duration fails. The cap does not apply when an IAM user assumes a role directly with long-term credentials.
Can a session policy grant permissions the role does not have?
No. A session policy only filters. The session receives the intersection of the role’s identity-based policies and the session policies. The one case that appears to break this is a resource-based policy that names the session ARN directly: that grant is applied after the session is created and is not limited by the session policy.
What is the difference between a source identity and a role session name?
Both are strings chosen when a role is assumed, and both appear in CloudTrail. The session name can be different at every hop of a role chain. The source identity is set once, cannot be changed, and is carried into every later session in the chain. It also requires the sts:SetSourceIdentity permission, so administrators can control who may set it and to what value.
How do I revoke temporary credentials for an IAM role?
Use Revoke active sessions on the role in the IAM console, or attach an inline policy that denies all actions when aws:TokenIssueTime is earlier than a chosen timestamp. Every session issued before that time is denied, and sessions created afterwards work normally. To block a single session, deny on aws:userid or aws:SourceIdentity. Also remove whatever allowed the credentials to be obtained, or the attacker will request new ones.
Should I use the STS global endpoint or a Regional endpoint?
Use Regional endpoints. They reduce latency, isolate failures to a Region, and issue session tokens that are valid in every Region, including opt-in Regions. The global endpoint remains available, and in default-enabled Regions it is now served locally when resolved through Amazon DNS, but its default version 1 tokens do not work in opt-in Regions, and AssumeRoot does not support it at all.
Do session tags survive role chaining?
Only if they are marked transitive when they are first passed. A transitive tag is inherited by every later session in the chain, cannot be overridden with a different value, and takes precedence over a matching tag on a downstream role. Non-transitive session tags and the role’s own tags are not passed to the next session.
Conclusion
A session is more than three strings with an expiry time. It has an identity of its own, a lifetime governed by three interacting limits, and a set of attributes fixed at the moment it is created. Session policies narrow it, session tags describe it, and a source identity pins it to a person for the rest of its life and through every role it assumes afterwards. Role chaining shortens it to an hour. The endpoint that issued it decides which Regions will accept it. And when it is stolen, you do not delete it; you deny it, at exactly the scope the incident calls for, and then close the door that issued it.
Those are the mechanics the Security Specialty exam builds its identity and incident-response scenarios on. If you can read a scenario and name the session mechanic in play, whether that is chaining, a missing permissions-only action, a session-ARN grant or a version 1 token, the right answer is usually the only one left standing.