Securing Your CI/CD Pipeline: Eliminate Long-Lived Credentials with Workload Identity Federation (2)

David-French
Staff

Welcome to part two of this series where we’re looking at how to improve an organization’s security posture by reducing the risks associated with using long-lived credentials. Part one reviewed the security risks associated with using service account keys.

This post will focus on reducing risk by implementing an alternative authentication method to service account keys. Specifically, I’m going to configure Workload Identity Federation to issue short-lived credentials to GitHub Actions workflows that are used to manage my rules in Google Security Operations (SecOps).

What is Workload Identity Federation?

Workload Identity Federation allows you to grant workloads access to your Google Cloud resources and eliminates the maintenance and security risks associated with managing and storing service account keys. It can be used with workloads that run on AWS or Azure, with deployment pipelines such as GitHub and GitLab, and with any identity provider (IdP) that supports OpenID Connect (OIDC) or Security Assertion Markup Language (SAML) V2.0.

A security benefit of using Workload Identity Federation is that it issues short-lived credentials to workloads. Even if an attacker manages to obtain a short-lived credential, their window of opportunity to exploit them is limited in comparison to a long-lived credential. Think of it like getting a room key card (that expires after your stay) instead of a physical key when you check into a hotel.

Configuring Workload Identity Federation with GitHub Actions and Google SecOps

In today’s example, we’re going to configure Workload Identity Federation to issue short-lived credentials to my GitHub Actions workflows that are used to manage my rules in Google SecOps. Once I’ve validated that my CI/CD pipeline is working with Workload Identity Federation, I’ll delete the redundant service account key from my Google Cloud project.

Define an Attribute Mapping

As per the documentation, one of the first steps for configuring Workload Identity Federation is to define the attribute mapping between the IdP (GitHub Actions in this example) and the workload identity pool provider in my Google Cloud project.

When a GitHub Actions workflow runs, it requests an OpenID Connect (OIDC) token from GitHub’s OIDC provider, which responds with a unique, automatically generated JSON web token (JWT). Attributes within the OIDC token describe the workload such as:

  • GitHub repository name (repository)
  • GitHub repository ID (repository_id)
  • GitHub Actions workflow name (workflow)
  • Commit SHA for the workflow file (workflow_sha)

GitHub’s documentation includes an example OIDC token and tool that you can use to explore the various fields and values available to use in your attribute mapping.

The workload identity pool provider in Google Cloud holds configurations for external identities. You define rules and conditions within this pool to determine which workloads are allowed to access your Google Cloud resources.

For my environment, I decided on the attribute mapping below. In production, I’d consider implementing an even stricter mapping to only grant access to the workload identity pool from certain branches of the GitHub repository or if the commit SHA for the workflow file is an expected value indicating that it has not been tampered with by a bad actor to carry out malicious actions in my pipeline.

Note that I opted to map the GitHub repository ID (an immutable value) as opposed to the GitHub repository name to decrease the chance of typosquatting attacks. I did the same for the attribute that identifies the owner ID for the GitHub repository.

Google OIDC (GitHub Actions)
google.subject assertion.sub
attribute.repository_id assertion.repository_id
attribute.repository_owner_id
assertion.repository_owner_id

Define an Attribute Condition

The next step is to define an attribute condition to restrict which identities can authenticate using the workload identity pool. In this example, I’m going to use the following Common Expression Language (CEL) expression to restrict access based on the values for the GitHub repository ID and GitHub owner ID.

 

assertion.repository_id == "123456789" &&
assertion.repository_owner_id == "87654321"

 

Create the Workload Identity Pool and Provider

Now that we’ve defined the attribute mapping and attribute condition to allow/deny access to Google Cloud resources, we can create the new workload identity pool and provider in the Google Cloud project. I configured the new workload identity pool as shown in the image below.

image.pngCreating a new workload identity pool

I added GitHub Actions as a provider to the workload identity pool as follows.

image.pngAdding GitHub Actions as a provider to the workload identity pool

The attribute mapping for the workload identity pool provider that I defined earlier is configured in the next step.

image.pngConfiguring the attribute mapping between the workload identity pool and IdP (GitHub Actions)

The CEL expression we defined earlier is configured under “Attribute Conditions” to restrict authentication to the workload identity pool based on the GitHub repository ID and owner ID.

