Skip to content

credctl Now Supports GCP: One Hardware Identity, Two Clouds

When we launched credctl, the pitch was simple: replace the plaintext AWS keys on your laptop with hardware-bound credentials using the Secure Enclave. No keys on disk. Ever.

Today, we’re extending that to GCP.

credctl auth --provider gcp exchanges the same hardware-bound JWT for short-lived GCP access tokens via Workload Identity Federation. Same Secure Enclave key. Same OIDC provider. No new infrastructure. No GCP SDK dependency.

If you work across AWS and GCP — and an increasing number of teams do — you now have a single device identity that works with both clouds. One credctl init, one OIDC provider, two clouds.

The security model is identical to AWS:

  • Private key lives in the Secure Enclave. Can’t be exported.
  • Credentials are short-lived (1 hour).
  • Touch ID required for every signing operation.
  • Nothing on disk to steal.

The difference is in the exchange mechanism. AWS uses a single AssumeRoleWithWebIdentity call. GCP uses a two-step exchange:

sequenceDiagram
participant CLI as credctl CLI
participant SE as Secure Enclave
participant STS as GCP STS
participant IAM as GCP IAM Credentials
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)
  1. The CLI signs a JWT with the Secure Enclave key (same as AWS, but with GCP’s Workload Identity Provider URI as the audience).
  2. GCP STS validates the JWT against the OIDC provider and returns a federated access token.
  3. The CLI exchanges the federated token for a service account access token via the IAM Credentials API.

The result: a standard GCP OAuth2 access token, usable with gcloud, Terraform, and all GCP client libraries.

You need credctl installed and initialised (credctl init), and AWS OIDC infrastructure deployed (credctl setup aws). GCP reuses the same OIDC provider — the CloudFront-hosted discovery documents that AWS validates are the same ones GCP validates.

You also need a GCP service account with the roles you want credctl to assume.

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

This single command handles everything: OIDC hosting on GCS, Workload Identity Pool, OIDC Provider, service account binding, and generating the credential config file at ~/.credctl/gcp-credentials.json.

Terminal window
export GOOGLE_APPLICATION_CREDENTIALS=~/.credctl/gcp-credentials.json
gcloud storage ls

Or authenticate gcloud directly:

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

That’s it. Every GCP API call now uses hardware-bound, short-lived credentials.

If your team prefers infrastructure-as-code over CLI setup, there’s a Terraform module at deploy/terraform-gcp/:

module "credctl_gcp" {
source = "github.com/credctl/credctl//deploy/terraform-gcp"
project_id = "my-project"
device_fingerprint = "SHA256:oKz3i9Tg..."
issuer_url = "https://d1234.cloudfront.net"
service_account_roles = [
"roles/storage.objectViewer",
"roles/bigquery.dataViewer",
]
}

This creates the same resources as credctl setup gcp — Workload Identity Pool, OIDC Provider, Service Account, and IAM bindings — but version-controlled and repeatable.

One design decision worth highlighting: credctl has zero GCP SDK dependency. The GCP STS token exchange and IAM Credentials API calls are implemented with Go’s net/http stdlib. This keeps the binary small, the dependency tree minimal, and the attack surface narrow.

The same is true for AWS — credctl’s only external Go dependency is spf13/cobra for CLI argument parsing.

When we chose OIDC federation over AWS Roles Anywhere (see the technical deep dive), cross-cloud portability was a key reason. OIDC is a standard. AWS, GCP, and Azure all accept OIDC tokens for credential exchange. By building on OIDC, adding GCP support meant implementing the GCP-specific exchange protocol — not rebuilding identity infrastructure.

The only code change to the shared JWT package was making the audience claim configurable. AWS uses sts.amazonaws.com. GCP uses the Workload Identity Provider URI. Same key, same signature, different audience.

  • Azure Federated Identity Credentials — the third major cloud. Same OIDC architecture, Azure-specific exchange.
  • Linux TPM 2.0 — the same multi-cloud identity on Linux workstations.
  • Credential caching daemon — avoid redundant STS calls and Touch ID prompts within the credential TTL. (This is already available as an experimental feature: credctl daemon start.)

Update to the latest credctl:

Terminal window
brew upgrade credctl/tap/credctl

If you’re using credctl with both AWS and GCP, we’d love to hear about your experience. Open an issue or start a discussion on GitHub.