gcp-ar-wif-writer-trust
An Artifact Registry repo IAM binding for a Workload Identity Federation principalSet/principal with uploadArtifacts grants an external OIDC identity (e.g. GitHub Actions) direct push access - supply-chain from external CI into GCP workloads.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?repo_policy is a
ResourcePolicy of an Artifact Registry repository ?repo
?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 artifactregistry.repositories.uploadArtifacts
node_type(?repo) in [ContainerRegistry, ArtifactRepository]
emit
| source type | ResourcePolicy |
|---|---|
| target type | FederatedIdentity |
| source | ?repo_policy |
| target | <FederatedIdentity / WIF principalSet or principal> |
| permissions | artifactregistry.repositories.uploadArtifacts |
| conditions | trust_relationship condition_expression |
| state logic | ACTIVE when the trust condition on the WIF binding is BROAD or UNPINNED (the external identity assertion is easily satisfied — e.g. the principalSet covers all identities in the WIF pool, or the attribute mapping has no specific subject constraint). CONDITIONAL(trust_relationship) when the binding is pinned to a specific subject (e.g. a specific GitHub repo + branch ref), because the attacker must control an identity matching that subject. BLOCKED if the WIF pool is disabled or the pool's OIDC issuer is not trusted. Inherit weakest from the WIF pool's trust posture. |
Narrative
Repository {repo.name} grants artifactregistry.repositories.uploadArtifacts to WIF identity {ext_identity.name}; an external OIDC workload (e.g. GitHub Actions runner) satisfying the attribute condition can push a malicious image directly to {repo.name} without any GCP service account key - supply-chain injection from external CI.
Raw rule rules/derived/gcp/artifactregistry.yaml
id: gcp-ar-wif-writer-trust
emits: TrustsExternalIdentity
description: "An Artifact Registry repo IAM binding for a Workload Identity Federation principalSet/principal\
\ with uploadArtifacts grants an external OIDC identity (e.g. GitHub Actions) direct push access \u2014\
\ supply-chain from external CI into GCP workloads."
match:
- - repo: null
- HasPolicy
- repo_policy: null
where:
- ?repo_policy is a ResourcePolicy of an Artifact Registry repository ?repo
- ?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 artifactregistry.repositories.uploadArtifacts
- node_type(?repo) in [ContainerRegistry, ArtifactRepository]
emit:
source_type: ResourcePolicy
target_type: FederatedIdentity
source: ?repo_policy
target: <FederatedIdentity / WIF principalSet or principal>
permissions:
- artifactregistry.repositories.uploadArtifacts
conditions:
- trust_relationship
- condition_expression
state_logic: "ACTIVE when the trust condition on the WIF binding is BROAD or UNPINNED (the external\
\ identity assertion is easily satisfied \u2014 e.g. the principalSet covers all identities in the\
\ WIF pool, or the attribute mapping has no specific subject constraint). CONDITIONAL(trust_relationship)\
\ when the binding is pinned to a specific subject (e.g. a specific GitHub repo + branch ref), because\
\ the attacker must control an identity matching that subject. BLOCKED if the WIF pool is disabled\
\ or the pool's OIDC issuer is not trusted. Inherit weakest from the WIF pool's trust posture."
confidence: 0.85
derived_from:
- 'gcp-ar-wif-binding (explicit: TrustsExternalIdentity from IAM binding)'
false_positive_note: "The strength of this edge depends entirely on the WIF attribute condition. A principalSet\
\ that maps `google.subject` to `repo:org/repo:ref:refs/heads/main` is CONDITIONAL \u2014 the attacker\
\ must push code to that specific branch. A principalSet covering all identities in the pool (no attribute\
\ condition) is ACTIVE. Only emit this rule when grants_upload is true; read-only WIF bindings (downloadArtifacts\
\ only) do not model supply-chain write risk and should not traverse this path for CanModifyCode derivations.\
\ Cite federation-chains for the CanFederateAs -> CanEnterProject roll-up; do not re-derive it here.\
\ The push permission itself is the Artifact Registry fact; the federation trust is the GCP WIF posture."
narrative: "Repository {repo.name} grants artifactregistry.repositories.uploadArtifacts to WIF identity\
\ {ext_identity.name}; an external OIDC workload (e.g. GitHub Actions runner) satisfying the attribute\
\ condition can push a malicious image directly to {repo.name} without any GCP service account key\
\ \u2014 supply-chain injection from external CI."