Introduction

Interacting with GCP or integrating Terraform deployments securely and efficiently into your CI/CD pipeline requires careful consideration, especially regarding authentication and permissions.

Direct Workload Identity Federation offers secure way to authenticate applications without relying on long-lived service account keys. By leveraging Workload Identity Federation, we can grant GitHub Actions access to Google Cloud (GCP) resources, minimizing security risks and improving operational efficiency. This blog post explores why using Workload Identity Federation is important, the role of GitHub in modern DevOps practices, and how to use GitHub Actions to interact with GCP securely.

Architecture Diagram

Why Use Direct Workload Identity Federation?

Principles of Workload Identity Federation

  1. Security: Traditional methods of authentication often involve distributing and managing long-lived credentials, which can pose significant security risks if compromised. Workload Identity Federation eliminates the need for these credentials by allowing short-lived tokens issued by an identity provider (like GitHub) to be exchanged for GCP access tokens.
  2. Scalability: As teams grow and projects scale, managing and rotating service account keys becomes cumbersome. Workload Identity Federation simplifies this by centralizing authentication management, making it easier to scale operations without compromising security.
  3. Compliance: Regulatory requirements often mandate stringent controls over access management. Workload Identity Federation provides a robust framework for enforcing access policies and maintaining audit trails, helping organizations stay compliant with industry standards.

The Role of GitHub in Modern DevOps

GitHub is a cornerstone of modern DevOps practices, offering a comprehensive platform for version control, collaboration, and continuous integration/continuous deployment (CI/CD). GitHub Actions, its integrated CI/CD service, enables developers to automate workflows directly within their repositories.

Advantages of Using GitHub Actions

  1. Centralized Management: GitHub Actions allows you to manage all CI/CD workflows in a single location, streamlining the development process and ensuring that all changes are tracked and auditable.
  2. Security and Compliance: By using GitHub Actions in combination with Workload Identity Federation, you can avoid distributing sensitive credentials. This setup ensures that only authorized workflows can interact with your cloud resources, enhancing security and compliance.
  3. Automation and Efficiency: Automating deployments through GitHub Actions reduces manual intervention, minimizes errors, and accelerates the delivery of features and updates.

Centralized Deployments with GitHub Actions

Centralizing deployments through GitHub Actions ensures that all changes to your infrastructure are managed through code reviews and automated workflows, eliminating the risks associated with "clickops" (manual operations via the cloud console). This approach promotes a disciplined and auditable deployment process.

Setting Up Workload Identity Federation

Create a Workload Identity Pool and Provider

In GCP, create a Workload Identity Pool and Provider to link GitHub as an identity provider.

Create an identity pool

Add a provider to the pool

We need to set the issuer of the token to https://token.actions.githubusercontent.com. This ensures that the tokens are correctly identified as coming from GitHub Actions.

Configure provider attributes

We can choose which attributes from the GitHub token to retain and map to the GCP token. This allows us to define the information passed between GitHub and GCP during authentication.

It's essential to set a robust authentication condition to ensure security. For instance, you can configure the condition to assertion.repository_owner == 'AlexanderHose'. This ensures that only tokens from specified repository owners or organizations are allowed. This condition helps in restricting access and enhancing security by limiting the scope of valid tokens.

Configure provider attributes

Granting access to GCP resources

To allow access to GCP resources via the Workload Identity Pool, you need to grant the necessary roles to the principalSet. This can be done either through the GCP Console UI or using the gcloud command-line tool.

Assign Roles via the UI: Navigate to the GCP service, select the appropriate resource, and add the principalSet with the necessary roles in the permissions section.

Add principalSet for secret

Using the gcloud CLI: You can also grant roles using the following command:

gcloud secrets add-iam-policy-binding "my-secret" 
--project="<ProjectName>" --role="roles/secretmanager.secretAccessor" --member="principalSet://iam.googleapis.com/projects/<ProjectID>/locations/global/workloadIdentityPools/<ProviderName>/attribute.repository/<GitHubName>/<RepositoryName>"

Service Availability: Not all GCP services support principalSet directly. For services that do not, you will need to use a service account in conjunction with Workload Identity Federation.

Understanding the Difference Between Principal and PrincipalSet

Understanding the distinction between principal and principalSet is crucial for designing effective and secure access policies. These concepts define how identities are granted permissions to access resources, but they operate at different levels of granularity and flexibility.

Principal

principal is a single identity that can be granted roles to access GCP resources. This identity can take several forms, including a user, service account, group, or domain. For example, a principal could be a specific user (user:[email protected]), a service account (serviceAccount:[email protected]), a group (group:[email protected]), or an entire domain (domain:example.com). Principals are used when you want to grant permissions to specific, individual identities. This approach ensures tight control over access, as each identity must be explicitly defined.

PrincipalSet

