gcp-sr-wif-writer-trust
A CSR repo IAM binding for a WIF principalSet/principal with source.repos.update grants an external OIDC identity (e.g. GitHub Actions) direct push access without any long-lived GCP key - supply-chain injection from external CI.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?repo is a CSR
ArtifactRepository
?repo_policy is a ResourcePolicy of the CSR repository
?repo_policy has an IAM binding for a WIF principal (member starts with principalSet://iam.googleapis.com/ or principal://iam.googleapis.com/)
the binding role or permissions include source.repos.update
emit
| source type | ResourcePolicy |
|---|---|
| target type | FederatedIdentity |
| source | ?repo_policy |
| target | <FederatedIdentity / WIF principalSet or principal> |
| permissions | source.repos.update |
| conditions | trust_relationship condition_expression |
| state logic | ACTIVE when the WIF binding attribute condition is BROAD or UNPINNED — the external assertion is easily satisfied (principalSet covers all pool identities, no specific subject constraint). CONDITIONAL(trust_relationship) when pinned to a specific external subject (e.g. a specific GitHub repo + branch ref), because the attacker must control a matching identity. BLOCKED if the WIF pool is disabled. Inherit weakest from the pool's trust posture. federation-chains::federation-maps-to-identity consumes this TrustsExternalIdentity + ExternalIdentityMapsTo to derive CanFederateAs -> CanEnterProject. |
Narrative
Repository {repo.name} grants source.repos.update to WIF identity {ext_identity.name}; an external OIDC workload (e.g. GitHub Actions) satisfying the attribute condition can push commits directly to {repo.name} without any GCP service account key - supply-chain injection from external CI into any Cloud Build trigger watching a branch in {repo.name}. federation-chains rolls up the CanFederateAs and CanEnterProject consequences.
Raw rule rules/derived/gcp/sourcerepos.yaml
id: gcp-sr-wif-writer-trust
emits: TrustsExternalIdentity
description: "A CSR repo IAM binding for a WIF principalSet/principal with source.repos.update grants\
\ an external OIDC identity (e.g. GitHub Actions) direct push access without any long-lived GCP key\
\ \u2014 supply-chain injection from external CI."
match:
- - repo: null
- HasPolicy
- repo_policy: null
where:
- ?repo is a CSR ArtifactRepository
- ?repo_policy is a ResourcePolicy of the CSR repository
- ?repo_policy has an IAM binding for a WIF principal (member starts with principalSet://iam.googleapis.com/
or principal://iam.googleapis.com/)
- the binding role or permissions include source.repos.update
emit:
source_type: ResourcePolicy
target_type: FederatedIdentity
source: ?repo_policy
target: <FederatedIdentity / WIF principalSet or principal>
permissions:
- source.repos.update
conditions:
- trust_relationship
- condition_expression
state_logic: "ACTIVE when the WIF binding attribute condition is BROAD or UNPINNED \u2014 the external\
\ assertion is easily satisfied (principalSet covers all pool identities, no specific subject constraint).\
\ CONDITIONAL(trust_relationship) when pinned to a specific external subject (e.g. a specific GitHub\
\ repo + branch ref), because the attacker must control a matching identity. BLOCKED if the WIF pool\
\ is disabled. Inherit weakest from the pool's trust posture. federation-chains::federation-maps-to-identity\
\ consumes this TrustsExternalIdentity + ExternalIdentityMapsTo to derive CanFederateAs -> CanEnterProject."
confidence: 0.85
derived_from:
- 'IAM binding on ?repo_policy: WIF principalSet/principal has source.repos.update'
- federation-chains::federation-maps-to-identity (for CanFederateAs consequence)
false_positive_note: "The strength depends entirely on the WIF attribute condition. A principalSet mapping\
\ google.subject == 'repo:org/repo:ref:refs/heads/main' is CONDITIONAL \u2014 the attacker must push\
\ code to that branch in that repo. A principalSet covering all pool identities (no attribute condition)\
\ is ACTIVE. Cite federation-chains for the CanFederateAs -> CanEnterProject roll-up; do not re-derive\
\ it here."
narrative: "Repository {repo.name} grants source.repos.update to WIF identity {ext_identity.name}; an\
\ external OIDC workload (e.g. GitHub Actions) satisfying the attribute condition can push commits\
\ directly to {repo.name} without any GCP service account key \u2014 supply-chain injection from external\
\ CI into any Cloud Build trigger watching a branch in {repo.name}. federation-chains rolls up the\
\ CanFederateAs and CanEnterProject consequences."