What does an assume_role block inside Terraform's aws provider do, and which credentials does it need before it can work?
answer
- base credentials first, then a session
- two-sided permission, both policies
- session name lands in CloudTrail
- external_id is for third-party access
- sessions expire mid-apply
basics
~20 sIt tells the provider to take the credentials it already resolved, call AWS STS to assume the named role, and use the temporary session credentials for every API call. It needs working base credentials that the target role's trust policy permits to assume it.
solid answer
~40 s`assume_role` is a second step layered on top of the ordinary credential chain. The provider first resolves base credentials the usual way — environment variables, a profile, an instance role — and then uses them to call `sts:AssumeRole` for the `role_arn` you gave it, receiving temporary credentials that every subsequent API call uses. Two things must be true for it to work: the base principal needs permission to call `sts:AssumeRole` on that role, and the role's own trust policy must name that principal as allowed. Beyond `role_arn` the block accepts `session_name` (which shows up in CloudTrail, so make it identifiable), `external_id` for third-party access, and `duration`. It is the standard way one pipeline identity operates in several accounts without holding a separate key for each.
code
hcl · 11 linesprovider "aws" {
region = "eu-west-1"
# Base credentials come from the environment; the provider derives a
# role session from them and uses that for every API call.
assume_role {
role_arn = "arn:aws:iam::111122223333:role/terraform-deploy"
session_name = "terraform-ci-build-4821"
duration = "2h"
}
}go deeper
Know that the block makes Terraform act as a different role than the credentials it started with, and that it needs some working starting credentials before it can perform that switch.
Explain the STS derivation step and the two-sided permission requirement — the caller's policy plus the role's trust policy — and name the useful arguments: session_name, external_id, duration.
Bring the operational failure modes: a session expiring partway through a long apply and leaving a half-applied change, the backend needing its own role, and session names chosen so CloudTrail identifies the pipeline run rather than just the role.
Own the role topology: how many hops a deployment identity takes, where the boundary between a low-privilege entry identity and per-account deployment roles sits, and how session duration, session naming and trust conditions are standardised so every change is attributable.
## What the block actually does Without `assume_role`, the provider authenticates as whatever identity the credential chain produced. With it, that identity becomes merely the *starting point*: ```hcl provider "aws" { region = "eu-west-1" assume_role { role_arn = "arn:aws:iam::111122223333:role/terraform-deploy" session_name = "terraform-ci-build-4821" } } ``` At provider configuration time, Terraform resolves base credentials, calls AWS STS to assume `terraform-deploy`, and gets back a temporary access key, secret and session token. Every resource read and write that provider instance makes afterwards is signed with the session, so CloudTrail records the role — annotated with the session name — as the actor. ## The two-sided permission requirement This is the part candidates most often get half right. Assuming a role requires agreement from both sides: - **The caller** must be allowed to perform `sts:AssumeRole` on the target role ARN, by its own identity policy. - **The role** must accept the caller, via its trust policy (the role's assume-role policy document), which names the principals permitted to assume it. If either half is missing you get an access-denied on the STS call, and the failure surfaces during plan, before any resource is touched — the provider cannot configure itself. That early failure is a feature: a permission problem shows up as "could not assume role", not as a half-completed apply. ## The other arguments worth knowing - **`session_name`** — free-form label attached to the session and visible in CloudTrail. Set it to something that identifies the pipeline and run; the default is generic and makes auditing painful when a dozen pipelines share a role. - **`external_id`** — a shared value the role's trust policy can require. Its purpose is the confused-deputy problem when a third party assumes a role in your account: the third party must present the specific external ID you issued, so another of their customers cannot trick them into acting on your account. - **`duration`** — how long the session lasts, bounded by the role's own maximum session duration. Sessions default to an hour. - **`policy` / `policy_arns`** — session policies that *further restrict* the session; they can only narrow what the role already permits, never widen it. - **`tags` / `transitive_tag_keys`** — session tags, useful when authorization policies condition on them. ## Production behaviour to be ready for **Long applies and session expiry.** A session obtained at provider configuration time has a finite life. An apply that creates slow resources — a database cluster, a managed cache, anything with a long provisioning time — can outlast a one-hour session, and calls made afterwards fail with an expired-token error partway through, leaving a partially applied change. If your applies routinely run long, raise the role's maximum session duration and request a longer `duration`, or break the configuration into smaller root modules so no single apply runs that long. **The backend assumes separately.** Remote state configuration has its own role settings and does not inherit the provider's `assume_role`. A common estate layout has state in a shared account and resources in a workload account, and both hops must be permitted. **Layering with federation.** `assume_role` composes naturally with a federated base identity: CI gets a short-lived session from OIDC federation into a low-privilege landing role, and the provider then assumes the account-specific deployment role from there. Nothing long-lived exists anywhere in the chain. **Auditing.** Because the session name travels into CloudTrail, a well-chosen `session_name` is the difference between "role terraform-deploy destroyed the bucket" and "run 4821 of the platform pipeline destroyed the bucket". Treat it as an observability field, not decoration. ## The interview point The strong answer says three things: `assume_role` is a *derivation* step on top of the ordinary chain rather than a replacement for it; the permission is two-sided, caller policy plus role trust policy; and the payoff is that one identity — ideally itself short-lived — can act across many accounts without any account-specific static key existing.
- What is external_id for, and when does it matter?It defends against the confused-deputy problem in third-party access. When a vendor assumes a role in your account, their trust relationship could otherwise be exercised on behalf of any of their customers. You issue a unique external ID, the role's trust policy requires it, and the vendor must present exactly that value — so one customer cannot induce the vendor to act on another's account.
- An apply that provisions a slow resource fails partway through with an expired-token error. What is happening and what do you change?The role session obtained when the provider configured itself reached its expiry while the apply was still running, so later API calls were rejected. Raise the role's maximum session duration and request a longer `duration`, or split the configuration so no single apply runs longer than a session. Then reconcile the partially applied state before retrying.
- Can a session policy passed through assume_role grant permissions the role lacks?No. Session policies only intersect with the role's existing permissions — the effective set is the overlap. They are a narrowing tool, useful for giving a specific run less authority than the role generally has, and they can never be used to escalate beyond what the role itself is allowed to do.
saying these in an interview costs you the question
- assume_role removes the need for any base credentials
- Only the caller's policy has to allow it
- A session policy can grant more than the role has
- Sessions last as long as the apply needs
- The state backend inherits the provider's assumed role