Safeguard
Developer Tools•

Can GitLab CI jobs reach the cloud without stored access keys?

Yes. GitLab ID tokens let a job prove who it is to a cloud provider with a short-lived JWT. Here is how the claims work and which ones to trust.

Safeguard Security Team
4 min read

Yes. A GitLab CI job can request an ID token, a signed JSON web token, and present it to a cloud provider that trusts GitLab as an identity provider. The provider checks claims such as project and branch, then issues short-lived credentials. No long-lived access key has to sit in a CI/CD variable.

What an ID token is

GitLab describes ID tokens as JSON web tokens generated by GitLab CI/CD, used to authenticate with third-party services such as secrets providers and cloud platforms. You declare one under the id_tokens keyword in a job. The token is signed with RS256, and it expires when the job's timeout is reached, or after 5 minutes if no timeout is set.

deploy:
  id_tokens:
    CLOUD_TOKEN:
      aud: https://cloud.example.internal
  script:
    - ./exchange-token-for-credentials.sh "$CLOUD_TOKEN"

The script name is a placeholder for whatever your provider's login step is.

The claims that matter

ClaimWhat it tells the providerTrust level
project_id, namespace_idWhich project and group ran the jobStable, preferred
ref_protectedWhether the Git ref is protectedUseful for production roles
environmentDeployment target, present only if the job names oneUseful
refThe branch or tagFine with other claims
user_login, user_emailThe person who triggered itDo not rely on alone

GitLab's own guidance is to use project_id and namespace_id in trust policies because renames do not change them, and not to rely on user_login or user_email as the sole condition because a user can change them.

Steps to adopt it

  1. Register GitLab as an OpenID Connect identity provider in your cloud account.
  2. Create a role that trusts that provider, and write the trust policy on project_id or namespace_id, plus ref_protected for production.
  3. Give each service its own aud value. The docs note that a different audience per service limits how far a stolen token travels.
  4. Add the id_tokens block to the deploy job only, not the whole pipeline.
  5. Delete the old stored key from CI/CD variables, then rotate it at the cloud side.

Gotchas

The older CI_JOB_JWT_V2 variable is deprecated and can cause 401 errors, so move to id_tokens. GitLab also blocks issuing a token when a sub path was previously used by a different project, so an old trust policy cannot be inherited by a renamed or recreated project. Extra claims as cloud condition keys are described as available on GitLab.com, while self-managed instances may be limited to sub, so check your own setup before relying on them.

A token is still a credential for its short life. Anyone who can change the job script can print it. Pair this with protected branches and protected environments so that only reviewed code runs in the job that asks for one. The same pattern on another platform is covered in GitHub Actions OIDC instead of long-lived cloud secrets.

Safeguard's policies, gates and guardrails can add automated checks to changes that touch pipeline configuration. You can try a free scan at https://gold.safeguard.sh/scan.

Quick check

Is an ID token safer than a stored key?

Usually, because it expires in minutes and is bound to a project and ref. It does not remove the need to control who can edit the job.

Which claim should a production role check?

Check a stable project identifier and ref_protected, so only jobs on protected refs can assume it.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.