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.
Why Use Direct Workload Identity Federation?
Principles of Workload Identity Federation
- 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.
- 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.
- 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
- 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.
- 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.
- 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.
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.
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.
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
A 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.
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.
Member discussion