diff --git a/docs/guides/modules/permissions-authentication/pages/openid-connect-tokens.adoc b/docs/guides/modules/permissions-authentication/pages/openid-connect-tokens.adoc index 2fab31adc9..5501e80912 100644 --- a/docs/guides/modules/permissions-authentication/pages/openid-connect-tokens.adoc +++ b/docs/guides/modules/permissions-authentication/pages/openid-connect-tokens.adoc @@ -3,162 +3,95 @@ :page-description: Learn how to use OpenID Connect ID tokens for access to compatible cloud services. :experimental: -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. +CircleCI provides OpenID Connect ID (OIDC) tokens in environment variables. Jobs can be configured to use these OIDC tokens to access compatible cloud services without long-lived credentials being stored in CircleCI. -[#openid-connect-id-token-availability] -== OpenID Connect token availability - -CircleCI OpenID Connect ID tokens are available in the following environment variables: - -* `$CIRCLE_OIDC_TOKEN` -* `$CIRCLE_OIDC_TOKEN_V2` - Includes a different format for the `sub` claim, See <> for full details. - -CAUTION: **What about forks?** 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**. See <>. - -[#setting-up-your-cloud-service] -== 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 https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html[Creating OpenID Connect (OIDC) identity providers], or Google Cloud Platform's https://cloud.google.com/iam/docs/configuring-workload-identity-federation#oidc[Configuring Workload Identity federation]. - -The https://openid.net/specs/openid-connect-core-1_0.html#Terminology[OpenID Provider] is unique to your organization. The URL is `\https://oidc.circleci.com/org/`, 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 https://app.circleci.com/[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 xref:oidc-tokens-with-custom-claims.adoc[OIDC tokens with custom claims] page. - -NOTE: It is possible to use CircleCI's OIDC tokens with multiple cloud services. - -[#format-of-the-openid-connect-id-token] -== Format of the OpenID Connect ID token - -The OIDC tokens contain the following standard https://openid.net/specs/openid-connect-core-1_0.html#IDToken[claims]: - -[.table-scroll] --- -[cols="1,2", options="header"] -|=== -| Claims -| Description - -| `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/"`, a string, where `organization_id` is a UUID identifying the current job's project's organization. - -| `sub` -a| 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//project//user/"`, 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 xref:orchestrate:triggers-overview.adoc[trigger]: - -* If the trigger is an xref:orchestrate:triggers-overview.adoc#trigger-a-pipeline-from-a-custom-webhook[custom webhook] then: -`"org//project//user/"`, 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. +Some advantages to using OIDC over using static credentials: -* Otherwise it will be: -`"org//project//user//vcs-origin//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 repository URL and reference to the change that caused the job to run. +* **Improved security**: By using OIDC authentication, storing credentials directly in your CircleCI configuration or environment variables is avoided, reducing the risk of exposure. -| `aud` -| The audience. By default, this is `"ORGANIZATION_ID"`, a string containing a UUID that identifies the job's project's organization. To customize the aud, you can generate an OIDC token with a custom audience. See xref:oidc-tokens-with-custom-claims.adoc[OIDC tokens with custom claims] for more information. +* **Simplified credential management**: OIDC allows CircleCI to automatically manage the authentication process, eliminating the need to manually manage and rotate credentials. -| `iat` -| The time of issuance. This is the time the token was created, which is shortly before the job starts. +* **Fine-grained access control**: By associating a cloud provider role with OIDC authentication, exact permissions granted to CircleCI can be controlled, ensuring a least-privilege approach. -| `exp` -| The expiration time. Its value is one hour after the time of issuance. +[#openid-connect-id-token-availability] +== OpenID Connect tokens -|=== --- +CircleCI OpenID Connect ID tokens are available in the following environment variables: +* `$CIRCLE_OIDC_TOKEN` -The OpenID Connect ID tokens also contain some https://openid.net/specs/openid-connect-core-1_0.html#AdditionalClaims[additional claims] with extra metadata about the job: +* `$CIRCLE_OIDC_TOKEN_V2` - This token includes a different `sub` claim format to include a reference to the source of the change that triggered the job. -[.table-scroll] --- -[cols="2,2", options="header"] -|=== -| Additional claims -| Metadata - -| `oidc.circleci.com/context-ids` -| An array of strings containing UUIDs that identify the context(s) used in the job. +See <> for full details on the Claims used in each token. -| `oidc.circleci.com/job-id` -| The unique identifier for the job. Its value is a string containing a UUID identifying the CircleCI job. -| `oidc.circleci.com/org-id` -| The unique identifier for the organization. Its value is a string containing a UUID identifying the CircleCI organization. +CAUTION: **What about forks?** 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**. See <>. -| `oidc.circleci.com/pipeline-definition-id` -| The unique identifier for the pipeline definition that created the pipeline running the workflow. The value is a string containing a UUID identifying the CircleCI pipeline definition. Pipeline definitions are found in your project settings under Project Setup. +[#authenticate-jobs-with-cloud-providers] +== Set up cloud provider authentication -| `oidc.circleci.com/pipeline-id` -| The unique identifier for the pipeline that triggered this job. Its value is a string containing a UUID identifying the CircleCI pipeline. +Before your cloud service will accept CircleCI's OIDC tokens, you need to configure it to trust CircleCI as an identity provider. This tells your cloud service that tokens issued by CircleCI for your organization are legitimate and should be accepted. -| `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. +An identity provider is a configuration in your cloud service that defines a trusted source of authentication tokens. -| `oidc.circleci.com/ssh-rerun` -| A boolean indicating if the CI job is started using the SSH rerun feature. +You can use CircleCI's OIDC tokens with multiple cloud services. -| `oidc.circleci.com/vcs-origin` -| The URL of the repository 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 custom webhooks. +The following sections describe how to configure CircleCI jobs to authenticate with a cloud provider. Follow steps for your cloud provider, either AWS or GCP. -| `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 custom webhooks. +== AWS -| `oidc.circleci.com/workflow-id` -| The unique identifier for the workflow running the job. Its value is a string containing a UUID identifying the CircleCI workflow. -|=== --- +The following instructions cover the following: -[#oidc-in-open-source-projects] -== OIDC in open source projects +* 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 -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**. +NOTE: See the xref:pull-an-image-from-aws-ecr-with-oidc.adoc[Pull an Image From AWS ECR With OIDC] how-to guide after following this setup section. -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. +=== Prerequisites -For more information about building open source projects on CircleCI, see the xref:integration:oss.adoc[Build open source projects] page. +You will need to have the following to continue your AWS OIDC setup: -[#oidc-server] -== OIDC on CircleCI server +* A CircleCI account. You must be a member of an organization. See xref:getting-started:first-steps.adoc[Sign up and Try CircleCI] for more information. +* A project set up that you want to configure to use OIDC. +* An AWS account with the necessary permissions to create an IAM identity provider and role. -OIDC is supported from server v4.4+. However, OIDC is **not** supported if your server installation is in an air-gapped environment. +[#set-up-aws] +=== 1. Set up identity provider in AWS -[#authenticate-jobs-with-cloud-providers] -== Authenticate jobs with cloud providers +In this step you will allow your AWS account to trust CircleCI's OpenID Connect tokens. Follow the steps in this section to create an Identity and Access Management (IAM) identity provider, and an IAM role in AWS. -The following sections describe how to authenticate CircleCI jobs with Amazon Web Services (AWS) and Google Cloud Platform (GCP). +Creating the identity provider is a one-time configuration to get set up. -=== AWS +To create your identity provider you will need to know your link:https://openid.net/specs/openid-connect-core-1_0.html#Terminology[OpenID Provider], which is unique to your organization. The OpenID Provider URL is `\https://oidc.circleci.com/org/`, where `organization_id` is your unique organization identifier. -The following AWS instructions cover the following: +TIP: You can find your CircleCI organization ID by navigating to **Organization Settings > Overview** in the https://app.circleci.com/[CircleCI web app]. -* 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 +The default OpenID Connect ID tokens issued by CircleCI have a fixed audience (see `aud` in <>), which is also the organization ID. To generate tokens with _custom_ audience claims, see the xref:oidc-tokens-with-custom-claims.adoc[OIDC Tokens With Custom Claims] page. -Also see the xref:pull-an-image-from-aws-ecr-with-oidc.adoc[Pull an image from AWS ECR with OIDC] how-to guide, which follows on from this setup section. +Visit the https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html[Creating OpenID Connect (OIDC) identity providers] page of the AWS docs and follow the instructions. Multiple setup options are available including using the management console or CLI. You will need to provide the following: +** **OpenIDProvider URL**: Enter `\https://oidc.circleci.com/org/`, where `your-organization-id` is the ID of your CircleCI organization. +** **Audience**: Enter your organization ID. -[#set-up-aws] -==== Set up AWS +=== 2. Assign a role to your identity provider -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. +Now you have you identity provider set up you can assign roles to your identity provider 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. -. Visit the https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html[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/`, where `your-organization-id` is the ID of your CircleCI organization. -** **Audience**: Enter your organization ID -+ -include::ROOT:partial$notes/find-organization-id.adoc[] +Once your have created your identity provider, a banner appears at the top of the AWS console with the option to **Assign role**. Select this button to create a new role, or visit the https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html#idp_oidc_Create[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: -. Once your have created your Identity Provider, a banner appears at the top of the AWS console with the option to **Assign role**. Select this button to create a new role, or visit the https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_oidc.html#idp_oidc_Create[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. +** The **identity provider** that you just created. +** For **Audience**, choose the only option, which is your organization ID that you entered when creating the identity provider. ** 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 https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege[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] -==== Adding AWS to the CircleCI configuration file +=== 3. Add AWS to your 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. Use CircleCI’s link:https://circleci.com/developer/orbs/orb/circleci/aws-cli[AWS CLI orb] to generate temporary keys and configure a profile that uses OIDC. +Now that you have set up your trusted identity provider and IAM role, you are ready to configure a CircleCI job that authenticates with AWS using OIDC. Use CircleCI's link:https://circleci.com/developer/orbs/orb/circleci/aws-cli[AWS CLI orb] to generate temporary keys and configure a profile that uses OIDC. -TIP: Orbs are reusable packages of YAML configuration that condense repeated pieces of configuration into a single line of code. In this case, the AWS CLI orb enables you to generate a temporary session token, AWS Access Key ID, and AWS secret access key with a single command in your configuration. +[TIP] +==== +When using OIDC authentication, you *do not need to manually create or store AWS credentials files* in CircleCI. The `aws-cli/setup` command automatically handles the credential generation and configuration using the OIDC token. + +Orbs are reusable packages of YAML configuration that condense repeated pieces of configuration into a single line of code. In this case, the AWS CLI orb enables you to generate a temporary session token, AWS Access Key ID, and AWS secret access key with a single command in your configuration. +==== . In your `.circleci/config`, import the `aws-cli` orb. + @@ -167,10 +100,10 @@ TIP: Orbs are reusable packages of YAML configuration that condense repeated pie version: 2.1 orbs: - aws-cli: circleci/aws-cli@3.1.5 + aws-cli: circleci/aws-cli@5.4.1 ---- -. 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`. +. 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 `region`, which is your AWS region. + [source,yaml] ---- @@ -179,43 +112,44 @@ jobs: environment: AWS_REGION: us-west-1 docker: - - image: cimg/aws:2023.06 + - image: cimg/aws:2025.01 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} + role_arn: "arn:aws:iam::123456789012:role/OIDC-ROLE" + region: ${AWS_REGION} # optional parameters - profile-name: "OIDC-PROFILE" - role-session-name: "example-session" - session-duration: "1800" + 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. +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. +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. +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. -```yaml +[source,yaml] +---- version: 2.1 orbs: - aws-cli: circleci/aws-cli@5.1.1 + aws-cli: circleci/aws-cli@5.4.1 jobs: aws-example: environment: AWS_REGION: us-west-1 docker: - - image: cimg/aws:2022.06 + - image: cimg/aws:2025.01 steps: - checkout # run the aws-cli/setup command from the orb - aws-cli/setup: role_arn: "arn:aws:iam::123456789012:role/OIDC-ROLE" - region: AWS_REGION + region: ${AWS_REGION} # optional parameters profile_name: "OIDC-PROFILE" role_session_name: "example-session" @@ -230,34 +164,36 @@ workflows: jobs: - aws-example: context: aws -``` +---- [#advanced-usage] -==== Advanced usage +=== Advanced usage -You can take advantage of the format of the claims in CircleCI's <> to limit what your CircleCI jobs can do in AWS. +You can take advantage of the format of the claims in CircleCI's <> to limit what your CircleCI jobs can do in AWS. [#limit-role-access-based-on-project] -=== Limit role access based on project +==== 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. +If a projects should only be able to access certain AWS resources, you can restrict your IAM role so that only CircleCI jobs in that 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. -. Go to an individual project's page in the https://app.circleci.com/[CircleCI web app] and navigate to **Project Settings > Overview** to find your Project ID. +. Go to an individual project's page in the https://app.circleci.com/[CircleCI web app] and navigate to menu:Project Settings [Overview] to find your Project ID. . 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`. + -```yaml +.Update trust policy to restrict access to specific project +[source,yaml] +---- "StringLike": { "oidc.circleci.com/org/:sub": "org//project//user/*" } -``` +---- + This uses https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String[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] -=== Limit role access based on branch +==== 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. @@ -282,39 +218,55 @@ You can also restrict access to specific branches. The following is an example o ``` [#google-cloud-platform] -=== Google Cloud Platform +== Google Cloud Platform + +The following instructions cover: + +* 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 following GCP instructions are for: +TIP: 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 https://cloud.google.com/iam/docs/configuring-workload-identity-federation#oidc[Google Cloud's docs]. -* 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 +=== Prerequisites -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 https://cloud.google.com/iam/docs/configuring-workload-identity-federation#oidc[Google Cloud's docs]. +You will need to have the following to continue your AWS OIDC setup: + +* A CircleCI account. You must be a member of an organization. See xref:getting-started:first-steps.adoc[Sign up and Try CircleCI] for more information. +* A project set up that you want to configure to use OIDC. +* A GCP account with the necessary permissions to create a Workload Identity pool and provider. [#setting-up-gcp] -==== Setting up GCP +=== 1. Set up GCP + +The steps in this section are based on Google Cloud Platform's link:https://cloud.google.com/iam/docs/configuring-workload-identity-federation#oidc[Configuring Workload Identity federation] documentation. + +To create your identity provider you will need to know your link:https://openid.net/specs/openid-connect-core-1_0.html#Terminology[OpenID Provider], which is unique to your organization. The OpenID Provider URL is `\https://oidc.circleci.com/org/`, where `organization_id` is your unique organization identifier. + +TIP: You can find your CircleCI organization ID by navigating to **Organization Settings > Overview** in the https://app.circleci.com/[CircleCI web app]. -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`). +The default OpenID Connect ID tokens issued by CircleCI have a fixed audience (see `aud` in <>), which is also the organization ID. To generate tokens with _custom_ audience claims, see the xref:oidc-tokens-with-custom-claims.adoc[OIDC Tokens With Custom Claims] page. -You will need your CircleCI organization ID, which can be found by navigating to **Organization Settings > Overview** on the https://app.circleci.com/[CircleCI web app]. +=== 2. Configure GCP Workload Identity Federation -After navigating to the **Grant Access** section of the GCP web UI, follow these steps to add CircleCI as an external Identity Provider: +GCP Workload Identity Federation is a feature that allows you to use CircleCI's OIDC tokens to authenticate with GCP. Using Workload Identity Federation allows applications outside Google Cloud to access Google Cloud resources without the need for storing service account credentials. Instead, you can use Identity and Access Management (IAM) to grant access to specific Google Cloud resources. + +In the GCP web UI, follow the steps to add CircleCI as an external identity provider: . Navigate to the **IAM & Admin panel**. . On the side panel, navigate to **Workload Identity Federation**. . Select **Add Provider**. . Select **OpenID Connect (OIDC)** from the "Select a provider" dropdown and select **Save**. . 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/`, where `organization_id` is your CircleCI organization ID. +** 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/`, where `organization_id` is your CircleCI organization ID. . Select **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: +Configuring the provider attributes provides an opportunity to map claims in CircleCI's oken to Google's "understanding". Use this mapping: + - [.table-scroll] -- -[cols="1,2"] +.Token to GCP mapping +[cols="1,2", options="header"] |=== | `google.subject` | `assertion.sub` @@ -333,15 +285,60 @@ Configuring the provider attributes provides an opportunity to map claims in Cir . 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. . Under **Select principals**, you can add conditions, or leave the default. . Select **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**. -. 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: +=== 3. Configure your CircleCI pipeline + +You have two options for configuring your CircleCI pipeline to use the GCP configuration file. You can download the configuration file once and commit this to your repository, or you can generate the configuration file dynamically in your CircleCI pipeline. + +TIP: *Dynamic configuration* generation is more secure (no secrets in repo), but more complex to set up. +Choosing the configuration *file download* option is simpler to set up, but the config file is in your repository and can be viewed by anyone with access to the repository. + +[tabs] +==== +Dynamic:: ++ +-- +If you choose to generate the configuration file dynamically in your pipeline you can use the GCP CLI. The following example is an excerpt from the full configuration file below: + +.Use CLI to generate the GCP configuration file dynamically +[source,shell] +---- +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}" +---- +-- +Download:: ++ +-- +Download the configuration file once and commit this to your repository. You can name the file anything you like but best practice is to give it a descriptive name, for example, `gcp-config-dev.json`. You will reference this file in your CircleCI configuration. +-- +==== + +An example of the configuration file is shown below along with descriptions for some fields. + +[.table-scroll] +-- +[cols="1,2", options="header"] +|=== +| **Placeholder** +| **Description** + +| `project_number` +| The unique identifying number generated for your project. -* `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`) +| `pool_id` +| An ID that references the Workload Identity pool, for example `circleci_oidc`. -```yaml +| `provider_id` +| An ID that references the Workload Identity pool provider, for example, `circleci`. +|=== +-- + +[source,json] +---- { "type": "external_account", "audience": "//iam.googleapis.com/projects//locations/global/workloadIdentityPools//providers/", @@ -355,13 +352,14 @@ An example of the configuration file is shown below. Note, the `audience` has no } } } -``` +---- -In this configuration, `credential_source` will attempt to find your identity token in the `CIRCLE_OIDC_TOKEN_FILE`, as noted in the (<<#openid-connect-id-token-availability,token availability>> section). +In this configuration, `credential_source` will attempt to find your identity token in the `CIRCLE_OIDC_TOKEN_FILE` file. The file name can be anything, as long as it matches the file name specified in `credential_source.file` in your downloaded configuration file. 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`. -```yaml +[source,json] +---- "credential_source": { "file": "CIRCLE_OIDC_TOKEN_FILE", "format": { @@ -369,27 +367,17 @@ If your token comes from an API response, it might be useful to set up the confi "path": "response.id_token" } } -``` - -NOTE: If needed, you can also attempt to generate the GCP configuration file by running the following script: - -```shell -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] -==== 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: +You will need to write one of CircleCI's OIDC tokens to a file in your job. You can use either $CIRCLE_OIDC_TOKEN or $CIRCLE_OIDC_TOKEN_V2. The V2 token includes additional VCS information (repository and branch) which allows for more granular access control in GCP. See <> for details on the differences. For example: -```bash +.Write the OIDC token to a file +[source,shell] +---- echo $CIRCLE_OIDC_TOKEN >> CIRCLE_OIDC_TOKEN_FILE -``` +---- -You will also need to add the following environment variables to a xref:security:contexts.adoc[context]. +Add the following environment variables to a context. You will use this context in your CircleCI configuration to give your pipeline access to securely access the environment variables. See the xref:security:contexts.adoc[Contexts] page for more information. [.table-scroll] -- @@ -419,7 +407,9 @@ You will also need to add the following environment variables to a xref:security 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 link:https://circleci.com/developer/orbs/orb/circleci/gcp-cli[`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. -```yaml +.Full example configuration using the `gcp-cli` orb for OIDC authentication +[source,yaml] +---- version: 2.1 orbs: @@ -493,10 +483,118 @@ workflows: 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 link:https://github.com/jtreutel/circleci-gcp-oidc-test#usage[example repository]. +[#format-of-the-openid-connect-id-token] +== OpenID Connect ID tokens format + +CircleCI's OIDC tokens contain the following standard https://openid.net/specs/openid-connect-core-1_0.html#IDToken[claims]: + +[.table-scroll] +-- +[cols="1,2", options="header"] +|=== +| Claims +| Description + +| `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/"`, a string, where `organization_id` is a UUID identifying the current job's project's organization. + +| `sub` +a| 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//project//user/"`, 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 type: + +*If the trigger is a* xref:orchestrate:triggers-overview.adoc#trigger-a-pipeline-from-a-custom-webhook[Custom Webhook]: + +`"org//project//user/"` + +A string in which `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. + +*All other trigger types*: + +`"org//project//user//vcs-origin//vcs-ref/"` + +A string in which `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 repository URL and reference to the change that caused the job to run. + +| `aud` +| The audience. By default, this is `ORGANIZATION_ID`, a string containing a UUID that identifies the job's project's organization. To customize the audience you can generate an OIDC token with a custom audience. See xref:oidc-tokens-with-custom-claims.adoc[OIDC Tokens With Custom Claims] for more information. + +| `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. + +|=== +-- + + +CircleCI's OpenID Connect ID tokens also contain some https://openid.net/specs/openid-connect-core-1_0.html#AdditionalClaims[additional claims] with extra metadata about the job: + +[.table-scroll] +-- +[cols="2,2", options="header"] +|=== +| Additional claims +| Metadata + +| `oidc.circleci.com/context-ids` +| An array of strings containing UUIDs that identify the context(s) used in the job. + +| `oidc.circleci.com/job-id` +| The unique identifier for the job. Its value is a string containing a UUID identifying the CircleCI job. + +| `oidc.circleci.com/org-id` +| The unique identifier for the organization. Its value is a string containing a UUID identifying the CircleCI organization. + +| `oidc.circleci.com/pipeline-definition-id` +| The unique identifier for the pipeline definition that created the pipeline running the workflow. The value is a string containing a UUID identifying the CircleCI pipeline definition. Pipeline definitions are found in your project settings under Project Setup. + +| `oidc.circleci.com/pipeline-id` +| The unique identifier for the pipeline that triggered this job. Its value is a string containing a UUID identifying the CircleCI pipeline. + +| `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/ssh-rerun` +| A boolean indicating if the CI job is started using the SSH rerun feature. + +| `oidc.circleci.com/vcs-origin` +| The URL of the repository 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 custom 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 custom webhooks. + +| `oidc.circleci.com/workflow-id` +| The unique identifier for the workflow running the job. Its value is a string containing a UUID identifying the CircleCI workflow. +|=== +-- + +[#oidc-in-open-source-projects] +== 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 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 that they should not. + +For more information about building open source projects on CircleCI, see the xref:integration:oss.adoc[Build Open Source Projects] page. + +[#oidc-server] +== 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. + [#next-steps] == Next steps -- xref:oidc-tokens-with-custom-claims.adoc[OpenID Connect tokens with custom claims] +- xref:oidc-tokens-with-custom-claims.adoc[OpenID Connect Tokens With Custom Claims] diff --git a/styles/circleci-docs/TableTitles.yml b/styles/circleci-docs/TableTitles.yml index 624a59450a..4cb3c6034a 100644 --- a/styles/circleci-docs/TableTitles.yml +++ b/styles/circleci-docs/TableTitles.yml @@ -9,44 +9,72 @@ script: | matches := [] lines := text.split(scope, "\n") - table_delimiter_count := 0 for i, line in lines { trimmed := text.trim_space(line) // Check for table delimiter if trimmed == "|===" { - // Even count = opening delimiter, odd count = closing delimiter - is_opening := table_delimiter_count % 2 == 0 + // Count how many |=== delimiters appear before this one + preceding_count := 0 + for k := 0; k < i; k++ { + if text.trim_space(lines[k]) == "|===" { + preceding_count = preceding_count + 1 + } + } + + // If preceding count is even, this is an opening delimiter + is_opening := preceding_count % 2 == 0 if is_opening { - // Look back for a title, skipping empty lines, attributes, and block delimiters + // This is an opening delimiter - check for title has_title := false + lookback_limit := 10 // Only look back max 10 lines - for j := i - 1; j >= 0; j-- { + // Look back for a title, skipping empty lines, attributes, and block delimiters + for j := i - 1; j >= 0 && (i - j) <= lookback_limit; j-- { prev_trimmed := text.trim_space(lines[j]) - // Skip empty lines, attribute lines, and block delimiters (-- or ==) - if prev_trimmed == "" || text.has_prefix(prev_trimmed, "[") || prev_trimmed == "--" || prev_trimmed == "==" { + // Skip empty lines + if prev_trimmed == "" { + continue + } + + // Skip attribute lines (start with [) + if text.has_prefix(prev_trimmed, "[") { continue } - // Check if this line is a title - if text.has_prefix(prev_trimmed, ".") { + // Skip block delimiters (only dashes or equals) + if text.re_match("^-+$", prev_trimmed) || text.re_match("^=+$", prev_trimmed) { + continue + } + + // Skip comment lines (start with //) + if text.has_prefix(prev_trimmed, "//") { + continue + } + + // Check if this line is a title (starts with a dot but not ..) + if text.has_prefix(prev_trimmed, ".") && !text.has_prefix(prev_trimmed, "..") { has_title = true break } - // Found a non-attribute, non-empty line that's not a title + // Found a non-skippable line that's not a title + // This means there's content between the table and any potential title break } if !has_title { - start := text.index(scope, line) - matches = append(matches, {begin: start, end: start + len(line)}) + // Calculate position by counting characters up to this line + pos := 0 + for k := 0; k < i; k++ { + pos = pos + len(lines[k]) + 1 // +1 for newline + } + matches = append(matches, {begin: pos, end: pos + len(line)}) } } - - table_delimiter_count = table_delimiter_count + 1 + // Closing delimiters don't need any action } }