Start Building for Free
CircleCI.comAcademyBlogCommunitySupport

Using OpenID Connect tokens in jobs

1 month ago9 min read
Cloud
Server v4.4+
On This Page

CircleCI provides OpenID Connect ID (OIDC) tokens in environment variables. A job can be configured to use these tokens to access compatible cloud services without long-lived credentials being stored in CircleCI.

OpenID Connect ID token availability

CircleCI OpenID Connect ID tokens are available in the following environment variables:

Setting up your cloud service

Refer to the documentation for your target cloud service for steps to add an identity provider. For example, AWS’s Creating OpenID Connect (OIDC) identity providers, or Google Cloud Platform’s Configuring workload identity federation.

The OpenID Provider is unique to your organization. The URL is https://oidc.circleci.com/org/<organization_id>, where organization_id is the organization ID (a universally unique identifier) that represents your organization. You can find your CircleCI organization ID by navigating to Organization Settings > Overview in the CircleCI web app.

The default OpenID Connect ID tokens issued by CircleCI have a fixed audience (see aud in the table below), which is also the organization ID. To generate tokens with custom audience claims, see the OIDC tokens with custom claims page.

Format of the OpenID Connect ID token

The OIDC tokens contain the following standard claims:

ClaimsDescription

iss

The issuer. The issuer is specific to the CircleCI organization in which the job is being run. Its value is "https://oidc.circleci.com/org/<organization_id>", a string, where organization_id is a UUID identifying the current job’s project’s organization.

sub

The subject. This identifies who is running the CircleCI job and where. $CIRCLE_OIDC_TOKEN_V2 also includes information about the source of change.

For $CIRCLE_OIDC_TOKEN its value is: "org/<organization_id>/project/<project_id>/user/<user_id>", a string, where organization_id, project_id, and user_id are UUIDs that identify the CircleCI organization, project, and user, respectively. The user is the CircleCI user that caused this job to run.

For $CIRCLE_OIDC_TOKEN_V2 its value depends on the trigger:

  • If the trigger is an inbound webhook then: "org/<organization_id>/project/<project_id>/user/<user_id>/vcs-origin/<vcs_origin>/vcs-ref/<vcs_ref>", a string, where organization_id, project_id, and user_id are UUIDs that identify the CircleCI organization, project, and user, respectively. The user is the CircleCI user that caused this job to run.

  • Otherwise it will be: "org/<organization_id>/project/<project_id>/user/<user_id>/vcs-origin/<vcs_origin>/vcs-ref/<vcs_ref>", a string, where organization_id, project_id, and user_id are UUIDs that identify the CircleCI organization, project, and user, respectively. The user is the CircleCI user that caused this job to run. vcs_origin and vcs_ref are strings that identify the repo URL and reference to the change that caused the job to run.

aud

The audience. Currently, this is a fixed value "ORGANIZATION_ID", a string containing a UUID that identifies the job’s project’s organization.

iat

The time of issuance. This is the time the token was created, which is shortly before the job starts.

exp

The expiration time. Its value is one hour after the time of issuance.

The OpenID Connect ID tokens also contain some additional claims with extra metadata about the job:

Additional claimsMetadata

oidc.circleci.com/project-id

The ID of the project in which the job is running. Its value is a string containing a UUID identifying the CircleCI project.

oidc.circleci.com/vcs-origin

The URL of the repo that triggered the pipeline. Its value is a string similar to github.com/organization-123/repo-1. This is not present for pipelines triggered by inbound webhooks.

oidc.circleci.com/vcs-ref

The reference to the change that triggered the pipeline. Its value is a string similar to refs/heads/main. This is not present for pipelines triggered by inbound webhooks.

oidc.circleci.com/context-ids

An array of strings containing UUIDs that identify the context(s) used in the job. Currently, just one context is supported.

oidc.circleci.com/ssh-rerun

A boolean indicating if the CI job is started using the SSH rerun feature.

OIDC in open source projects

OIDC tokens will only be generated for forked builds if the Pass secrets to builds from forked pull requests setting is enabled. Find this option at Project settings > Advanced.

If you do allow OIDC tokens to be generated for forks, you must check the oidc.circleci.com/vcs-origin claims in your policies to avoid forked builds having access to resources outside those that you require.

For more information about building open source projects on CircleCI, see the Build open source projects page.

OIDC on CircleCI server

OIDC is supported from server v4.4+. However, OIDC is not supported if your server installation is in an air-gapped environment.

Authenticate jobs with cloud providers

The following sections describe how to authenticate CircleCI jobs with Amazon Web Services (AWS) and Google Cloud Platform (GCP).

AWS

