
ktIAM Roles Anywhere hands out IAM Role temporary credentials to workloads outside AWS, using X.509 certificates instead of long-lived access keys. This article walks through the Trust Anchor / Profile / Role triangle, the CreateSession signing flow, what the credential helper actually does, CRL-based revocation, and pricing, with diagrams the whole way.
"I want to drop a file from an on-prem server into S3."
"I want to read DynamoDB from a Kubernetes pod sitting in my datacenter."
"I want to pull a secret from AWS Secrets Manager from an app in someone else's cloud."
Do this the naive way and you end up here:
AKIA... kind)~/.aws/credentials, env vars, or some on-prem Secrets ManagerThis is where most production incidents start today. Long-lived access keys leak and stay leaked, rotation gets forgotten, and there is no record of who copied them where or when.
AWS IAM Roles Anywhere is the mechanism that hands IAM Role temporary credentials to workloads outside AWS without distributing any long-lived key. The key material is replaced by an X.509 certificate.
This article goes deep on Roles Anywhere.
Roles Anywhere sits on top of two things: IAM Role and PKI (the certificate world). If either is fuzzy you will get lost fast. The bare minimum below.
| Term | What to remember |
|---|---|
| IAM Role | A box that says "who is allowed to take this permission on". It has two parts: a Trust Policy (who can assume it) and a Permission Policy (what the assumer can do) |
| AssumeRole | The act of taking on a Role. When it succeeds, you immediately get back a set of temporary credentials |
| STS (Security Token Service) | The AWS service that issues temporary credentials. The sts:AssumeRole family of APIs lands here |
| Temporary credentials | A three-piece set: AccessKeyId + SecretAccessKey + SessionToken. Default lifetime 1 hour, up to 12 hours via the Role config |
| Term | What to remember |
|---|---|
| X.509 certificate | A digital document where a CA signs "this public key belongs to this entity". The cert sitting in front of any HTTPS site is the same shape |
| CA (Certificate Authority) | The party that issues certificates. Trusting a CA's certificate means trusting every certificate it has ever issued |
| Private CA | A CA for closed environments such as inside a company. AWS sells a managed version called AWS Private CA (formerly ACM PCA) |
| PKI (Public Key Infrastructure) | The whole ecosystem of issuing, distributing, and revoking certificates |
| Private key | The key paired with the certificate. Digital signatures are made with it. Never put it on the network |
Roughly: Roles Anywhere is the mechanism that makes AssumeRole callable using an X.509 certificate's private-key signature, instead of an IAM User's long-term key.
Roles Anywhere has three specific concepts: Trust Anchor / Profile / Role. Pin them down visually first.
The three actors and their jobs:
| Concept | What it is | What it holds |
|---|---|---|
| Trust Anchor | The declaration "I (this AWS account) trust this CA" | A reference to an AWS Private CA, or the PEM of an external CA |
| Profile | The declaration "for callers authenticated via this CA, which Roles can they use and with what session limits" | A list of allowed Role ARNs + session duration + optional Session Policy |
| IAM Role | The permission body that activates once assumed | Trust Policy (allowing the Roles Anywhere service principal) + Permission Policy |
Walking through each in order.
A Trust Anchor is the declaration "this AWS account trusts this CA". When Roles Anywhere sees a certificate, it walks the chain to confirm the certificate was issued by this CA.
There are two ways to create a Trust Anchor.
AWS Private CA (formerly ACM PCA) is AWS's managed paid CA. When creating a Trust Anchor you say "use this PCA", and every certificate issued by that PCA is trusted automatically.
PCA has two modes (Tokyo region reference pricing, varies by region):
Upside: issuance, revocation, and renewal automation lean on AWS. The AWS Private CA Issuer for cert-manager lets Kubernetes consume it.
Downside: either mode bills a flat monthly fee just for having a CA stood up. For verification or dev work, an external CA is cheaper.
Upload a CA certificate in PEM and register it as a Trust Anchor. If you already have an internal PKI (HashiCorp Vault, smallstep step-ca, an OpenSSL-based homemade CA, etc.), the extra cost is zero.
aws rolesanywhere create-trust-anchor \
--name "my-internal-ca" \
--source '{
"sourceType": "CERTIFICATE_BUNDLE",
"sourceData": {
"x509CertificateData": "-----BEGIN CERTIFICATE-----\nMIID...\n-----END CERTIFICATE-----"
}
}' \
--enabled
With an external CA you own revocation management (CRL updates). Covered in §8.
A Profile is "the usage rules for callers authenticated against a given Trust Anchor".
What goes into a Profile:
MaxSessionDuration)A Session Policy intersects with the Role's Permission Policy via AND. Even if the Role allows s3:*, narrowing the Session Policy to s3:GetObject means only s3:GetObject is effectively permitted.
The Role itself is created the usual way, but its Trust Policy (the policy saying "who can Assume this Role") has a Roles Anywhere-specific shape:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "rolesanywhere.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession",
"sts:SetSourceIdentity"
],
"Condition": {
"StringEquals": {
"aws:PrincipalTag/x509Subject/CN": "server-a.example.com"
},
"ArnEquals": {
"aws:SourceArn": "arn:aws:rolesanywhere:ap-northeast-1:123456789012:trust-anchor/abc-..."
}
}
}
]
}
Key points:
rolesanywhere.amazonaws.com. Without this entry, AssumeRole via the Roles Anywhere CreateSession path will not worksts:TagSession lets the certificate's Subject / SAN / Issuer be injected as session tags (more on this below)aws:PrincipalTag/x509Subject/CN let you narrow down further based on the certificate contents. Fine-grained control like "only certificates with CN server-a.example.com may assume this" is possibleaws:SourceArn pins the call to a specific Trust Anchor, so a request coming from a Trust Anchor you did not expect is deniedA session created through CreateSession + AssumeRole automatically carries certificate attributes as tags. The common ones:
| Tag key | Content |
|---|---|
aws:PrincipalTag/x509Subject/CN |
Common Name of the certificate Subject |
aws:PrincipalTag/x509SAN/DNS |
DNS name in the Subject Alternative Name (SAN) |
aws:PrincipalTag/x509SAN/URI |
URI in SAN (e.g. a SPIFFE ID like spiffe://example.com/ns/prod/sa/app) |
aws:PrincipalTag/x509Issuer/CN |
CN of the issuing CA |
aws:PrincipalTag/x509Serial |
Certificate serial number |
A small bit of supplementary vocabulary:
spiffe://...). If your internal identity platform uses SPIFFE, dropping a SPIFFE ID into the SAN URI lets the AWS side reference it directly in a ConditionThe upshot: the Role's Permission Policy can also use aws:PrincipalTag/x509Subject/CN in its Conditions. Patterns like "the server-a.example.com certificate can only write under the prefix=server-a/* portion of S3" become possible. That is ABAC (Attribute Based Access Control): instead of carving permissions up by Role (RBAC-style), principal attributes (tags) dynamically tighten what is allowed.
Tracing what actually happens from the client's first call until temporary credentials are in hand.
Key points:
AWS4-HMAC-SHA256 (symmetric HMAC using the access key). CreateSession uses one of AWS4-X509-RSA-SHA256 / AWS4-X509-ECDSA-SHA256 / AWS4-X509-MLDSA (the last one is post-quantum, PQC-capable) depending on the key type. The Canonical Request construction is the same as SigV4. Only the final step is an asymmetric X.509 signature instead of HMACHand-rolling the CreateSession signing on the client side is not realistic, so AWS ships an official binary called aws_signing_helper (repo: aws/rolesanywhere-credential-helper). That binary is the credential helper.
aws_signing_helper plugs into the AWS CLI / SDK credential_process spec. Drop this into ~/.aws/config and both the CLI and any SDK transparently fetch credentials through Roles Anywhere:
[profile myapp]
credential_process = /usr/local/bin/aws_signing_helper credential-process \
--certificate /etc/pki/server.pem \
--private-key /etc/pki/server.key \
--trust-anchor-arn arn:aws:rolesanywhere:ap-northeast-1:123456789012:trust-anchor/xxxx \
--profile-arn arn:aws:rolesanywhere:ap-northeast-1:123456789012:profile/yyyy \
--role-arn arn:aws:iam::123456789012:role/MyAppRole
A call like aws s3 ls --profile myapp triggers credential_process, which runs aws_signing_helper, which returns the JSON. The AWS CLI / SDK takes care of automatic credential refresh. No manual refresh needed.
The choice of private-key storage sets the ceiling on your Roles Anywhere operational quality. aws_signing_helper supports the following backends. Leak resistance rises as you go down the table.
| Storage | Properties | Leak resistance |
|---|---|---|
File (/etc/pki/server.key etc.) |
Easiest. Anyone with read access can cat it |
Low |
| OS keystore (Windows Certificate Store / macOS Keychain) | Protected by OS access control | Medium |
| PKCS#11 module (HSM / smartcard) | Key stays inside the HSM, only signing operations are delegated | High |
| TPM 2.0 (secure chip on the motherboard) | Key sealed into hardware, non-exportable | High |
In high-security environments, sealing the key into PKCS#11 (HSM) or TPM 2.0 so that the key cannot be extracted at all is the right move. aws_signing_helper exposes flags like --cert-selector and --tpm-key-handle to wire into these backends.
You will eventually need to kill a compromised server's certificate immediately. Roles Anywhere supports CRL (Certificate Revocation List).
Generate a revocation list on the CA side and register it in Roles Anywhere as PEM.
aws rolesanywhere import-crl \
--name "my-ca-crl" \
--crl-data file://crl.pem \
--trust-anchor-arn arn:aws:rolesanywhere:ap-northeast-1:123456789012:trust-anchor/xxxx \
--enabled
Once registered, Roles Anywhere checks the CRL on every CreateSession. Calls from revoked certificates are rejected.
When the Trust Anchor source is PCA, calling revoke-certificate on the PCA causes the PCA to publish a CRL into S3 within about 30 minutes. The standard pattern is to catch that with Lambda and feed it to the ImportCrl API.
When you need to disable it during incident response, DisableCrl flips the check off and EnableCrl turns it back on. In normal production, leave it on.
Roles Anywhere is powerful but not for every case. The decision flow:
Takeaways:
| Item | Default | Increase request |
|---|---|---|
| Trust Anchors per account | 50 | Allowed |
| Profiles per account | 250 | Allowed |
| Roles per Profile | 250 | Not allowed (hard limit) |
| Registered certificates per Trust Anchor | 2 | Not allowed (two slots, for rotation) |
| CRLs per Trust Anchor | 2 | Not allowed |
| CreateSession rate | 10 req/sec | Allowed |
| Session lifetime | 15 minutes to 12 hours | Within the Role's MaxSessionDuration
|
Note that CreateSession is 10 req/sec. A design that pulls short-lived credentials in volume will hit this per-Region rate. The basic pattern is to cache credentials on the client side and refresh just before expiration. aws_signing_helper's credential_process does this automatically.
❌ Don't
rolesanywhere.amazonaws.com alone, with no aws:SourceArn or certificate Conditions✅ Do
cert-manager and step-ca's auto-renew machinery is the standard patternaws:SourceArn (Trust Anchor) and aws:PrincipalTag/x509Subject/CN into the Role's Trust PolicyDisableCrl ready as an operations break-glassaws:PrincipalTag/x509...) to drive ABAC in the Role's Permission Policyaws_signing_helper ships as a credential_process provider, so existing CLI and SDK code works as-isImportCrl. PCA-backed setups can auto-integrate via S3