"category": "CI/CD federation" · job/github-oidc-trust-aws

One workflow, three clouds: how AWS, Azure and Google Cloud match GitHub OIDC tokens

The same GitHub Actions token is checked three different ways. A side-by-side comparison of where the trust lives, how claims are matched, wildcard support, limits and how failures show up.

published updated 7 min readby Cloud Identity Security

payload.takeaways# checked against sources November 10, 2026
  • AWS evaluates IAM conditions with wildcards; Entra matches exact strings; Google evaluates a CEL expression and then IAM bindings.
  • Entra allows 20 credentials per app or identity and no wildcards, so per-branch trust adds up quickly.
  • All three providers' docs now point to numeric repository and owner IDs over names.
  • A wrong Entra subject is saved without error; you only find out when the token exchange fails.

A GitHub Actions job can deploy to AWS, Azure and Google Cloud with the same kind of OIDC token. The audience changes per cloud; the rest of the claims describe the same job. What each cloud does with the other claims is quite different, and those differences decide how tight your trust can be and how you notice when it breaks.

Side by side

AWS Microsoft Entra (Azure) Google Cloud
Where trust lives IAM role trust policy Federated identity credential on an app registration or user-assigned managed identity Workload identity pool provider (attribute condition) + IAM bindings
Matching model IAM condition operators on claim keys Exact match on issuer, subject and audience; or a claims-matching expression (flexible credential) CEL expression over assertion.*, then principal or principalSet bindings
Wildcards Yes, with StringLike (*, ?) No, in any credential property[Microsoft Learn] No wildcard syntax; you write CEL comparisons
Audience sts.amazonaws.com in GitHub’s and AWS’s examples api://AzureADTokenExchange recommended[Microsoft Learn] Not covered in the sources used here
Required restriction sub or job_workflow_ref condition, enforced on create/update[AWS IAM User Guide] Flexible credentials for GitHub must match sub plus repository_id and/or repository_owner_id[Microsoft Learn] Attribute condition restricting the GitHub organization[Google Cloud documentation]
ID-based matching repository_id, repository_owner_id, actor_id condition keys[AWS IAM User Guide] Immutable sub, or ID claims in an expression assertion.repository_id, assertion.repository_owner_id
Count limit Not covered in the sources used here 20 credentials per app or identity[Microsoft Learn] Not covered in the sources used here
How a bad config shows up Create/update fails if sub is missing; otherwise STS refuses at sign-in Credential is saved even with a wrong subject; the exchange fails later[Microsoft Learn] Exchange fails if the condition is false

AWS: conditions on claim keys

Every GitHub claim AWS supports becomes a condition key such as token.actions.githubusercontent.com:repository_id. You combine them with operators: StringEquals for exact values, StringLike for patterns. Multiple keys in a block must all match; multiple values for one key are alternatives. This makes “repository X, environment Y, owner ID Z” a single statement. See the AWS scoping guide.

Microsoft Entra: one credential per subject

A plain credential is three strings: issuer, subject, audience. The token must match all three exactly, and Microsoft says pattern matching is not supported for branches and tags.[Microsoft Learn] One repository with main, a release tag pattern and two environments therefore needs several credentials, and the cap of 20 per app or identity applies.

Microsoft’s docs also note that an incorrect subject is accepted when you create the credential, and the problem only appears when the token exchange fails.[Microsoft Learn] Test the workflow after every change.

Flexible credentials replace the exact subject with an expression such as claims['sub'] matches 'repo:octo-org@123456/octo-repo@456789:*' and claims['repository_id'] eq '456789'.[Microsoft Learn]

Google Cloud: a condition, then a binding

Google splits the decision in two. The provider’s attribute condition decides whether a token is accepted at all. Google says it is required for GitHub and must restrict tokens to your organization.[Google Cloud documentation] Its examples:

assertion.repository_owner == 'ORGANIZATION'
assertion.repository_owner == 'ORGANIZATION' && assertion.ref == 'refs/heads/main'

The same page warns that name fields like repository_owner invite squatting and recommends the numeric *_id claims instead.[Google Cloud documentation] After the condition passes, the token’s identity still needs an IAM grant, either directly on resources or through service account impersonation. A narrow condition with a broad binding, or the reverse, can both leave gaps, so review them together.

What carries over between clouds?

  • Pin the owner and repository by numeric ID.
  • Name the job context (branch, environment or reusable workflow) instead of trusting the whole repository.
  • Check the audience.
  • Keep pull request jobs away from deploy permissions.

The OIDC trust checker evaluates all three formats against the same token, which is useful when one workflow signs in to more than one cloud.

Questions people ask

Which cloud is easiest to scope tightly?
That is a judgment call. AWS and Google can express 'this repository, this environment' in one rule using IDs. Entra needs a credential per subject unless you use a flexible credential with an expression.
Do I need a separate GitHub token per cloud?
Yes, one per sign-in. The audience claim must match what each cloud expects, so each sign-in step requests its own token. The other claims describe the same job.

Sources

  1. Create a role for OpenID Connect federation (console) — AWS IAM User Guide.# official documentation · checked November 10, 2026 (full page text)
  2. IAM and AWS STS condition context keys — available keys for AWS OIDC federation — AWS IAM User Guide.# official documentation · checked November 10, 2026 (first 100,000 characters of the page (the GitHub and default OIDC sections were inside that range))
  3. Create a trust relationship between an app and an external identity provider — Microsoft Learn.# official documentation · checked November 10, 2026 (full page text)
  4. Migrate GitHub Actions federated credentials to immutable subjects — Microsoft Learn.# official documentation · checked November 10, 2026 (full page text (page dated 2026-07-28))
  5. Configure Workload Identity Federation with deployment pipelines — Google Cloud documentation.# official documentation · checked November 10, 2026 (full page text)
  6. OpenID Connect reference — GitHub Docs.# official documentation (issuer) · checked November 10, 2026 (full page text)

Update history

  • — First published.
4 jobs
  1. job/github-oidc-immutable-subject category CI/CD federation

    GitHub's immutable OIDC subject claims, fixed in AWS, Azure and Google Cloud

    Repositories created after July 15, 2026 send a new sub format with owner and repository IDs. What changed, how to tell which format you get, and the trust changes for each cloud.

    · 8 min
  2. job/github-actions-aws-oidc category CI/CD federation

    Scoping a GitHub Actions trust policy in AWS

    Which condition keys to use in an IAM role trust policy for GitHub Actions, which ones are immutable, and worked examples for a branch, an environment and a reusable workflow.

    · 8 min
  3. job/gitlab-ci-oidc-trust category CI/CD federation

    Scoping GitLab CI OIDC trust in AWS, Azure and Google Cloud

    How GitLab ID tokens are matched by each cloud, which claims stay stable when a project moves, and worked trust configurations for a protected branch on GitLab.com.

    · 7 min
  4. job/hcp-terraform-dynamic-credentials category CI/CD federation

    Scoping HCP Terraform dynamic credentials: trust for plan and apply

    How HCP Terraform workload identity tokens are built, why plan and apply deserve different roles, and the trust configuration each cloud needs.

    · 7 min