Skip to main content

STS and Role Assumption

AWS Security Token Service (STS) hands out temporary credentials in exchange for proof of identity. Every credential used in the platform comes from STS, whether the caller is a person who signed in or a pipeline running in GitHub.

What it does

STS has a few operations that matter here. AssumeRole swaps one set of credentials for a session in another role, possibly in another account. AssumeRoleWithWebIdentity does the same for a caller that presents a signed token from an external identity provider, such as GitHub. TagSession attaches tags to the session. Every session expires: a role session lasts one to twelve hours, and nothing can extend it. Because credentials are temporary, there is nothing to rotate and nothing to leak for long.

Role chaining is assuming a role from a session that was itself obtained by assuming a role. The platform uses one hop of chaining for pipelines.

How BuiltForProd uses it

Two entry points lead into the accounts. People sign in through IAM Identity Center, which creates a role session for them. Pipelines start from a GitHub Actions job:

  1. The job presents its OIDC token to STS. The acme-<repo>-deployer role in core-auto trusts the GitHub provider only for its own repository, for the audience sts.amazonaws.com and for the subjects the delivered workflows present: the main branch, a pull request, or a declared GitHub Environment (see GitHub OIDC).
  2. The deployer role assumes acme-terraform-deployer in the target account. That role, created in every account by modules/account-baseline, trusts only core-auto principals whose ARN matches acme-*-deployer, and allows sts:AssumeRole and sts:TagSession.
  3. State reads and writes go through acme-terraform-state-access in core-root.

root.hcl generates the provider assume_role block for every unit from org_accounts.hcl, so no unit names an account id or a role. The landing-zone role may assume acme-terraform-* in any account; the blueprint roles only in plat-* accounts plus the state-access role.

Other STS callers follow the same pattern with their own roles: the secrets repository workflow assumes acme-secrets-syncer in core-security, then the target account's deployer role, to write parameters; the ACM certificate unit assumes acme-route53-cross-account in core-dns to write validation records; the private-zone units assume it in core-network. The guardrails SCP requires MFA for any principal that is not an SSO session or a tagged automation role, which is why each of these roles carries mfa-exempt = true.

Terms you will see

TermMeaning
Temporary credentialsAn access key, secret key and session token that expire together.
AssumeRoleThe STS call that opens a session in a role.
AssumeRoleWithWebIdentityThe STS call that opens a session from an external token, such as GitHub's.
Role chainingAssuming a role from a session that came from another role.
Session tagA key-value pair attached to a session with TagSession.
Subject (sub) claimThe field in the OIDC token that names the repository and ref.
Audience (aud) claimThe intended recipient of the token; sts.amazonaws.com here.

Where to read more