Business Challenge
The problem Roles Anywhere solves is real and worth solving. “Using IAM Roles Anywhere means you don't need to manage long-term AWS credentials for workloads running outside of AWS.” A build agent, an on-premises job server, a VM in another cloud — instead of an access key pair that lives until somebody remembers it, the workload presents an X.509 certificate and receives a temporary session.
The mechanism is a trust anchor: “A trust anchor is a reference to either AWS Private CA or an external CA certificate… There can be several trust anchors in one AWS account.”
Register the CA, point a role at the service, and you are done. The word "anchor" does a lot of work in that sentence, and it is the wrong word for what the object does.
AWS puts this under a heading called Account trust boundary, and the heading is the answer: “For IAM Roles Anywhere, the trust boundary is established at the account level.”
What that means in practice: “Certificates issued by any trust anchor in the account can be used to assume any target role in that same account, unless you specify conditions in the role's trust policy.”
So two teams, two CAs, two trust anchors, two roles in one account is not two isolated paths. It is four, and the two you did not intend are indistinguishable from the two you did. Registering a CA for one purpose grants it the union of everything Roles Anywhere can reach in that account.
FixEvery Roles Anywhere role gets an aws:SourceArn condition naming its trust anchor. Without it the anchor is decorative.
The second bullet under that heading is one sentence and it is the one worth carrying away: “There is no automatic integration with organization-wide controls.”
An organisation that governs identity centrally — and today's daily is about exactly that machinery — does not get Roles Anywhere governance for free. The trust decision lives in the account, in a role's trust policy, written by whoever created the role.
That is a governance surface in the one place org-level tooling does not look, and it is created by a team solving a credential-hygiene problem, usually quickly, usually with the console's default.
FixTreat rolesanywhere:CreateTrustAnchor as a privileged action and deny it outside a reviewed path.
Revocation exists, and it is pull-only:
“Certificate revocation is supported through the use of imported certificate
revocation lists (CRLs)… You can import a CRL that is generated from your CA using
ImportCrl…”
And then the sentence that decides your incident response: “Callbacks to CRL Distribution Points (CDPs) or Online Certificate Status Protocol (OCSP) endpoints are not supported.”
AWS never asks your PKI whether a certificate is still good. It knows only what you last imported. So
a certificate revoked in your CA keeps working until somebody runs
ImportCrl — and the gap between those two events is not visible from
either side.
Make CRL import part of the revocation procedure itself, not a scheduled job that runs afterwards.
Architecture
The exchange is: certificate → CreateSession → temporary
credentials, with the role's trust policy as the only gate.
What the trust policy has to say
Three actions, not one:
“The policy must grant the permissions: sts:AssumeRole,
sts:SetSourceIdentity, sts:TagSession.”
The second and third are what make the certificate's contents available as policy inputs, which is the part worth understanding: “IAM Roles Anywhere extracts values from the subject, issuer, and Subject Alternative Name (SAN) fields of the authenticating certificate and makes them available for policy evaluation via the sourceIdentity and principal tags.”
So a trust policy can condition on aws:PrincipalTag/x509Subject/CN,
aws:PrincipalTag/x509Issuer/CN,
aws:PrincipalTag/x509SAN/DNS and the rest. That is a genuinely good design
— your PKI's naming becomes your authorisation vocabulary, and it composes with everything
#37 covers about trust policies generally.
The scoping condition is separate and it is the one from the challenge above:
“When a client obtains temporary security credentials from IAM Roles Anywhere, the
aws:SourceArn and aws:SourceAccount will be set
based on the ARN of the trust anchor specified in the call to
CreateSession.” AWS's reason for insisting on it is named:
it “prevents IAM Roles Anywhere from acting as a potential confused deputy.”
Four places the certificate's identity changes shape
This is the half that will cost someone an afternoon, because in each case the certificate is valid, the session is issued, and a condition that reads correctly does not fire.
The source identity prefix depends on the length of the common name. Three rules:
“"CN=": the common name of the subject in the certificate
is set and less than or equal to 61 characters…
"ID=": the common name of the subject in the certificate is not
set… "" (empty string): the common name of the subject in the
certificate is set and has a length from 62 to 256 characters.”
A condition written as StringEquals sts:SourceIdentity "CN=buildagent-..."
works for every certificate until one is issued with a 62-character CN, at which point the prefix is gone
and the condition fails. Past 256 the call does not degrade, it stops:
“IAM Roles Anywhere does not support subject common names longer than 256 characters, and the
CreateSession request fails.”
Only the first SAN value of each type is mapped.
“IAM Roles Anywhere will map the first value of the following types:
DNS Names, Directory Name (DN), and
URI Names.” A certificate carrying two DNS SANs exposes one. A
condition on the second never matches, and the certificate contains it.
Repeated RDNs are flattened into one string, in certificate order.
“Because principal tags do not support multiple values, IAM Roles Anywhere combines multiple
values into a single string, separating them with forward slashes (/) in the order they appear in the
certificate.” So CN=alice, OU=Security, OU=Engineering, OU=Research
becomes one tag with the value Security/Engineering/Research.
An equality condition on that tag is an assertion about the order your CA happens to emit OUs in. Reissue with the same three OUs in a different order and the policy stops matching.
The session name is the serial number, not the name.
“IAM Roles Anywhere sets this automatically, using the hex-encoded serial
number of the authenticating certificate.” So the assumed-role ARN in CloudTrail
identifies the certificate, not the workload; the human-readable identity is in source identity instead.
AWS's own worked conversions:
“Decimal serial number 291 converts to hex 123, which becomes
ID=0123… Decimal serial number 17767 converts to hex 4567, which
becomes ID=4567.”
The trust policy section says the extracted values “need to match the pattern defined in STS session tags. The service ignores values that do not match this pattern. You cannot use these values in policy conditions.” Read in isolation that last sentence appears to forbid the very thing every example on the page does. It does not: its subject is the ignored values — the ones that failed the session-tag pattern. The tags that do match are usable, which is why the page then says they are “also available to be used in conditions in the identity-based policy attached to the role” and shows five policies conditioning on them. Worth knowing because the practical consequence is real: a certificate field containing characters the session-tag pattern rejects is dropped silently, and a condition on it fails closed with nothing to show you why.
Why This Architecture Holds Up
The certificate requirements are strict, and that is load-bearing
For end-entity certificates:
“The certificates MUST be X.509v3… If the CA field is present
in the basic constraints extension, its value MUST be false. The key usage
MUST include Digital Signature. The signing algorithm MUST include
SHA256 or stronger. MD5 and
SHA1 signing algorithms are rejected.”
The CA: false requirement is the interesting one — it stops an
intermediate CA certificate being used as a workload identity, which would otherwise let anything that
could issue certificates also authenticate as one.
“For AWS Private CA trust anchors, only the validity period can be modified after creation. When the validity period changes, you must call UpdateTrustAnchor to register this change. IAM Roles Anywhere honors certificates based on the validity period found during the most recent TrustAnchor Create/Update event.” So the validity AWS enforces is the one it read when you last created or updated the anchor. Change it in Private CA and nothing takes effect until UpdateTrustAnchor runs. This is the same shape as the CRL behaviour: Roles Anywhere holds a copy of your PKI's state and does not refresh it on its own.
The profile is the second gate, and it has one slot
“A profile can have many IAM roles, but only one session policy. Any session
returned by a CreateSession call that references the profile will have its
permissions limited by the session policy.”
That shapes how you lay profiles out: a profile is the unit of session-policy granularity, so roles whose sessions need different ceilings belong in different profiles regardless of how convenient one profile would be. And a session policy only subtracts — it is the seventh gate from #35, in a place you may not have expected to find it.
Everything is Regional, including the pairing
“All IAM Roles Anywhere resources are regional and they must be created in the same account and region to be used together.” A trust anchor and a profile in different Regions are not a configuration, and the multi-Region story is replication of the whole set rather than one anchor serving many Regions.
That cuts both ways and the good side is worth naming: because the account is the trust boundary and resources are Regional, a per-workload account remains the cleanest isolation available. The documented multi-account guidance is an onward pointer rather than a feature, which is itself informative — there is no org-level construct here to reach for.
Key Architecture Decisions
| Decision | Choice | Reasoning |
|---|---|---|
| Scoping a role to its CA | aws:SourceArn on the trust anchor ARN, always |
Without it, any trust anchor in the account can assume the role. |
| Isolating two workloads | Separate accounts, not separate trust anchors | The trust boundary is the account; anchors do not partition it. |
| Creating trust anchors | Privileged, reviewed action | A new anchor widens what can reach every existing Roles Anywhere role. |
| Identity conditions | x509Issuer and SAN, over bare subject CN |
The CN also drives the source-identity prefix, which changes at 61 characters. |
| Conditioning on OU | Avoid equality on multi-valued RDNs | They flatten to one slash-joined string in certificate order. |
| Revocation | ImportCrl inside the revocation runbook |
No CDP or OCSP callbacks; AWS knows only what was imported. |
| Private CA validity changes | Always follow with UpdateTrustAnchor |
The enforced window is the one read at the last create or update. |
| Session ceilings | One profile per distinct ceiling | A profile carries many roles but only one session policy. |
The audit that finds the open path
One query, and it is cheap: list every role in the account whose trust policy names
rolesanywhere.amazonaws.com, and check each for an
aws:SourceArn or aws:SourceAccount condition. Every
role without one is reachable by every certificate every registered CA has ever issued.
Then count trust anchors. One is a design. Several, created at different times by different teams, is the case the account trust boundary was written to warn about.
Closing Thought
Roles Anywhere is a good trade. Exchanging a certificate for a fifteen-minute session is strictly better than an access key with no expiry, and the mechanism does what it says. The thing to notice is where it moved the decision to.
With an access key, the authorisation story is entirely inside AWS and entirely visible to AWS tooling. With Roles Anywhere, half of it is in your PKI: which CA signs, what goes in the CN, how many OUs a certificate carries and in what order, when a revocation list was last exported. None of those are IAM changes, none of them appear in an IAM diff, and three of them can silently stop a condition from matching.
That makes the certificate template a security control, which is not where most organisations keep their
security controls. The practical consequence is small and specific: write the
aws:SourceArn condition on day one, and treat the certificate profile your CA
issues from as part of the policy, because that is what it is.
Security & Identity — AWS Private CA: what a private CA costs to operate rather than to create, why the hierarchy you choose is close to permanent, and where certificate lifetime stops being a security parameter and becomes an availability one.
Official AWS Reference
- The IAM Roles Anywhere trust model — required trust-policy actions, certificate field mapping, source-identity rules, signature validation and revocation
- What is IAM Roles Anywhere — trust anchors, profiles, and the account trust boundary
- AWS Private CA — further reading on operating the CA behind a trust anchor; no claims in this post are drawn from it
Comments