If you are running production workloads on Google Cloud and still authenticating GitHub Actions using Service Account JSON keys, you are carrying unnecessary security risk and not following the best practises from google
This article explains why JSON keys are dangerous, what Workload Identity Federation (WIF) actually does, and how GitHub and GCP talk to each other under the hood - written for engineers and data scientists who already understand CI/CD but want the deeper identity story.
The Problem with JSON Keys
For years, the default pattern looked like this:
- Create a GCP service account
- Generate a JSON key
- Store it in GitHub Secrets
- Authenticate from CI
It was the best we've got while it violates almost every modern security principle. Because:
A Service Account JSON key is effectively a permanent password.
- It does not expire automatically
- It can be copied infinitely
- It works from anywhere on the internet
- Rotation is manual and often forgotten
If that key leaks, the attacker does not need GitHub, your repository, or your workflow. They authenticate directly against GCP.
This is why Google has been strongly nudging teams away from keys. Away from Long-Lived to Short-Lived credentials
Long-Lived vs Short-Lived Credentials (Quick 101)
This distinction is the entire reason Workload Identity Federation exists.
Long-Lived Credentials (JSON Keys)
Think of these as static secrets:
- Created once
- Valid until revoked
- Reusable outside their original context
- High blast radius They break zero-trust and least-privilege by design.
Short-Lived Credentials (OIDC Tokens)
Short-lived credentials behave like just-in-time access passes:
- Issued only when needed
- Automatically expire (usually ~1 hour)
- Bound to a specific workload execution
- Impossible to reuse later Even if intercepted, damage is limited. This is the security model WIF enables.
What Is Workload Identity Federation?
Workload Identity Federation allows external workloads (GitHub Actions, GitLab CI, Kubernetes, etc.) to access Google Cloud without service account keys.
Instead of trusting a file, GCP trusts an identity assertion.
- GitHub = Identity Provider (IdP)
- Google Cloud = Resource Provider No keys stored. No secrets copied. No rotation required.
What Actually Happens Between GitHub and GCP
Assume you already understand GitHub Actions jobs and runners. Here's the identity flow.
- GitHub Action job starts A runner begins executing your workflow. At this point, it has zero GCP credentials.
- GitHub issues an OIDC token Because your job has id-token: write permission, the runner can request an OpenID Connect (OIDC) token from GitHub. This token is: • Cryptographically signed by GitHub • Short-lived • Audience-restricted The token payload contains execution metadata: • Repository • Repository owner • Branch or tag • Workflow name • Job reference Think of this as a structured record describing who is running what, from where.
- Token is sent to Google Cloud STS The google-github-actions/auth action sends this token to Google Cloud's Security Token Service (STS).
- Google validates trust conditions GCP verifies: • Token signature (issued by GitHub) • Token audience • Attribute conditions you configured (repo, org, branch) This is where your security rules are enforced.
- Token exchange happens If validation passes, STS exchanges the GitHub OIDC token for a short-lived Google access token. No service account keys are created. Nothing is persisted.
- Service account impersonation The access token represents a temporary impersonation of a specific GCP service account. IAM permissions are evaluated exactly like any other GCP identity - but only for the token's lifetime.
- Access expires automatically When the job ends (or the token expires), access disappears. This is zero-trust implemented correctly.
Benefits
- No long-lived secrets in GitHub
- Credentials expire automatically
- Access can be restricted by repo, org, branch
- Easier audits and compliance
- No key rotation burden Security improves and operational friction drops.
Migration Overview
I recently migrated my Data ETL pipeline github action from JSON keys to WIF in under 20 minutes.
GCP Setup (One-Time)
You need to:
• Create a Workload Identity Pool
gcloud iam workload-identity-pools create "github-actions-pool" ...
• Create a Workload Identity Provider (GitHub)
• Allow a service account to be impersonated
gcloud iam workload-identity-pools providers create-oidc "github-actions-provider" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository" \
--attribute-condition="assertion.repository_owner == 'YOUR_ORG_NAME'"
Important: Attribute conditions are mandatory. This is where you lock down trust. By giving your org name you lock in the source which can be the provider so that this impersonation can happen only from github. Also not from any github repo but only from your your org repository.
GitHub Workflow Change
Enable OIDC:
permissions:
contents: read
id-token: write
Authenticate using WIF:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider
service_account: my-service-account@my-project.iam.gserviceaccount.com
That's it.
Final Thoughts
JSON keys were a necessary workaround in the past. They are technical debt today.
Workload Identity Federation gives you:
• Stronger security
• Smaller blast radius
• Less operational overhead
If Google is recommending WIF, it's the new baseline of dev sec ops
Glossary
Service Account
Non-human identity in GCP used by workloads.
Service Account JSON Key
Long-lived private key tied to a service account.
OIDC (OpenID Connect)
Identity layer on OAuth 2.0 using signed tokens.
OIDC Token (JWT)
Short-lived, signed token containing identity claims.
Identity Provider (IdP)
Entity that issues identity tokens (GitHub).
Workload Identity Federation
GCP mechanism for trusting external identities.
Workload Identity Pool
Container for external identities in GCP.
Workload Identity Provider
Defines how GCP validates external tokens.
STS (Security Token Service)
Exchanges external tokens for GCP access tokens.
Service Account Impersonation
Temporarily acting as a service account without keys.
Zero-Trust
Every access is verified; nothing is trusted by default.
Top comments (0)