"category": "CI/CD federation" · job/gitlab-ci-oidc-trust

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.

published updated 7 min readby Cloud Identity Security

payload.takeaways# checked against sources November 10, 2026
  • GitLab.com signs every customer's ID tokens with one issuer, so the sub claim is what keeps other groups out.
  • The default sub is built from paths; project_id and namespace_id are the stable identifiers.
  • On AWS, gitlab.com:namespace_id and gitlab.com:project_id work as condition keys only for the gitlab.com provider.
  • Pick one audience value and use it in the job's id_tokens block and in the cloud's trust record.

A GitLab CI job asks for an OIDC token with the id_tokens keyword, then trades that token for cloud credentials. GitLab.com uses one issuer, https://gitlab.com, for every customer, so the cloud can only tell your jobs apart from anyone else’s by reading the token’s claims. AWS lists GitLab among the shared providers whose trust policies must check gitlab.com:sub.[AWS IAM User Guide]

What does a GitLab ID token contain?

The default subject is built from the project path and the ref:[GitLab Docs]

project_path:mygroup/myproject:ref_type:branch:ref:main

Alongside it, the token carries project_id, project_path, namespace_id, namespace_path, ref, ref_type, ref_protected and, when the job names one, environment. GitLab’s docs describe project_id as globally unique for the life of the project and namespace_id as stable while the project stays in its namespace. Paths change when a group or project is renamed or moved.[GitLab Docs]

A project can change the subject format with the ci_id_token_sub_claim_components setting. When it starts with project_id, the subject looks like project_id:67890:ref_type:branch:ref:main.[GitLab Docs] Every trust record for that project then has to use the new form.

The job requests the token and sets its audience:

deploy:
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: sts.amazonaws.com

AWS: sub plus the ID keys

GitLab’s own example trust policy for GitLab.com pins three things: the subject, the group ID and the project ID.[GitLab Docs]

"Condition": {
  "StringEquals": {
    "gitlab.com:aud": "sts.amazonaws.com",
    "gitlab.com:sub": "project_path:mygroup/myproject:ref_type:branch:ref:main",
    "gitlab.com:namespace_id": "12345",
    "gitlab.com:project_id": "67890"
  }
}

GitLab’s example leaves out aud; the version above adds it. GitLab says the audience is often sts.amazonaws.com or your GitLab URL, that it must match the IAM OIDC provider’s configuration, and that using the GitLab URL “might work” but is semantically misleading.[GitLab Docs]

GitLab’s troubleshooting section calls out StringEquals used with a wildcard. It never matches; use StringLike for patterns.[GitLab Docs]

Microsoft Entra: one credential per ref

GitLab’s Azure guide uses the GitLab URL as both the issuer and the audience:[GitLab Docs]

{
  "name": "myproject-main",
  "issuer": "https://gitlab.com",
  "subject": "project_path:mygroup/myproject:ref_type:branch:ref:main",
  "audiences": ["https://gitlab.com"]
}

The job’s id_tokens block must then request aud: https://gitlab.com. Entra matches the subject exactly, allows no wildcards and holds at most 20 credentials per app or user-assigned managed identity,[Microsoft Learn] so each branch or tag that deploys needs its own credential.

Google Cloud: a condition on the group

Google requires an attribute condition for GitLab.com providers that restricts tokens to your group:[Google Cloud documentation]

assertion.namespace_id == '12345'

Its example optionally adds && assertion.environment == 'production'. Because the condition reads IDs, it keeps working through renames and doesn’t depend on the subject format. Narrow it further to the project and ref if the IAM binding doesn’t:

assertion.namespace_id == '12345' &&
assertion.project_id == '67890' &&
assertion.ref == 'main'

Checklist

  • The trust record names your group and project, never project_path:* or a whole group with *.
  • On GitLab.com AWS roles, gitlab.com:namespace_id and gitlab.com:project_id are checked.
  • The audience in id_tokens matches the cloud side.
  • Deploy roles trust protected branches or tags only.
  • Trust records are removed when a project is archived, renamed or moved.

Test a policy with the GitLab preset in the OIDC trust checker. For why path-based trust is risky after a project is renamed or deleted, see subject recycling.

Questions people ask

Does this apply to GitLab Self-Managed?
The token format is the same, but the issuer is your instance URL. GitLab says that for Self-Managed and Dedicated, only sub and aud are supported as AWS condition keys, so scope AWS trust with sub.
What happened to CI_JOB_JWT_V2?
GitLab removed it in GitLab 17.0. Jobs request tokens through the id_tokens keyword instead.
What does GitLab do if a project path is reused?
If a project path in sub was previously used by a different project, GitLab blocks ID token issuance for the new project. The fix GitLab gives is to start sub with an ID component and update trust policies to match.

Sources

  1. OpenID Connect (OIDC) authentication using ID tokens — GitLab Docs.# official documentation (issuer) · checked November 10, 2026 (full page text)
  2. Configure OpenID Connect in AWS to retrieve temporary credentials — GitLab Docs.# official documentation (issuer) · checked November 10, 2026 (full page text)
  3. Configure OpenID Connect in Azure to retrieve temporary credentials — GitLab Docs.# official documentation (issuer) · checked November 10, 2026 (full page text)
  4. Identity-provider controls for shared OIDC providers — AWS IAM User Guide.# official documentation · checked November 10, 2026 (full page text)
  5. Configure Workload Identity Federation with deployment pipelines — Google Cloud documentation.# official documentation · checked November 10, 2026 (full page text)
  6. Create a trust relationship between an app and an external identity provider — Microsoft Learn.# official documentation · checked November 10, 2026 (full page text)

Update history

  • — First published.
3 jobs
  1. job/github-oidc-trust-aws category CI/CD federation

    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.

    · 7 min
  2. job/oidc-subject-recycling category Risks

    Subject recycling: when a deleted GitHub name still unlocks your cloud role

    Trust rules that match names can be satisfied by whoever registers that name next. What the 2026 research found, what GitHub, GitLab and the clouds changed, and how to audit your own roles.

    · 7 min
  3. 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