Plainwork

Plainwork / CI OIDC Atlas / GitLab CI id_tokens: sub claim and AWS trust policy

GitLab CI id_tokens for AWS and Azure: the sub claim and the trust policy that matches it

GitLab CI/CD does not hand a job an OIDC token by default. You ask for one with the id_tokens keyword, and what your AWS role, Azure federated credential or Google Cloud pool sees is whatever the sub and aud in that token say. This page lists what GitLab's documentation (read on 13 Oct 2026) says the token contains, the one trap that breaks merge request pipelines, and how to write a trust policy that matches.

What GitLab puts in the token

FieldDefaultCan you change it?
Issuer (iss)The domain of the GitLab instance: https://gitlab.com on GitLab.com, your own domain on self-managedNo
Audience (aud)The domain of the GitLab instanceYes: set aud per token under id_tokens in the job
Subject (sub)project_path:{group}/{project}:ref_type:{type}:ref:{branch_name}Yes: configurable per project through the projects API
LifetimeThe job's timeout if one is set, otherwise 5 minutesThrough the job timeout
SigningRS256, keys at https://gitlab.com/oauth/discovery/keysNo

Example subject from GitLab's page: project_path:my-group/my-project:ref_type:branch:ref:feature-branch-1. For GitLab 18.7 and later the docs add that the sub "can include additional fields such as ref_protected" and, for jobs with an environment, environment_protected and deployment_tier. If your instance is on 18.7 or later, print a real token before you write the policy, because a pattern written from the older example may stop at the first extra field.

Asking for a token

Add id_tokens to the job, name the variable, and set the audience your cloud expects. The names below are ours, not GitLab's:

deploy:
  id_tokens:
    CLOUD_TOKEN:
      aud: sts.amazonaws.com
  script:
    - echo "use $CLOUD_TOKEN with your cloud's token exchange"

Do not print the token in a shared log. It is short lived, but it is a bearer credential while it is valid. For debugging, copy one into the OIDC token debugger, which decodes it in your browser and sends nothing anywhere.

The AWS trust policy

With the GitLab.com issuer registered as an IAM OIDC provider, a role that only the main branch of one project may assume looks like this (our example; replace the group and project, and make the audience equal the one in the job):

"Condition": {
  "StringEquals": {
    "gitlab.com:aud": "sts.amazonaws.com",
    "gitlab.com:sub": "project_path:my-group/my-project:ref_type:branch:ref:main"
  }
}

AWS documents StringEquals as "Exact matching, case sensitive", and StringLike as case-sensitive matching where the value "can include multi-character match wildcards (*) and single-character match wildcards (?) anywhere in the string". To allow every branch of the project, use StringLike with project_path:my-group/my-project:ref_type:branch:ref:*. Never use a bare * for the project part: every project on the same GitLab would match.

Trap 1: merge request pipelines have a different project and ref

GitLab's claim table says that in a merge request pipeline project_path is "the path of the source project". So a policy pinned to ref_type:branch:ref:main in the target project does not match a job running in an MR pipeline, whose subject describes the source project and source branch. If MR pipelines need cloud access, decide deliberately which source branches may have it; do not widen the pattern to * to make the error go away.

Trap 2: self-managed GitLab has only sub on AWS

GitLab's page says claims such as namespace_id and project_id are not available as AWS condition keys "for GitLab Self-Managed or GitLab Dedicated, where only the sub claim is supported as an AWS condition key". If you copied a tutorial that conditions on gitlab.com:project_id, it works on GitLab.com and not on your own instance. Put the project into the sub condition instead.

Azure and Google Cloud

  • Microsoft Entra. A standard federated credential compares issuer, subject and audience exactly and case-sensitively, and "wildcard characters aren't supported in any federated identity credential property value". Create one credential per subject, or use a flexible federated identity credential (a preview feature), which Microsoft says supports GitLab-issued tokens and lets one credential match many branches with an expression. The subject field is limited to 600 characters, which matters if you customise the sub. The recommended audience is api://AzureADTokenExchange, so set the job's aud to that.
  • Google Cloud. Map google.subject to a claim that is unique and cannot change; Google limits mapped attributes to 127 bytes, so a long custom sub can be too big to map.

Check a policy before you deploy

Paste the token and the sub from your trust policy into the debugger. It names GitLab from iss, splits the subject into its parts, and reports the first character where your pattern and the token differ. If the job already fails, work through the six-step checklist for "Not authorized to perform sts:AssumeRoleWithWebIdentity". The free MIT token decoder does the matching offline, and the CI OIDC Atlas ($12) puts GitLab next to ten other CI platforms with the vendor sentence behind every cell, for teams that run more than one.

Sources read 13 Oct 2026: GitLab Docs, "Use ID tokens to authenticate with third-party services"; AWS IAM documentation, condition operators; Microsoft Entra documentation on federated credentials and flexible federated identity credentials; Google Cloud, workload identity federation with other providers. Formats change between GitLab versions; re-read the current page before relying on a detail.

More from the catalogue

Other small tools

See everything →