The following AWS instructions cover the following:

  • A one-time configuration of your AWS account to trust CircleCI’s OIDC tokens

  • Running a job that uses the OIDC token to interact with AWS

Also see the Pull an image from AWS ECR with OIDC how-to guide, which follows on from this setup section.

Set up AWS

You will need to allow your AWS account to trust CircleCI’s OpenID Connect tokens. To do this, create an Identity and Access Management (IAM) identity provider, and an IAM role in AWS. Creating the identity provider is a one-time configuration to get set up, and then you can decide how to manage the associated role(s). You can update the role permissions, using policies, to fit your use cases, or you can create roles specific to each use.

  1. Visit the Creating OpenID Connect (OIDC) identity providers page of the AWS docs and follow the instructions. There are multiple setup options covered on this page, including using the management console, or CLI. You will need to provide the following:

    • Provider URL: Enter https://oidc.circleci.com/org/<your-organization-id>, where your-organization-id is the ID of your CircleCI organization.

    • Audience: Enter your organization ID

  2. Once your have created your identity provider, a banner will appear at the top of the ADW console with the options to Assign role. Click this button to create a new role, or visit the Creating a role for web identity or OIDC section of the AWS docs and follow the steps there. You will need to select the following:

    • The Identity Provider that you just created.

    • For Audience, choose the only option, which is your organization ID that you entered earlier.

    • On the Add Permissions page you can specify what your CircleCI jobs can and cannot do. Choose only permissions that your job will need. This is an AWS best practice. You can also write your own policies to lock down permissions to exactly what you need for a specific use case.

Adding AWS to the CircleCI configuration file

Now that you have set up your trusted identity provider and IAM role, you are ready to write a CircleCI job that authenticates with AWS using OIDC. This is accomplished using CircleCI’s AWS CLI orb to generate temporary keys and configure a profile that uses OIDC.

  1. In your .circleci/config, import the aws-cli orb.

    version: 2.1
    
    orbs:
      aws-cli: circleci/aws-cli@3.1.5
  2. Configure your job to run the aws-cli/setup command before interacting with any AWS services. You will need to provide the aws-cli/setup command with the role-arn associated with the role you have created in the step above along with your aws-region.

    jobs:
      aws-example:
        environment:
          AWS_REGION: us-west-1
        docker:
          - image: cimg/aws:2023.06
        steps:
          - checkout
          # run the aws-cli/setup command from the orb
          - aws-cli/setup:
              role-arn: "arn:aws:iam::123456789012:role/OIDC-ROLE"
              aws-region: ${AWS_REGION}
              # optional parameters
              profile-name: "OIDC-PROFILE"
              role-session-name: "example-session"
              session-duration: "1800"

    You can optionally provide a profile-name, role-session-name, and session-duration. If you provide a profile-name, the temporary keys and token will be configured to that specific profile. You must use that same profile-name with the rest of your AWS commands. If a profile-name is not provided, the keys and token will be configured to the default profile.

    Additionally, if you do not provide a role-session-name or session-duration, their default values are ${CIRCLE_JOB} (your job’s name) and 3600 seconds respectively.

Below is an example of a complete configuration with a job that configures a profile with OIDC and uses it to log into AWS ECR. The same profile can be used to run other AWS commands, such as S3, EKS, ECS, and more, as long as the role-arn has been configured with appropriate permissions.

version: 2.1

orbs:
  aws-cli: circleci/aws-cli@3.1.5

jobs:
  aws-example:
   environment:
      AWS_REGION: us-west-1
    docker:
      - image: cimg/aws:2022.06
    steps:
      - checkout
      # run the aws-cli/setup command from the orb
      - aws-cli/setup:
          role-arn: "arn:aws:iam::123456789012:role/OIDC-ROLE"
          aws-region: AWS_REGION
          # optional parameters
          profile-name: "OIDC-PROFILE"
          role-session-name: "example-session"
          session-duration: "1800"
      - run:
        name: Log-into-AWS-ECR
        command: |
          # must use same profile specified in the step above
          aws ecr get-login-password --profile "OIDC-PROFILE"
workflows:
  OIDC-with-AWS:
    jobs:
      - aws-example:
          context: aws

Advanced usage

You can take advantage of the format of the claims in CircleCI’s OIDC token to limit what your CircleCI jobs can do in AWS.

Limit role access based on project

If certain projects should only be able to access certain AWS resources, you can restrict your IAM role so that only CircleCI jobs in a specific project can assume that role.

