Privilege Escalation Using AWS IAM Roles Anywhere

May 12, 2025

IAM Roles Anywhere allows external workloads—like on-prem servers or CI runners—to authenticate to AWS using X.509 certificates issued by a trusted certificate authority (CA). These CAs are registered as Trust Anchors, and can be reused across regions, accounts, and roles. But without strict scoping in the trust policy, this flexibility can be abused for lateral movement or privilege escalation.

🚨 As warned in the AWS Docs in multiple pages:

“Without a Condition statement present in a role trust policy, any valid certificate from the CA used as the trust anchor… may be used to assume a role via IAM Roles Anywhere.”

Although if you create a role using the AWS Console the default policy does not follow this best practice.


Abusing Open Trust Policies for Privilege Escalation

Here’s a dangerously open trust policy, which is is the default if you create the role via the AWS Console:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "rolesanywhere.amazonaws.com"
      },
      "Action": [
        "sts:AssumeRole",
        "sts:SetSourceIdentity",
        "sts:TagSession"
      ]
    }
  ]
}

This policy lacks any Condition to restrict:

A properly scoped Trust Policy could look something like this (more examples).

"Condition": {
          "StringEquals": {
            "aws:PrincipalTag/x509Issuer/CN": "ci-runner"
          },
          "ArnEquals": {
            "aws:SourceArn": [
              "arn:aws:rolesanywhere:region:account:trust-anchor/TA_ID"
            ]
          }
        }

Attack Scenario

Let’s say an attacker can extract the cert and private key from a compromised CI runner (e.g., through disk access or environment variable leakage). That runner was issued a cert with CN=ci-readonly. The intended role only had read permissions.

However, another high-privilege role, AdminOpsRole was configured with the default open trust policy.

The attacker can now pivot:

aws_signing_helper credential-process \
  --certificate ci-runner.pem \
  --private-key ci-runner.key \
  --trust-anchor-arn arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/ta-id \
  --profile-arn arn:aws:rolesanywhere:us-east-1:123456789012:profile/ci-profile \
  --role-arn arn:aws:iam::123456789012:role/AdminOpsRole

The STS call succeeds because the cert is valid and the trust policy on AdminOpsRole doesn’t scope who can assume it. What should have been a restricted CI identity is now a gateway to admin access.

IAM Roles Anywhere is a great tool for hybrid identity—but like any trust-based system, its strength depends entirely on how narrowly that trust is scoped.