GitLab CI can authenticate to AWS and GCP using OpenID Connect (OIDC) without ever needing to store long-lived AWS/GCP credentials in GitLab.

Let’s see this in action. Imagine a GitLab CI job that needs to deploy an application to Google Cloud.

deploy-to-gcp:
  stage: deploy
  image: google/cloud-sdk:latest
  script:
    - echo "Authenticating to GCP..."
    - gcloud auth login --cred-file=/tmp/gcp_credentials.json
    - echo "Deploying to GKE..."
    - gcloud container clusters get-credentials my-cluster --zone us-central1-a --project my-gcp-project
    - kubectl apply -f kubernetes/deployment.yaml
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

This job doesn’t have any secrets like GCP_SA_KEY or AWS_ACCESS_KEY_ID baked into its environment. Instead, it relies on OIDC.

How it Works: The OIDC Flow

At its core, OIDC is about identity federation. GitLab acts as an Identity Provider (IdP), and AWS/GCP act as Service Providers (SPs). When a GitLab CI job needs to assume a role or get credentials in AWS/GCP, it initiates an OIDC flow:

  1. GitLab Generates a Token: When a CI job starts, GitLab can be configured to generate a short-lived OIDC token. This token contains claims about the job, such as the project, branch, commit SHA, and the runner that executed it.
  2. GitLab Publishes its Public Keys: GitLab makes its public OIDC signing keys available at a well-known URL. This allows AWS/GCP to verify that tokens generated by GitLab are legitimate.
  3. AWS/GCP Trust GitLab: You configure AWS IAM or GCP IAM to trust GitLab as an OIDC provider. This involves registering GitLab’s OIDC discovery endpoint URL and the URL where its public keys are published.
  4. Assume Role/Get Credentials:
    • AWS: The CI job uses the generated GitLab OIDC token to make an AssumeRoleWithWebIdentity API call to AWS. AWS validates the token against its configured OIDC provider (GitLab), checks the role’s trust policy (which explicitly allows gitlab.com or your self-hosted GitLab instance to assume the role), and if valid, issues temporary AWS security credentials.
    • GCP: Similarly, the CI job uses the GitLab OIDC token to authenticate with GCP’s security token service (STS). GCP validates the token, checks the IAM policy for the service account that the job is trying to impersonate, and if valid, issues temporary credentials for that service account.

Configuring GitLab for OIDC

To enable this, you need to configure GitLab:

  1. GitLab Admin Area: Navigate to Admin Area > Settings > CI/CD > Token access.
  2. Enable OIDC: Check the box for "Enable OpenID Connect token generation".
  3. Configure OIDC Claims: You can customize the claims included in the OIDC token. By default, GitLab includes useful information. For more advanced scenarios, you can add custom claims.
  4. Set Expiration: Define how long the OIDC tokens should be valid. Shorter lifetimes (e.g., 5-15 minutes) are generally more secure.

Configuring AWS for OIDC

  1. Create an IAM OIDC Provider:
    • Go to IAM in the AWS console.
    • Navigate to "Identity providers" and click "Add provider".
    • Choose "OpenID Connect".
    • Provider URL: Enter your GitLab instance URL, e.g., https://gitlab.com or https://your.gitlab.instance.com.
    • Audience: This is crucial. For AWS, the standard audience is sts.amazonaws.com.
    • Click "Add provider".
  2. Create an IAM Role:
    • Go to IAM -> Roles -> Create role.
    • Trusted entity type: Select "Web identity".
    • Identity provider: Choose the GitLab OIDC provider you just created.
    • Audience: Keep it as sts.amazonaws.com.
    • Service account: You might see an option to specify a service account if you are using a specific GitLab configuration, but for general gitlab.com usage, you often leave this blank or use https://gitlab.com.
    • Policy: Attach policies that grant the necessary permissions (e.g., S3 read/write, EC2 start/stop).
    • Trust Relationship: The trust policy will look something like this, allowing your GitLab instance to assume this role:
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/gitlab.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
              "StringEquals": {
                "gitlab.com:aud": "sts.amazonaws.com"
              }
            }
          }
        ]
      }
      
    • Customizing Trust: You can make the trust policy more granular. For example, to only allow jobs from a specific project and branch:
      {
        "Version": "2012-10-17",
        "Statement": [
          {
            "Effect": "Allow",
            "Principal": {
              "Federated": "arn:aws:iam::<AWS_ACCOUNT_ID>:oidc-provider/gitlab.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
              "StringEquals": {
                "gitlab.com:aud": "sts.amazonaws.com",
                "gitlab.com:iss": "https://gitlab.com",
                "gitlab.com:sub": "project_id/<GITLAB_PROJECT_ID>:ref_type:branch:ref:main"
              }
            }
          }
        ]
      }
      