image.pngRestricting access to the workload identity pool using a CEL expression

Allow the External Workload to Access Google Cloud Resources

Now it’s time to grant the external workload (GitHub Actions) access to Google Cloud resources, which in this case is my rules in Google SecOps.

On the IAM page in the Google Cloud console, I granted direct resource access to the principal (my GitHub Actions workflows in my GitHub repository) to Google SecOps by assigning it the “Chronicle API Editor” role. In production, I’d recommend creating a custom IAM role and assigning it only the minimum necessary permissions that your GitHub Actions workflow needs.

image.pngGranting the GitHub Actions workflows direct resource access to Google SecOps

Configure GitHub Actions to Use Workload Identity Federation

The google-github-actions/auth action makes it easy to configure your GitHub Actions workflows to authenticate to a Google Cloud workload identity pool and carry out actions in your Google Cloud environment. I added the step below to my GitHub Actions workflows that manage my rules in Google SecOps.

The “workload_identity_provider” should be set to the full identifier of the workload identity pool provider including the Google Cloud project number, pool name, and provider name. For example, “projects/1234567891234/locations/global/workloadIdentityPools/github-actions-google-secops-1/providers/github”.

I set the “access_token_lifetime” to 180 seconds. Three minutes is long enough for my GitHub Actions workflows to run and shortens an attacker’s window of opportunity to abuse the credential if it’s compromised.

 

- uses: google-github-actions/auth@v2
with:
  project_id: ${{ vars.GOOGLE_CLOUD_PROJECT_ID }}
  
  # The full identifier of the workload identity pool provider
  workload_identity_provider: ${{ secrets.GOOGLE_CLOUD_WORKLOAD_IDENTITY_PROVIDER}}
  
  # Request an access token with a lifetime of 3 minutes (180 seconds)
  access_token_lifetime: 180s
  
  # Export common environment variables to be consumed by downstream libraries and tools (e.g. GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_GHA_CREDS_PATH)
  export_environment_variables: true
  
  # Generate a credentials file which can be used for authentication via gcloud and Google Cloud SDKs in other steps in the workflow
  create_credentials_file: true
  
  # Remove any created credentials from the filesystem upon completion
  cleanup_credentials: true

 

I also did the following before testing authentication from my GitHub Actions workflows using Workload Identity Federation:

  • Removed calls to the service account key secret (GOOGLE_SECOPS_SERVICE_ACCOUNT_KEY) from my GitHub Actions workflow files
  • Updated my code to authenticate to the Google SecOps API using Application Default Credentials instead of a service account key

Testing Authentication via Workload Identity Federation

To validate that my GitHub Actions workflows can authenticate via Workload Identity Federation and manage my rules in Google SecOps, I created a new YARA-L rule in my GitHub repository. This triggered my GitHub Actions workflow that pushes rule updates to Google SecOps.

The output below shows that my GitHub Actions workflow authenticated to my Google Cloud environment successfully.

image.pngValidating authentication via Workload Identity Federation from GitHub Actions

The following images show that the GitHub Actions workflow has direct resource access to Google SecOps and was able to create the new rule successfully.

image.pngCreating a new rule via the Google SecOps API

image.pngViewing the new rule in Google SecOps

Finally, to validate that the attribute condition I configured earlier is restricting access to the workload identity pool, I changed the “assertion.repository_id” value in the CEL expression temporarily in the Google Cloud console and ran the GitHub Actions workflow again.

The output below shows that authentication failed. This is expected behavior. I changed the attribute condition back to its previous state.

image.pngValidating that authentication fails based on the attribute condition configured in the workload identity pool provider

Deleting the Service Account Key

The configuration of Workload Identity Federation with my GitHub Actions and Google SecOps environment is complete. It’s now safe to delete the service account key from my Google Cloud project and GitHub repository. I can also delete the service account itself if it’s not used elsewhere in my environment.

Wrap Up

That’s it for part two where we learned how to improve an organization’s security posture by configuring Workload Identity Federation as an alternative authentication method to service account keys. Now it’s time to focus on monitoring and detection.

Join me in part three where I’ll explain how to use Google SecOps to understand service account key usage and detect service account key creation in a Google Cloud organization.

Additional Resources