Keyless Access Scoped to Callers You Meant
attribute_condition is optional, and the issuer is not yours - so omitting it on a GitHub Actions provider trusts every workflow in every repository belonging to anyone on GitHub. It works perfectly in testing, because your workflow is one of the ones it admits. Refused here, along with a wildcard principalSet.
Verification
Static-verifiedPassed: validated and lint-clean (provider-schema-validated for AWS/Azure/GCP; Terraform-language lint elsewhere).
Conformance
- Static validation (fmt · validate · tflint)
- Security scan clean (Checkov)
- Plan tests (mocked: validation rules · outputs)
Provenance
- SHA-256 checksum
- Signature (pending)
Functional
- Live test pending (no cloud run yet)
Last verified 2026-09-13 · how we verify
Use it from the registry
terraform · opentofumodule "workload_identity_federation" {
source = "www.iac-bazaar.com/iac-bazaar/gcp-workload-identity-federation/gcp"
version = "1.0.0"
}Needs a registry token from /account/tokens. The module itself is free; the account is what identifies you. Full setup: registry docs.
Inputs & outputs
Create a free account to read this module's contract
The declared contract - every input name, type, default and description, plus every output - is shown to signed-in accounts, not to anonymous visitors.
A free account sees the contract of every module in the catalogue. There is no subscription and nothing to buy - the modules are free to download, and they run under Vizier.
Documentation
gcp-workload-identity-federation
Keyless access from outside Google, scoped to the callers you actually meant.
Works with Terraform and OpenTofu (>= 1.6), google provider
>= 6.0, < 7.0.
attribute_condition is optional, and omitting it is the worst default in
this service. The issuer is not yours. For GitHub Actions the issuer is
GitHub's, so "any token this issuer signs" means any workflow, in any
repository, belonging to anybody, anywhere on GitHub - all of it able to
impersonate whatever service account the pool grants. The setup works perfectly
in testing, because your workflow is one of the ones it admits, and that is
exactly why this one gets shipped. A precondition refuses a provider with no
condition, and a second refuses a GitHub provider whose condition never
mentions the repository or its owner, since a condition that only checks how
a token was issued has not narrowed who.
The member string is the other half. A binding to
principalSet://…/attribute.repository/my-org/my-repo is one repository;
principalSet://…/* is everything the pool admits. Those differ by very little
in a place nobody reads twice, so a precondition refuses the wildcard and
wildcard_grants is an output that should stay empty.
This exists to replace service account keys, which is the point. A downloaded key is a credential with no expiry that lives in somebody's CI settings forever and survives every offboarding. A federated token lasts an hour and cannot be lifted out of the workflow that earned it - provided the condition above is real.
Pin assertion.sub where you can. GitHub's subject claim already carries
the repository and the ref in one value (repo:org/repo:ref:refs/heads/main), so
there is no way to satisfy half of it. Separate assertion.repository and
assertion.ref clauses are equivalent and more flexible; repository_owner
alone is the weakest form still worth having, because it admits every repository
in your organisation including one a contractor opened this morning.
Smaller things: google.subject must be mapped and Google's error does not say
which key is missing, so a precondition names it; and a pool id cannot be reused
for 30 days after deletion, so it is worth picking a name you can live with.
Verification
Static validation runs tofu fmt, init, validate, tflint and checkov.
This module has not yet had a live test, so it is published as statically
validated with its live test pending and does not carry the live-tested mark.
Usage code & full reference need an account
The complete copy-paste usage, the full input/output reference, and operational notes are free with an account - shown here and bundled in the download. Sign in and this section fills in.
- Usage
Related modules
gcp-service-perimeter
spec is the dry-run configuration and status is the enforced one - two blocks of the same shape, and a perimeter with only a spec is evaluated on every request, logs violations, and blocks nothing. Empty restricted_services is the other way to have none: the perimeter exists, covers the projects, and governs no API.
gcp-cloud-armor
A global Cloud Armor WAF policy with preconfigured OWASP SQLi and XSS rules enforcing by default, an optional per-client rate limit, and custom IP allow/deny rules - attachable to many backends.
gcp-binary-authorization
DRYRUN_AUDIT_LOG_ONLY admits the image and writes a line about it while the console shows the policy as configured. ALWAYS_ALLOW is the other way to have nothing: a valid, enforced policy that admits everything. Both have to be right, so one output reports over both.
gcp-service-accounts-iam
Service accounts with least-privilege project/resource IAM and optional Workload Identity Federation for keyless CI/CD (GitHub Actions).