Skip to content

GCP setup guide

credctl authenticates to GCP using Workload Identity Federation. It signs a JWT with the Secure Enclave key and exchanges it for short-lived GCP access tokens via a two-step process: STS token exchange, then service account impersonation.

This guide covers two approaches:

  1. Automated (recommended) — credctl setup gcp does everything in one command
  2. Manual — deploy the infrastructure yourself using Terraform

credctl publishes your device’s public key as a JWKS at an HTTPS endpoint. GCP’s Workload Identity Federation validates the JWT signature against the published JWKS and exchanges it for GCP access tokens.

sequenceDiagram
participant SE as Secure Enclave
participant CLI as credctl CLI
participant STS as GCP STS
participant IAM as GCP IAM Credentials
Note over SE,CLI: Each authentication
CLI->>SE: Sign JWT (Touch ID)
SE-->>CLI: Signed JWT
CLI->>STS: ExchangeToken (JWT)
STS-->>CLI: Federated access token
CLI->>IAM: GenerateAccessToken
IAM-->>CLI: OAuth2 access token (1h)

The two-step exchange is handled transparently by credctl auth --provider gcp or by GCP client libraries when using the credential config file.

A single command sets up everything — OIDC hosting on GCS, the Workload Identity Pool and Provider, the service account binding, and the credential config file:

Terminal window
credctl setup gcp --service-account credctl@my-project.iam.gserviceaccount.com

Enable the required APIs before running setup:

Terminal window
gcloud services enable iam.googleapis.com sts.googleapis.com iamcredentials.googleapis.com

Create a service account if you don’t have one:

Terminal window
gcloud iam service-accounts create credctl \
--display-name="credctl Device Service Account"

Grant it the roles you need:

Terminal window
gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:credctl@my-project.iam.gserviceaccount.com" \
--role="roles/storage.objectViewer"
  1. Creates a GCS bucket and uploads OIDC discovery documents
  2. Creates a Workload Identity Pool (credctl-pool by default)
  3. Creates an OIDC Provider within the pool, configured with the GCS-hosted issuer URL
  4. Binds the service account with roles/iam.workloadIdentityUser
  5. Generates the GCP credential config file (~/.credctl/gcp-credentials.json)
  6. Writes configuration to ~/.credctl/config.json

If you already have an OIDC issuer configured (e.g., from credctl setup aws), the command reuses it automatically and skips GCS bucket creation.

FlagTypeDefaultDescription
--service-accountstringService account email to impersonate. Required.
--projectstringgcloud defaultGCP project ID.
--pool-idstringcredctl-poolWorkload Identity Pool ID.
--provider-idstringcredctl-providerWorkload Identity Provider ID.
--issuer-urlstringauto-detectedOIDC issuer URL. Defaults to any existing issuer URL in your config.
Using GCP project: my-project
Creating GCS bucket 'credctl-oidc-my-project'...
Uploading OIDC documents...
Creating Workload Identity Pool 'credctl-pool'...
Creating OIDC Provider 'credctl-provider'...
Binding service account 'credctl@my-project.iam.gserviceaccount.com'...
Generating credential config file...
GCP setup complete.
Issuer URL: https://storage.googleapis.com/credctl-oidc-my-project
Credential file: ~/.credctl/gcp-credentials.json
Test it:
export GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1
gcloud auth login --cred-file=~/.credctl/gcp-credentials.json
gcloud storage ls

A Terraform module is available at deploy/terraform-gcp/ in the credctl repo.

Create a terraform.tfvars file:

project_id = "my-project"
device_fingerprint = "SHA256:aBcDeFg..."
issuer_url = "https://storage.googleapis.com/credctl-oidc-my-project"
service_account_roles = [
"roles/storage.objectViewer",
"roles/bigquery.dataViewer",
]

Get your device fingerprint with credctl status.

Terminal window
cd deploy/terraform-gcp
terraform init
terraform apply

Add the GCP block to ~/.credctl/config.json using the Terraform outputs:

{
"gcp": {
"project_number": "123456789",
"workload_pool_id": "credctl-pool",
"provider_id": "credctl-provider",
"service_account_email": "credctl@my-project.iam.gserviceaccount.com",
"issuer_url": "https://storage.googleapis.com/credctl-oidc-my-project"
}
}
Terminal window
credctl auth --provider gcp
Terminal window
export GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1
gcloud auth login --cred-file=~/.credctl/gcp-credentials.json
gcloud storage ls
Terminal window
export GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1
export GOOGLE_APPLICATION_CREDENTIALS=~/.credctl/gcp-credentials.json
gcloud storage ls

This works with any tool that supports GCP Application Default Credentials — Terraform, all GCP client libraries (Go, Python, Node.js, Java), and kubectl with the gke-gcloud-auth-plugin.

Install gcloud from cloud.google.com/sdk/docs/install.

”Permission denied on Workload Identity Pool creation”

Section titled “”Permission denied on Workload Identity Pool creation””

You need the iam.workloadIdentityPools.create permission. Grant the roles/iam.workloadIdentityPoolAdmin role or use a project owner account.

The OIDC issuer URL must be reachable from GCP. Verify it serves the discovery document:

Terminal window
curl https://storage.googleapis.com/credctl-oidc-my-project/.well-known/openid-configuration

Audience mismatch between the JWT and the Workload Identity Provider. Check the audience in your config with credctl status and compare it to the provider’s allowed_audiences.

”generateAccessToken permission denied”

Section titled “”generateAccessToken permission denied””

The service account is missing the roles/iam.workloadIdentityUser IAM binding from the Workload Identity Pool principal. Re-run credctl setup gcp or add the binding manually.

Enable the required APIs:

Terminal window
gcloud services enable iam.googleapis.com sts.googleapis.com iamcredentials.googleapis.com

“Executables need to be explicitly allowed”

Section titled ““Executables need to be explicitly allowed””

Set the environment variable that gcloud requires for executable-sourced credentials:

Terminal window
export GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1

Add this to your shell profile (.zshrc / .bashrc) so it persists.

This is a known bug in gcloud SDK versions 560+. It affects gcloud storage ls, gcloud projects describe, and other commands when using executable-sourced credentials.

Workaround: Use gcloud auth login --cred-file instead of GOOGLE_APPLICATION_CREDENTIALS:

Terminal window
export GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES=1
gcloud auth login --cred-file=~/.credctl/gcp-credentials.json

This authenticates gcloud with the credential file. Subsequent gcloud commands will work without setting GOOGLE_APPLICATION_CREDENTIALS.

GCP client libraries (Go, Python, Node.js, Java) and Terraform are not affected — this is a gcloud-specific issue.

Run credctl setup gcp or add the GCP configuration block to ~/.credctl/config.json manually.

See the full troubleshooting guide for more errors and solutions.