GCP CI/CD
Set up Workload Identity Federation (WIF) for GitHub Actions to authenticate with GCP without storing service account keys.
For generating workflow files and general CI/CD setup, see CI/CD Setup.
Overview
WIF allows GitHub Actions to authenticate using short-lived OIDC tokens instead of exported key files. The GitHub Actions runner gets a token from GitHub, exchanges it for GCP credentials, and authenticates as the service account.
Benefits:
- No secret keys stored in GitHub
- Short-lived tokens (valid only during the workflow run)
- Full auditability under the service account identity
Prerequisites
Complete Account Setup first. You need a service account with roles already configured before setting up CI/CD.
Setup
1. Enable Required APIs
- Go to APIs & Services
- Search and enable:
- IAM Service Account Credentials API
- Security Token Service API
2. Create Workload Identity Pool
- Go to IAM & Admin > Workload Identity Federation
- Click Create Pool
- Name:
github-pool - Click Continue
3. Add GitHub Provider
-
Provider: OpenID Connect (OIDC)
-
Provider name:
github-provider -
Provider ID:
github-provider(auto-generated from name — keep the default) -
Issuer URL:
https://token.actions.githubusercontent.com -
Audiences: Default audience
-
Attribute mapping:
google.subject=assertion.subattribute.repository=assertion.repository
-
Attribute condition (CEL) — choose one:
Repository only (any branch can deploy):
Repository + branch (only
maincan deploy):Replace
YOUR_ORG/YOUR_REPOwith your GitHub repository (e.g.,myorg/myapp). -
Click Save
4. Grant Service Account Access
- Go to IAM & Admin > Service Accounts
- Click on your deploy service account (don't see one? Complete Account Setup first)
- Go to the Principals with access tab
- Click Grant Access
- New principal:
principalSet://iam.googleapis.com/projects/{PROJECT_NUMBER}/locations/global/workloadIdentityPools/github-pool/attribute.repository/{GITHUB_ORG}/{GITHUB_REPO} - Role: Workload Identity User
- Click Save
Find your project number in Project Settings.
GitHub Secrets
Add these secrets in your GitHub repository under Settings > Secrets and variables > Actions.
Secret names use the pattern GCP_{TYPE}_{ENV} where {ENV} is the UPPERCASE environment name from your .tsdevstack/config.json.
The framework has no naming convention for environments. dev, staging, prod are common choices, but you can use any name. The examples below use dev and prod.
Example: dev environment
Example: prod environment
Repeat for each environment you have configured.
Private npm packages — NPM_TOKEN (optional, single global secret)
If your project depends on private npm packages, add a single NPM_TOKEN repository secret — not per-environment. Registry tokens identify your developer / org account, not a deployment target, so the same value works for every env.
The token is auto-detected and wired through generated workflows when an .npmrc exists at your project root. See CI/CD Setup — Private npm packages for the full setup.
User Secrets (Required Before First Deployment)
The CI workflow pushes framework-generated secrets automatically (cloud-secrets:push --skip-user-secrets), but user secrets must be created manually in GCP Secret Manager before the first CI deployment.
Without these secrets, deployment will fail. The CI pipeline cannot prompt for interactive input.
Creating Secrets in GCP Console
- Go to Secret Manager and select your project
- If Secret Manager is not enabled, click Enable when prompted
- Click Create Secret
- Name: Enter the full secret name (e.g.,
myapp-shared-DOMAIN) - Secret value: Enter the value (e.g.,
example.com) - Leave all other settings as default
- Click Create Secret
Repeat for each required secret in each environment.
Secret Naming Format
Secrets in GCP Secret Manager follow the format: {project-name}-{scope}-{KEY}
Where {project-name} is the project.name from your .tsdevstack/config.json.
For example, if your project name is myapp:
Required User Secrets
These are the minimum secrets required by the framework:
Your project may have additional user secrets (e.g., STRIPE_KEY, TWILIO_SID). Any secret defined in .secrets.user.json that is not framework-generated must also be created manually in GCP Secret Manager before deployment. Use the same naming format: {project-name}-shared-{KEY}.
Alternative: Using the CLI
If you have local credentials configured (see Account Setup), you can push all user secrets from your machine:
This will prompt for DOMAIN, RESEND_API_KEY, EMAIL_FROM, and any custom secrets interactively.
Workflow Authentication Pattern
The generated workflows authenticate using the google-github-actions/auth action:
The id-token: write permission is required — without it, GitHub won't issue the OIDC token and authentication will fail silently.
Security Best Practices
- Use separate service accounts per environment (separate GCP projects)
- Restrict repository access via attribute conditions on the WIF provider
- Grant only the required roles to the deploy service account (see Account Setup)
Troubleshooting
WIF Authentication Fails
- Verify the provider path includes your project number (not project ID)
- Check the repository attribute mapping matches
{org}/{repo}exactly - Ensure the service account has the Workload Identity User role granted to the correct principal
Token Exchange Failed
Ensure the workflow has the id-token: write permission:
Service Account Does Not Exist
Verify the service account email format: <name>@<project-id>.iam.gserviceaccount.com
- Go to IAM & Admin > Service Accounts
- Check that the service account exists and the email matches what you set in
GCP_SA_{ENV}