Configuring GCP for OIDC

  1. Create a Workload Identity Pool:
    • Go to IAM & Admin -> Workload Identity Pools in the GCP console.
    • Click "Create pool".
    • Give it a display name and an ID (e.g., gitlab-oidc-pool).
  2. Create a Workload Identity Provider:
    • Within your newly created pool, click "Add provider".
    • Choose "OpenID Connect".
    • Provider name: e.g., gitlab-provider.
    • Issuer OAuth/OIDC URL: Enter your GitLab instance URL, e.g., https://gitlab.com or https://your.gitlab.instance.com.
    • Attribute mapping: This is where you map GitLab claims to GCP attributes.
      • google.subject mapped to assertion.sub (standard)
      • google.audience mapped to assertion.aud (standard audience for your GCP project)
    • Attribute condition (optional but recommended): Use this to restrict which GitLab jobs can use this provider. For example, to only allow jobs from a specific project: attribute.repository == "your-group/your-project".
    • Click "Continue".
    • Important: Note the Workload Identity Pool Provider Name (e.g., projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/gitlab-oidc-pool/providers/gitlab-provider). You’ll need this.
  3. Create a Service Account:
    • Create a GCP service account that your CI jobs will impersonate (e.g., gitlab-deployer@your-gcp-project.iam.gserviceaccount.com).
  4. Grant the Service Account to the Workload Identity Provider:
    • In the Workload Identity Pool provider settings, under "Grant access to this provider", select the service account you created.
    • This effectively creates a binding similar to an IAM policy, allowing the OIDC provider to impersonate the service account.
  5. Update Service Account IAM Policy:
    • Go to the Service Account’s IAM page.
    • Click "Grant Access".
    • New principals: Enter the Workload Identity Pool Provider Name you noted earlier.
    • Role: Assign the role that allows the provider to impersonate the service account. This is typically the roles/iam.workloadIdentityUser role.

Using the OIDC Token in GitLab CI

In your .gitlab-ci.yml, you’ll use a tool like gcloud or the AWS CLI, which has built-in support for OIDC.

For GCP:

You’ll typically configure gcloud to use the OIDC token. The gcloud auth login command can take a --cred-file argument pointing to a JSON file containing the OIDC token. The google-github-actions/auth action is a good example of how this is done programmatically. In a raw script, it looks like this:

# In your GitLab CI job
# 1. Export the OIDC token and configure GCP:
export GOOGLE_OIDC_TOKEN=$(cat "$CI_JOB_JWT_FILE") # GitLab makes the token available here
export GOOGLE_OIDC_TOKEN_AUDIENCE="//iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/gitlab-oidc-pool/providers/gitlab-provider"
export GOOGLE_OIDC_TOKEN_SUBJECT="https://gitlab.com/your-group/your-project" # Or a more specific sub based on your trust policy

# 2. Authenticate gcloud (this is a simplified view, actual auth involves STS calls)
gcloud auth login --cred-file=/tmp/gcp_credentials.json --scopes="https://www.googleapis.com/auth/cloud-platform"

# The /tmp/gcp_credentials.json will contain temporary credentials obtained by gcloud
# using the OIDC token to impersonate the GCP service account.
# You can then use gcloud commands as usual.
gcloud container clusters get-credentials ...

For AWS:

The AWS CLI can use the OIDC token directly. You’ll need to configure the CLI to use the AssumeRoleWithWebIdentity action.

# In your GitLab CI job
export AWS_OIDC_TOKEN=$(cat "$CI_JOB_JWT_FILE") # GitLab makes the token available here

# Install jq if not present
# apt-get update && apt-get install -y jq

# Get temporary AWS credentials
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
ROLE_ARN="arn:aws:iam::<AWS_ACCOUNT_ID>:role/your-gitlab-ci-role" # Replace with your role ARN

WEB_IDENTITY_TOKEN=$(cat "$CI_JOB_JWT_FILE")

TEMP_CREDS=$(aws sts assume-role-with-web-identity \
  --role-arn "$ROLE_ARN" \
  --role-session-name "gitlab-ci-session-$(echo $CI_JOB_ID)" \
  --web-identity-token "$WEB_IDENTITY_TOKEN" \
  --provider-id "https://gitlab.com" \
  --region "us-east-1" \
  --output json)

export AWS_ACCESS_KEY_ID=$(echo $TEMP_CREDS | jq -r .Credentials.AccessKeyId)
export AWS_SECRET_ACCESS_KEY=$(echo $TEMP_CREDS | jq -r .Credentials.SecretAccessKey)
export AWS_SESSION_TOKEN=$(echo $TEMP_CREDS | jq -r .Credentials.SessionToken)

# Now you can use AWS CLI commands
aws s3 ls

The most surprising thing about OIDC authentication is how it completely decouples the cloud provider’s credential management from your CI/CD system’s secret management. Instead of rotating static access keys or service account keys, you’re managing trust relationships between identity providers and service providers.

The CI_JOB_JWT_FILE variable is a file path provided by GitLab CI that contains the OIDC token for the current job. This token is short-lived and signed by GitLab, allowing AWS/GCP to verify its origin and content.

The next concept you’ll likely explore is how to manage multiple environments (dev, staging, prod) using OIDC, perhaps by dynamically selecting different AWS roles or GCP service accounts based on GitLab CI variables like CI_ENVIRONMENT_SLUG.

Want structured learning?

Take the full Gitlab-ci course →