To do this, edit your IAM role’s trust policy so that only an OIDC token from your chosen project can assume that role. The trust policy determines under what conditions the role can be assumed.

  1. Go to an individual project’s page in the CircleCI web app and navigate to Project Settings > Overview to find your Project ID.

  2. Add the following condition to your role’s trust policy, so that only jobs in your chosen project can assume that role. Enter your Organization ID for organization_id and your Project ID for project_id.

    "StringLike": {
      "oidc.circleci.com/org/<organization_id>:sub": "org/<organization_id>/project/<project_id>/user/*"
    }

    This uses StringLike to match the sub claim of CircleCI’s OIDC token in your chosen project. Now, jobs in your other projects cannot assume this role.

Limit role access based on branch

You can also restrict access to specific branches. The following is an example of a trust policy that restricts the AssumeRoleWithWebIdentity action to any project pipelines running only on the main branch in the my-org GitHub organization and the CircleCI organization with the ID: organization_id. Note that the sub claim uses the $CIRCLE_OIDC_TOKEN_V2 format.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.circleci.com/org/<organization_id>"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "oidc.circleci.com/org/<organization_id>:sub": "org/<organization_id>/project/*/user/*/vcs-origin/github.com/my-org/*/vcs-ref/refs/heads/main"
                }
            }
        }
    ]
}

Google Cloud Platform

The following GCP instructions are for:

  • A one-time configuration of your GCP settings to trust CircleCI’s OIDC tokens

  • Running a job that uses the OIDC token to interact with GCP

The Google Cloud CLI reads your configuration file, which contains necessary information instructing Google Cloud to authenticate. You can read about external identity providers on Google Cloud’s docs.

Setting up GCP

The GCP configuration file can be set up using the GCP web UI. In the Workload Identity Federation UI, navigate to Grant Access, which will prompt the configuration, which can then be downloaded. You will need to create a file named CIRCLE_OIDC_TOKEN_FILE, which Google Cloud will read your identity token from (the file name can be anything, as long as it matches what is in the configuration under credential_source).

You will need your CircleCI organization ID, which can be found by navigating to Organization Settings > Overview on the CircleCI web app.

After navigating to the Grant Access section of the GCP web UI, follow these steps to add CircleCI as an external identity provider:

  1. Navigate to the IAM & Admin panel.

  2. On the side panel, navigate to Workload Identity Federation.

  3. Click the Add Provider button.

  4. Select OpenID Connect (OIDC) from the "Select a provider" dropdown and click Save.

  5. Fill out the Provider details form.

    • Select Allowed audiences since the aud claim in the JSON Web Token is a UUID (your CircleCI organization ID). The audience will be your CircleCI organization ID.

    • The issuer is https://oidc.circleci.com/org/<organization_id>, where organization_id is your CircleCI organization ID.

  6. Click Continue to configure provider attributes.

    Configuring the provider attributes provides an opportunity to map claims in CircleCI’s Token to Google’s "understanding". Use this mapping:

    google.subject

    assertion.sub

    attribute.org_id

    assertion.aud

    attribute.project

    assertion['oidc.circleci.com/project-id']

  7. Navigate to Service Account in the IAM & Admin Panel to create a service account, and give appropriate permission.

  8. Navigate back to Workload Identity Federation and select the provider from the table.

  9. Click the Grant access button.

  10. A modal will open and you will select the service account you created from the dropdown. This is the account that the token will impersonate, which grants all the associated permissions.

  11. Under Select principals, you can add conditions, or leave the default.

  12. Click Save. A pop-up will appear to ask you configure and download the configuration file. This file can also be downloaded later by navigating to Connected Service Accounts.

  13. Save the downloaded configuration file in your repository. This file will be referenced in your CircleCI configuration.

An example of the configuration file is shown below. Note, the audience has not been set up yet with the following:

  • project_number (the unique identifying number generated for your project)

  • pool_id (an ID that references the workload identity pool, for example circleci_oidc)

  • provider_id (an ID that references the workload identity pool provider, for example, circleci)

 {
  "type": "external_account",
  "audience": "//iam.googleapis.com/projects/<project_number>/locations/global/workloadIdentityPools/<pool_id>/providers/<provider_id>",
  "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
  "token_url": "https://sts.googleapis.com/v1/token",
  "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/circleci-test@incubator-344312.iam.gserviceaccount.com:generateAccessToken",
  "credential_source": {
    "file": "CIRCLE_OIDC_TOKEN_FILE",
    "format": {
      "type": "text"
    }
  }
}

In this configuration, credential_source will attempt to find your identity token in the CIRCLE_OIDC_TOKEN_FILE, as noted in the ( token availability section).

If your token comes from an API response, it might be useful to set up the configuration to read a JSON file. In this case, the type will need to be set to json and you will need to provide a valid path, for example, response.id_token.

  "credential_source": {
    "file": "CIRCLE_OIDC_TOKEN_FILE",
    "format": {
      "type": "json",
      "path": "response.id_token"
    }
  }
gcloud iam workload-identity-pools create-cred-config \
  "${GCP_WORKLOAD_IDENTITY_POOL_AUDIENCE}" \
  --output-file="${GCP_CREDENTIAL_CONFIGURATION_FILE}" \
  --service-account="${GCP_SERVICE_ACCOUNT_EMAIL}" \
  --credential-source-file="${GCP_CREDENTIAL_SOURCE_FILE}"

Adding GCP to the CircleCI configuration file

You will need to export the $CIRCLE_OIDC_TOKEN to the file named CIRCLE_OIDC_TOKEN_FILE by running the following:

echo $CIRCLE_OIDC_TOKEN >> CIRCLE_OIDC_TOKEN_FILE

You will also need to add the following environment variables to a context.

Context var name

Example value

Notes

GCP_PROJECT_ID

123456789012

GCP project number

GCP_WIP_ID

myworkloadpoolid

Workload identity pool ID

GCP_WIP_PROVIDER_ID

myproviderid

Workload identity pool provider name

GCP_SERVICE_ACCOUNT_EMAIL

myserviceacct@myproject.iam.gserviceaccount.com

User-managed Service Accounts

Below is a full example configuration adding GCP to a job and demonstrating that authentication works with the gcp-oidc-authenticate command. This example uses the circleci/gcp-cli orb. Note that you can enable the use of OIDC token when using circleci/gcp-cli orb version 3.0.0 or later.

version: 2.1

orbs:
  gcp-cli: circleci/gcp-cli@2.4.1

commands:
  gcp-oidc-generate-cred-config-file:
    description: "Authenticate with GCP using a CircleCI OIDC token."
    parameters:
      project_id:
        type: env_var_name
        default: GCP_PROJECT_ID
      workload_identity_pool_id:
        type: env_var_name
        default: GCP_WIP_ID
      workload_identity_pool_provider_id:
        type: env_var_name
        default: GCP_WIP_PROVIDER_ID
      service_account_email:
        type: env_var_name
        default: GCP_SERVICE_ACCOUNT_EMAIL
      gcp_cred_config_file_path:
        type: string
        default: /home/circleci/gcp_cred_config.json
      oidc_token_file_path:
        type: string
        default: /home/circleci/oidc_token.json
    steps:
      - run:
          command: |
            # Store OIDC token in temp file
            echo $CIRCLE_OIDC_TOKEN > << parameters.oidc_token_file_path >>
            # Create a credential configuration for the generated OIDC ID Token
            gcloud iam workload-identity-pools create-cred-config \
                "projects/${<< parameters.project_id >>}/locations/global/workloadIdentityPools/${<< parameters.workload_identity_pool_id >>}/providers/${<< parameters.workload_identity_pool_provider_id >>}"\
                --output-file="<< parameters.gcp_cred_config_file_path >>" \
                --service-account="${<< parameters.service_account_email >>}" \
                --credential-source-file=<< parameters.oidc_token_file_path >>

  gcp-oidc-authenticate:
    description: "Authenticate with GCP using a GCP credentials file."
    parameters:
      gcp_cred_config_file_path:
        type: string
        default: /home/circleci/gcp_cred_config.json
    steps:
      - run:
          command: |
            # Configure gcloud to leverage the generated credential configuration
            gcloud auth login --brief --cred-file "<< parameters.gcp_cred_config_file_path >>"
            # Configure ADC
            echo "export GOOGLE_APPLICATION_CREDENTIALS='<< parameters.gcp_cred_config_file_path >>'" | tee -a "$BASH_ENV"

jobs:
  gcp-oidc-defaults:
    executor: gcp-cli/default
    steps:
      - gcp-cli/install
      - gcp-oidc-generate-cred-config-file
      - gcp-oidc-authenticate
      - run:
          name: Verify that gcloud is authenticated
          environment:
            GCP_SERVICE_ACCOUNT_EMAIL: jennings-oidc-test@makoto-workbench.iam.gserviceaccount.com
          command: gcloud iam service-accounts get-iam-policy "${GCP_SERVICE_ACCOUNT_EMAIL}"

workflows:
  main:
    jobs:
      - gcp-oidc-defaults:
          name: Generate Creds File and Authenticate
          context:
          - gcp-oidc-dev

You have the ability to use multiple service accounts from the same GCP project, or multiple service accounts from multiple GCP projects. You can read about these methods and find an example in CircleCI’s example repository.


Suggest an edit to this page

Make a contribution
Learn how to contribute