Every IAM OIDC identity provider and every IAM Roles Anywhere trust anchor in an AWS account is a door that lets something outside AWS mint temporary credentials, and most accounts have doors nobody remembers opening. This guide is an audit procedure: how to enumerate OIDC providers and Roles Anywhere trust anchors, profiles and subjects in each account, which trust policy conditions to check, how to find federation that is no longer used, and how to remove it safely. It is for cloud security engineers, platform teams and identity teams reviewing workload federation across an AWS Organization. It does not repeat design guidance: for that see the AWS IAM Roles Anywhere Security Guide and the Workload Identity Federation Guide.
Key takeaways
- Federation is configured per account: AWS states that an OIDC provider used in a role trust policy must be in the same account as the role, and Roles Anywhere trust anchors are account resources too, so the audit has to visit every account.
- The trust policy is where the risk lives: an OIDC provider or trust anchor on its own grants nothing; the roles that trust it decide who gets in, so audit roles and providers together.
- Check sub and aud on every OIDC role: AWS warns that if a GitHub role does not limit
token.actions.githubusercontent.com:sub, workflows from organisations outside your control can assume it, and recommends immutable IDs such asrepository_idover names. - Roles Anywhere needs certificate conditions: AWS strongly recommends
aws:SourceArn,aws:SourceAccountorsts:SourceIdentityconditions plus certificate attributes in the role trust policy. - Both mechanisms record last use:
ListSubjectsreturnslastSeenAtper certificate subject, andGetRolereturnsRoleLastUsed, so idle federation can be found from APIs before anyone is asked.
When you need this
- Periodic access review: federation trust is an NHI entitlement like any other. See the How to find unused AWS IAM roles and access keys guide for the role side.
- After migrating off access keys: teams that moved CI or on-premises servers to federation often leave test providers, broad trial roles and old anchors behind.
- CI platform or CA change: a retired CI provider or decommissioned issuing CA should take its provider, anchor and roles with it.
- Suspected trust tampering: adding a provider or anchor is a persistence route. MITRE ATT&CK lists it under T1484.002 Trust Modification, and adding roles under T1098.003 Additional Cloud Roles.
- Issuer key exposure: AWS states that a private key published in an OIDC provider's JWKS must be treated as compromised, and that you should review
AssumeRoleWithWebIdentityevents for the exposure period.
Before you start
- Access: a read-only audit role in every account with
iam:List*,iam:Get*(includingiam:GetAccountAuthorizationDetails) androlesanywhere:List*androlesanywhere:Get*, deployed through your organisation's account baseline. - Regions: IAM OIDC providers are global to the account; Roles Anywhere trust anchors, profiles and subjects are regional, so loop over every enabled Region.
- CloudTrail: an organisation trail or log archive you can query for
sts.amazonaws.com,iam.amazonaws.comandrolesanywhere.amazonaws.comevents. See the AWS CloudTrail Guide. - Owner data: the list of CI organisations, Kubernetes clusters and issuing CAs your company actually runs, so you can recognise a provider or anchor that does not belong.
- A findings register: one row per provider or anchor with account, Region, URL or CA, audiences, roles that trust it, conditions present, last use, owner and decision.
Step-by-step
1. Inventory IAM OIDC providers (read-only)
- In each account, run
aws iam list-open-id-connect-providers, thenaws iam get-open-id-connect-provider --open-id-connect-provider-arn ARNfor each one. - Record
Url,ClientIDList(audiences),ThumbprintList,CreateDateandTags. - Match each URL to a platform you own. Typical issuers include
token.actions.githubusercontent.com, GitLab, HCP Terraform (app.terraform.io), CircleCI and EKS cluster issuers. An EKS issuer for a cluster that no longer exists is a common leftover. - Check audiences: AWS states that the token's
audclaim must match an audience on the provider. An audience list padded with old client IDs widens what can be accepted. - Note that Google, Facebook and Amazon Cognito are built into AWS and do not appear as IAM OIDC providers, so search trust policies for those principals separately.
2. Map roles to each provider and check the conditions
Pull every role's trust policy in one call with aws iam get-account-authorization-details --filter Role, then select roles whose Principal.Federated is an OIDC provider ARN or a built-in provider, with action sts:AssumeRoleWithWebIdentity.
| Provider | What AWS documents | Audit finding if absent or loose |
|---|---|---|
| GitHub Actions | IAM checks on create or update that token.actions.githubusercontent.com:sub is present and not solely a wildcard or null; AWS recommends immutable claims such as repository_id, repository_owner_id and actor_id | A sub of repo:org/* trusts every repository and branch in the organisation; name-based conditions break if a name is freed and re-registered |
| HCP Terraform | Trust policy must evaluate app.terraform.io:sub; STS denies requests otherwise | Roles created before enforcement may still be too broad at workspace or project level |
| GitLab.com, Buildkite, CircleCI | Provider-specific keys, for example GitLab project_id and namespace_id, Buildkite organization_id and pipeline_id, CircleCI oidc.circleci.com/project-id; AWS recommends immutable IDs over slugs | Roles that check only aud trust every project on that provider's tenant for your audience |
Use accounts.google.com:aud, oaud and sub; google/organization_number can restrict to one organisation | A role trusting accounts.google.com with only aud trusts any Google identity for that client | |
| Amazon Cognito | Roles must contain at least one condition key to limit principals; cross-account roles use aud | Missing aud means a user from an unintended identity pool could assume the role |
| Any provider | Pair sub with aud; do not use email as the primary identifier | Trust policies keyed on email or on StringLike with leading wildcards |
For GitHub roles, check also whether you use job_workflow_ref or environment to pin access to approved workflows and protected environments. See the GitHub Actions OIDC Federation Hardening Guide and How to set up workload identity federation for GitHub Actions to AWS.
3. Inventory Roles Anywhere resources (read-only)
- In each account and Region, run
aws rolesanywhere list-trust-anchors. For each anchor recordname,enabled,source.sourceType(an AWS Private CA ARN or an uploaded certificate bundle),createdAt,updatedAtandnotificationSettings. - Run
aws rolesanywhere list-profiles. RecordroleArns,sessionPolicy,managedPolicyArns,durationSeconds,acceptRoleSessionName,attributeMappingsandenabled. - Run
aws rolesanywhere list-crlsand confirm every anchor whose CA revokes certificates has an enabled CRL. AWS states that revocation works only through imported CRLs, by API or CLI, and that callbacks to CRL distribution points or OCSP are not supported. - Run
aws rolesanywhere list-subjects. Each subject hasx509Subject,createdAt(first use) andlastSeenAt(last credential request).aws rolesanywhere get-subjectadds the certificates seen, with serial number, issuer,seenAtand whether the requestfailed.
4. Check Roles Anywhere trust policies
| Check | Why | Finding |
|---|---|---|
Trust policy names rolesanywhere.amazonaws.com with sts:AssumeRole, sts:TagSession, sts:SetSourceIdentity | Required for the service to assume the role | Inventory every role that trusts the service, in or out of a profile |
aws:SourceArn pinned to one trust anchor | AWS sets aws:SourceArn to the anchor used in CreateSession; without it any anchor in the account can be used | Missing or wildcard source condition |
Certificate attribute condition such as aws:PrincipalTag/x509Subject/CN | Maps one certificate identity to one role | Role accepts any certificate the CA issues |
| Profile session policy and managed policies | Cap what any session from the profile can do | Profile with no session policy on an administrative role |
durationSeconds and acceptRoleSessionName | Session lifetime and CloudTrail attribution | Long sessions without a reason; custom session names accepted without need |
| CRL present and recently updated | Revocation at the CA does nothing in AWS without it | Anchor with no CRL, or a CRL older than the CA's publication interval |
5. Find idle federation
- Roles:
aws iam get-rolereturnsRoleLastUsed.LastUsedDateandRegion. AWS notes the field is null if the role has not been used within the IAM tracking period. - OIDC providers: a provider is idle when no role trusting it has been used, and when CloudTrail shows no
AssumeRoleWithWebIdentityevents naming it for your idle period. - Roles Anywhere: subjects with an old
lastSeenAtshow certificates no longer authenticating; anchors whose subjects are all idle, and profiles whose roles are all unused, are candidates for removal. CloudTrail recordsCreateSessionunderrolesanywhere.amazonaws.com. - Repeated failures: subject certificates with
failedset, or bursts of failedAssumeRoleWithWebIdentity, show something still trying to use federation you thought was gone, or something probing it.
6. Remediate (destructive steps flagged)
- Tighten before deleting: add
sub, immutable ID,aws:SourceArnand certificate attribute conditions to roles in use. Test in a non-production account with the real workload. - Disable before deleting where AWS offers it:
aws rolesanywhere disable-profileanddisable-trust-anchorstop new sessions and can be reversed with the matching enable command. Watch for breakage over your notice period. - Destructive: remove unused roles first, then
aws iam delete-open-id-connect-providerfor providers no role trusts, anddelete-profile,delete-trust-anchoranddelete-crlfor Roles Anywhere resources. Record the configuration first so it can be recreated. - Remove stale audiences with
aws iam remove-client-id-from-open-id-connect-provider. - If a credential or issuer key may have been exposed, revoke active sessions for affected roles, as AWS describes for exposed JWKS keys, and import an updated CRL for revoked certificates.
Verify it worked
| Metric | Source | Target |
|---|---|---|
OIDC roles without a sub or provider-specific identity condition | Trust policy scan | Zero |
Roles Anywhere roles without aws:SourceArn and a certificate condition | Trust policy scan | Zero |
| Providers and anchors with no owner tag or no matching platform | Inventory joined with owner data | Zero |
| Idle providers, anchors and subjects beyond policy | RoleLastUsed, lastSeenAt, CloudTrail | Zero after each review |
| Federation changes outside change control | CloudTrail CreateOpenIDConnectProvider, AddClientIDToOpenIDConnectProvider, UpdateOpenIDConnectProviderThumbprint, CreateTrustAnchor, UpdateProfile, ImportCrl, UpdateAssumeRolePolicy | Every event matched to a ticket |
Rollback and common errors
- Deleting a provider that a role still trusts: the role's federated sign-ins stop. Recreate the provider with the recorded URL and audiences, and check the role trust policies still reference the same ARN.
- Replacing thumbprints by mistake: AWS notes that
UpdateOpenIDConnectProviderThumbprintreplaces the whole list rather than merging. AWS verifies most issuers through its trusted root CAs and falls back to thumbprints only in some cases, so record the old list before any change. - Adding a GitHub condition that IAM rejects: IAM refuses a trust policy where the GitHub
subis missing or only a wildcard. Write a specificsubor immutable ID condition rather than a placeholder. - Trusting null last use: a null
RoleLastUsedmeans no use inside the tracking period, not proof of no consumer. Confirm in CloudTrail and with the owning team. - Auditing one Region: Roles Anywhere resources are regional; an anchor in a Region nobody uses is exactly what an attacker would add.
- Forgetting the CA: removing an anchor while the external CA keeps issuing certificates leaves a path that reopens the moment anyone recreates the anchor. Retire the issuing template too.
Hardening afterwards
- Restrict who can create trust: AWS advises limiting
CreateOpenIDConnectProviderandUpdateOpenIDConnectProviderThumbprintto highly privileged users. Use SCPs to deny those actions and Roles Anywhere administration outside a pipeline role. See the AWS Organizations and SCPs Guide. - Alert on trust changes: stream the CloudTrail events in the verification table to your SIEM.
- Tag owners: tag every provider, anchor and profile with owner and platform, and treat untagged federation as a finding.
- Use certificate expiry notifications: trust anchors can send expiry events to EventBridge and AWS Health, which doubles as a liveness signal for anchors nobody watches.
- Repeat quarterly and on every platform change: retire the provider or anchor in the same change that retires a CI tenant, cluster or CA.
| Framework | Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.AA-01, PR.AA-05, DE.CM-09 | Service credentials managed; entitlements reviewed for least privilege; runtime monitored |
| NIST SP 800-53 Rev 5 | AC-2, AC-6, IA-5, IA-5(2), CM-8, AU-6 | Account review, least privilege, authenticator and PKI-based authentication management, inventory, audit review |
| CIS Controls v8.1 | Controls 5 and 6 | Account and access control management for service accounts |
| MITRE ATT&CK v20 | T1484.002 Trust Modification; T1098.003 Additional Cloud Roles; T1649 Steal or Forge Authentication Certificates; T1078.004 Cloud Accounts | Adding federation trust, widening roles, abusing certificates, and using cloud identities obtained through federation |
Practitioner checklist
- Deploy a read-only audit role to every account and loop over every Region for Roles Anywhere.
- Inventory OIDC providers with URL, audiences, thumbprints and tags, and match each to a platform you own.
- Map every role that trusts a provider or Roles Anywhere and record its conditions.
- Require
subplus immutable IDs on OIDC roles andaws:SourceArnplus a certificate attribute on Roles Anywhere roles. - Confirm every Roles Anywhere anchor that needs revocation has a current imported CRL.
- Use
RoleLastUsed,lastSeenAtand CloudTrail to find idle federation. - Disable, observe, then delete; record configuration before each deletion.
- Restrict federation administration with SCPs and alert on every trust change.
Standards and references
- AWS: Create an OpenID Connect (OIDC) identity provider in IAM
- AWS: Create a role for OpenID Connect federation
- AWS: IAM and AWS STS condition context keys
- AWS: IAM Roles Anywhere trust model
- AWS: IAM Roles Anywhere API Reference, ListSubjects
- AWS: IAM API Reference, GetOpenIDConnectProvider
- MITRE ATT&CK: T1484.002 Trust Modification
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
Related NHI Mgmt Group resources: AWS STS and AssumeRole Guide, Cloud Workload Identity Guide, Top 10 AWS IAM Mistakes, Identity Federation Failure Modes.