Upgrading GitLab CI/CD Authentication: Migrating to OIDC for Google Cloud
Tags: devops, cloud, gitlab, googlecloud
Published: 2024-02-27 03:34:14

## The Challenge

Why should I migrate my pipelines to OIDC? I have my Service Account credentials stored securely in a CI/CD variable, and I don't plan on it going anywhere. Here's the thing, static keys present a significant risk of compromise since they remain constant over time. If these keys are compromised, an attacker could potentially manipulate the cloud environment undetected for an extended period, posing a severe threat to the security and integrity of the infrastructure and the data stored within it. Additionally, static keys lack context and are highly portable, exacerbating the security risk. Unlike dynamically generated tokens or keys tied to specific environments, static keys can be copied and used across multiple environments without any linkage to their origin. This portability makes it challenging for security teams to trace the usage of these keys and identify where they are being utilized, thereby increasing the difficulty of detecting and mitigating unauthorized access or malicious activities. Introducing OIDC!

## The Benefits of OIDC

Using Google Cloud's Workload Identity Federation is the safer and recommended way to authenticate your GitLab pipelines with Google Cloud. Workload Identity Federation eliminates the need to issue static keys for authentication, removing the burden of long-term key management. With Workload Identity Federation, there is no compliance requirement to rotate secrets every few months, since temporary access tokens are issued each time! This greatly reduces the risk of leaked credentials or compromised access, since the tokens are short-lived. Overall, Workload Identity Federation provides a more secure and lower maintenance way to connect GitLab pipelines to Google Cloud resources compared to using static service account keys. The temporary tokens provide defense in depth against leaked credentials, while freeing developers from having to constantly rotate keys.

## How it Works

![How it Works](https://about.gitlab.com/images/blogimages/2023-06-30-introduction-of-oidc-modules-for-integration-between-google-cloud-and-gitlab-ci/oidc-auth-diagram.png)

## Demonstration

### Existing Infrastructure

In the following demonstration, we will showcase the infrastructure that enables secure authentication between a GitLab pipeline and Google Cloud resources. When the GitLab pipeline is triggered, Workload Identity Federation will automatically exchange the pipeline's credentials for temporary IAM access tokens to deploy into Google Cloud. The following are existing components within the CI/CD pipeline and Google Cloud: 

- Terraform Service Account for the pipelines

![Service Account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thhacgnsk09hc0n2akvs.png)

- Pipeline utilizing Service Account static credentials to create infrastructure

```yaml
stages:
  - validate
  - test
  - build
  - deploy
  - cleanup

before_script:
  - cat $GCP_CREDENTIALS > /tmp/gcp_credentials.json
```

### Harnessing Google Workload Identity

The following [Terraform `oidc` module](https://gitlab.com/gitlab-com/gl-security/security-operations/infrastructure-security-public/oidc-modules) does the following:

  1. Workload Identity Pool Creation:
        - Creates a new Google Cloud Workload Identity Pool with an ID derived from either a provided `workload_identity_name` or `gitlab_project_id`.
        - Associates the pool with a Google Cloud project specified by `google_project_id`.

  2. Workload Identity Provider Creation:
        - Creates a new Google Cloud Workload Identity Provider inside the previously created pool (The provider's ID is derived similarly to the pool ID).
        - Sets conditions for attribute mapping based on the provided parameters.
        - Maps attributes from the OIDC token to attributes understood by Google Cloud IAM.
        - Configures OIDC settings such as the issuer URI (`gitlab_url`) and allowed audiences (`allowed_audiences`).

  3. Permission Granting:
        - Grants permissions for Service Account impersonation by creating IAM bindings.
            - For each service account specified in `var.oidc_service_account`, it binds the role `roles/iam.workloadIdentityUser`.
        - Grants access to the principal set of the previously created identity pool for each service account.

Our `main.tf` file will look like this:

```terraform
module "gitlab_oidc" {
  source = "./modules/oidc"

  google_project_id = var.google_project_id
  gitlab_project_id = var.gitlab_project_id
  oidc_service_account = {
    "sa" = {
      sa_email  = var.service_account_email
      attribute = "attribute.project_id/${var.gitlab_project_id}"
    }
  }
}
```

The output from a `terraform apply` will provide us with the needed information for migrating our existing pipelines to OIDC:

```console
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:
workload_identity_pool = "projects/458331852021/locations/global/workloadIdentityPools/gl-id-pool-oidc-55282716/providers/gitlab-jwt-55282716"
```

Making use of the [CI Template](https://gitlab.com/gitlab-com/gl-security/security-operations/infrastructure-security-public/oidc-modules/-/raw/3.1.2/templates/gcp_auth.yaml) provided by GitLab's infrastructure security team, we can add these variables to our pipeline to authenticate via OIDC:

```yaml
include:
  - remote: 'https://gitlab.com/gitlab-com/gl-security/security-operations/infrastructure-security-public/oidc-modules/-/raw/3.1.2/templates/gcp_auth.yaml'
  - template: "Terraform/Base.gitlab-ci.yml"

variables:
  WI_POOL_PROVIDER: //iam.googleapis.com/projects/458331852021/locations/global/workloadIdentityPools/gl-id-pool-oidc-55282716/providers/gitlab-jwt-55282716
  SERVICE_ACCOUNT: terraform@oidc-demo-415417.iam.gserviceaccount.com

build:
  extends:
    - .google-oidc:auth
    - .terraform:build

deploy:
  extends:
    - .google-oidc:auth
    - .terraform:deploy
```

Now that we have this in place, we can create resources using OIDC:

```terraform
module "compute_engine" {
  source = "./modules/compute-engine"

  instance_name = "oidc-demo-instance"
  zone          = "us-central1-a"
}
```

And we can see that the resource is created:

```console
Terraform has been successfully initialized!
module.gitlab_oidc.google_iam_workload_identity_pool.gitlab_pool: Creating...
module.compute_engine.google_compute_instance.default: Creating...
module.compute_engine.google_compute_instance.default: Still creating... [10s elapsed]
module.compute_engine.google_compute_instance.default: Creation complete after 13s [id=projects/oidc-demo-415417/zones/us-central1-a/instances/oidc-demo-instance]
```

## Conclusion

This article highlights the security and automation benefits of Workload Identity Federation for connecting GitLab pipelines to Google Cloud. By automatically exchanging pipeline identities for short-lived IAM access tokens, Workload Identity Federation removes the risks of long-term credentials while enabling access between GitLab and Google Cloud. With minimal setup, pipelines can securely deploy to Google Cloud without managing static keys. Stay safe out there!

## References

- [How OIDC can simplify authentication of GitLab CI/CD pipelines with Google Cloud](https://about.gitlab.com/blog/2023/06/28/introduction-of-oidc-modules-for-integration-between-google-cloud-and-gitlab-ci/)