In contrast, a principalSet is a collection of principals grouped together based on specific attributes or conditions. This concept allows you to define broader access policies that apply to multiple principals sharing common characteristics. PrincipalSets are particularly useful for federated identities, such as those coming from an external identity provider like GitHub Actions. For instance, a principalSet might be configured to include all identities from a particular GitHub repository using a workload identity pool (principalSet://iam.googleapis.com/projects/<ProjectName>/locations/global/workloadIdentityPools/<ProviderName>/attribute.repository/<GitHubName>/<RepositoryName>). This approach is more flexible than using individual principals, as it dynamically includes multiple identities based on the specified attributes.

Setup GitHub Actions Workflow

Integrating GitHub Actions with GCP allows you to automate various tasks, such as retrieving secrets, which is essential for maintaining security and efficiency in your development workflow. This method ensures centralized and controlled access management, reducing the risks associated with manual operations.

Here's the complete GitHub Actions workflow configuration:

name: Deploy code to GCP

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest

    permissions:
      id-token: write
      contents: read

    steps:
    - name: 'Checkout code'
      uses: 'actions/checkout@v2'

    - name: 'Authenticate with GCP'
      id: auth
      uses: 'google-github-actions/auth@v2'
      with:
        project_id: 'security-alexanderhose'
        workload_identity_provider: 'projects/243190957191/locations/global/workloadIdentityPools/github-actions-provider/providers/github-actions-pool'
        
    - name: 'Set up Cloud SDK'
      uses: 'google-github-actions/setup-gcloud@v2'
      
    - name: 'Describe Secrets'
      run: |
        gcloud secrets describe "my-secret" --project="security-alexanderhose"

Detailed Breakdown of the Workflow

The workflow is configured to run on several triggers:

  • Push: Triggers the workflow on pushes to the main branch.
  • Pull Request: Triggers the workflow on pull request events targeting the main branch.
  • Manual Trigger: Allows the workflow to be triggered manually from the Actions tab in GitHub.
Job Configuration

The workflow contains a single job named build, which runs on an ubuntu-latest runner. The job requires permissions to write ID tokens and read repository contents.

Steps in the Workflow

Checkout Code: This step uses the actions/checkout@v2 action to clone the repository, ensuring that the latest code is available for the workflow

- name: 'Checkout code'
  uses: 'actions/checkout@v2

Authenticate with GCP: This step uses the google-github-actions/auth@v2 action to authenticate with GCP using Workload Identity Federation. This step requires the project ID and the workload identity provider details.

- name: 'Authenticate with GCP'
  id: auth
  uses: 'google-github-actions/auth@v2'
  with:
    project_id: 'security-alexanderhose'
    workload_identity_provider: 'projects/243190957191/locations/global/workloadIdentityPools/github-actions-provider/providers/github-actions-pool'

Set Up Cloud SDK: This step uses the google-github-actions/setup-gcloud@v2 action to set up the Google Cloud SDK, enabling the use of gcloud commands in subsequent steps.

- name: 'Set up Cloud SDK'
  uses: 'google-github-actions/setup-gcloud@v2'

Describe Secrets: This step runs a gcloud command to describe a secret in Google Cloud Secret Manager. It retrieves the details of the secret named my-secret in the specified project.

- name: 'Describe Secrets'
  run: |
    gcloud secrets describe "my-secret" --project="security-alexanderhose"

Debugging OIDC Tokens

To ensure the OIDC token setup works correctly, you can add a debugging step to print the OIDC token. This should be done temporarily and removed after verification to avoid exposing sensitive information.

- name: 'Print OIDC Token'
  run: |
    echo "Retrieving OIDC Token..."
    TOKEN=$(curl -s -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL" | jq -r .value)
    echo "OIDC Token: $TOKEN"
    echo "Decoded Token:"
    echo $TOKEN | cut -d '.' -f2 | base64 --decode | jq .

This debugging step helps you verify that the authentication process is working correctly by displaying the OIDC token and its decoded content. A sample token would look like this:

{
  "jti": "f11937de-d4a9-463e-8170-b6eefd034d43",
  "sub": "repo:AlexanderHose/gcp-deployment:ref:refs/heads/main",
  "aud": "https://github.com/AlexanderHose",
  "ref": "refs/heads/main",
  "sha": "355243140d9a50cf2e275f89114174d123e349e0",
  "repository": "AlexanderHose/gcp-deployment",
  "repository_owner": "AlexanderHose",
  "repository_owner_id": "12799633",
  "run_id": "10237897672",
  "run_number": "11",
  "run_attempt": "1",
  "repository_visibility": "private",
  "repository_id": "834791668",
  "actor_id": "12799633",
  "actor": "AlexanderHose",
  "workflow": "Deploy code to GCP",
  "head_ref": "",
  "base_ref": "",
  "event_name": "push",
  "ref_protected": "false",
  "ref_type": "branch",
  "workflow_ref": "AlexanderHose/gcp-deployment/.github/workflows/gcp-terraform.yml@refs/heads/main",
  "workflow_sha": "355243140d9a50cf2e275f89114174d123e349e0",
  "job_workflow_ref": "AlexanderHose/gcp-deployment/.github/workflows/gcp-terraform.yml@refs/heads/main",
  "job_workflow_sha": "355243140d9a50cf2e275f89114174d123e349e0",
  "runner_environment": "github-hosted",
  "iss": "https://token.actions.githubusercontent.com",
  "nbf": 1722790588,
  "exp": 1722791488,
  "iat": 1722791188
}

After setting up your workflow, running it successfully will result in a series of green checkmarks in the Actions tab of your GitHub repository. Below is a screenshot showing a successful run of the pipeline, which includes the steps for checking out the code, authenticating with GCP, setting up the Cloud SDK, and describing the secret.

GitHub Actions Pipeline

Conclusion 🎓

This GitHub Actions workflow centralizes and automates the retrieval of secrets from GCP, enhancing security and efficiency by leveraging Workload Identity Federation. This approach mitigates the risks associated with manual operations and ensures a streamlined, secure workflow, aligning with best practices for modern DevOps processes. Moreover, the same principles and configurations can be extended to deploy code to GCP, providing a robust and scalable solution for CI/CD pipelines.

Share this post