Cloud Infrastructure · Identity and Access
Role Assumption and the Shape of a Temporary Session
How a caller exchanges long-lived identity for short-lived credentials, what the issued token actually carries, and why revocation is harder than expiry.
A long-lived access key is a password that never changes and that nobody can tell has leaked until it is used. The industry’s answer to that is not to make the key harder to steal but to stop having keys: a workload proves its identity to a token service, receives a credential valid for a bounded window, and repeats the exchange when the window closes. The mechanism is small. Its consequences for revocation, caching, and clock handling are not.
The exchange, in three artifacts
A caller asks a security token service for credentials by presenting something it already holds and naming the role it wants. The response contains three artifacts, and conflating them causes most of the confusion around temporary credentials.
The first is an access token or a set of signing credentials: a key identifier, a secret, and often a session token string that must accompany every subsequent request. The secret is used to sign requests; the session token is what distinguishes a temporary principal from a permanent one when the request reaches the service.
The second is an expiry timestamp. Its precision matters more than it looks, because it is absolute, not relative: a workload that computes its refresh interval from its own clock rather than from the returned instant will refresh late or early depending on drift.
The third is a session identifier and the identity of the role that was assumed. Downstream audit records attribute actions to the role session, not to the role and not to the human or service that assumed it. The role session name is therefore the only hook for attribution, and it is chosen by the caller at assumption time. A caller that passes a constant name has made every action by every instance of that workload indistinguishable in the logs.
The whole thing is a token exchange in the OAuth sense: one credential is presented, a different one with narrower scope and shorter lifetime is issued. RFC 8693 formalizes that shape for generic OAuth deployments; the cloud token services implement the same pattern with their own request grammar.
What the credential does not contain
A common mental model treats the issued credential as a serialized bundle of permissions. It is not. The credential is an identifier plus proof of possession. The permissions are looked up server-side at request time from the role’s attached policies, the session policy passed at assumption, the identity’s permission boundary, and the organization policies above the account.
This separation is why a session can be narrowed but never widened. The session policy passed during assumption intersects with the role’s policies, so a service that assumes a broad role and hands a session policy to a sub-process gets a strictly weaker session. It also means permission changes take effect immediately for already-issued sessions: editing the role’s policies changes the answer for a token that was minted an hour ago, because the token never held the permission in the first place.
Some token formats do carry claims. An OIDC identity token is a JWT with issuer, subject, audience, and expiry in its payload, and that payload is what a relying party verifies. The distinction is worth holding onto: a JWT is self-describing and can be validated offline against a key set; a cloud session credential is opaque and validated online by the service that receives the request. Opaque credentials permit instant revocation of the permission set. Self-describing credentials permit offline verification and horizontal scale. Choosing one is choosing which of those properties the deployment requires.
Durations, chaining, and the refresh race
Temporary credentials have a maximum lifetime, and the maximum is shorter for credentials obtained by chaining than for those obtained directly. A role that assumes another role cannot receive a session that outlives the session it used to make the call; the effective expiry is the minimum of the requested duration, the role’s maximum session duration, and the remaining lifetime of the calling session. Chained assumption therefore shrinks the window at each hop, and a chain of three hops has a usable window much shorter than any individual role’s configured maximum.
The refresh race follows from that. A process that refreshes at eighty percent of the window is fine when the window is an hour and dangerous when it is fifteen minutes, because the request that discovers the credential is about to expire is itself subject to the same latency and retry budget. The safe structure refreshes well before expiry, caches the new credential under a lock so concurrent workers do not each trigger a separate exchange, and treats a clock skew between host and token service as a first-class failure. Signing schemes tolerate only a small skew, commonly five minutes, before a signature is rejected as outside its validity window.
The lock matters more than it appears. A token service that receives a hundred simultaneous exchanges from the same workload will serve them, and each exchange is an audited event. A refresh storm turns a routine expiry into a page of security alerts and a burst of latency at the exact moment the workload is least able to absorb it.
Revocation is a property of the issuer, not the token
Because the credential is opaque and permissions are looked up at request time, there are two distinct revocation questions. Changing the role’s policies changes what existing sessions may do, immediately and without any token being invalidated. Ending a session entirely requires an explicit action at the issuer, and the effect propagates to services with a delay that depends on how each service caches the session’s validity.
That caching is the reason revocation is not instantaneous. Services that validate a session token on every request can observe a revocation on the next request; services that validate once and cache the result for the session’s lifetime will honour the credential until it expires. The window between revocation and enforcement is therefore a property of the receiving service, not of the issuer, and it is not documented per service in a way that can be enumerated.
An explicit deny is the more reliable instrument. A deny statement evaluated against the session’s principal takes effect wherever the policy is consulted, without depending on token caches. The interaction between deny and the gates that cap a session is covered in the evaluation order.
Deleting the role is the bluntest instrument and the one with the widest blast radius: it invalidates assumption for everyone, and it invalidates existing sessions only insofar as services re-check the role’s existence. It is not a substitute for revoking the specific session that leaked.
Where the trust is actually stored
Assumption requires a trust policy on the target role: a resource-based document naming which principals may assume it and under what conditions. That document is the security boundary. The identity policy of the caller is the other half of the check, and for cross-account assumption both halves must allow.
Because the trust policy is written by the role owner and evaluated against a principal named by the caller’s account, the two sides can disagree about who the caller is. The classic disagreement is a service that acts on behalf of many customers and can be induced to assume a role in a third party’s account. That failure, and the condition that prevents it, is treated in cross-account trust and the confused deputy problem.
For workloads on cloud instances, the exchange is automatic: an agent reachable at a link-local address serves credentials to whatever process can reach it, which means the network position is the identity. That conflation, and its consequences for containers and proxies, belongs to the instance credential chain.
The design constraint, stated plainly
Long-lived keys exist because they are simple: copy a string into a config file, and the workload works. Short-lived credentials buy three properties at the cost of a dependency. They bound the damage of a leak to the remaining lifetime of the credential, which is a real reduction but not an elimination. They make every credential issuable and auditable at a known point in time, so a log of exchanges is a log of who held what. And they remove the static secret from disk, so a compromised filesystem does not automatically yield long-term access.
The cost is that the token service is now in the request path at start-up and periodically thereafter. A workload that cannot reach it cannot start. A workload whose refresh logic is wrong fails at a time determined by the clock, not by load. That failure mode is worse than a static key in one respect: it is periodic and correlated, so every instance of the workload fails at once rather than only the instance whose disk was read.
The mitigation is not to lengthen the window until the problem disappears. A long window converts the refresh race into a rare event that nobody tests. The mitigation is to make the refresh path an ordinary code path with the same retry, logging, and error handling as any other dependency, and to keep the window short enough that a leaked credential stops being useful before it stops being valid.
References
- RFC 6749: The OAuth 2.0 Authorization Framework — IETF
- RFC 7519: JSON Web Token (JWT) — IETF
- Requesting temporary security credentials — AWS Identity and Access Management User Guide
- RFC 8693: OAuth 2.0 Token Exchange — IETF