gcp-ar-wif-binding
match (record)
{
"field": "iamPolicy.bindings",
"resource_type": "google.artifactregistry.Repository"
}
where
binding member starts with principalSet://iam.googleapis.com/ or principal://iam.googleapis.com/
binding role includes artifactregistry.repositories.uploadArtifacts
emit
| source type | ResourcePolicy |
|---|---|
| target type | FederatedIdentity |
| source | <ResourcePolicy of the Artifact Registry repository> |
| target | <FederatedIdentity / WIF principalSet or principal node> |
Narrative
Repository {repo.name} grants {role} to WIF identity {wif_member}; an external OIDC workload (e.g. GitHub Actions) satisfying the attribute condition in the WIF pool can push to {repo.name} without a GCP service account key - supply-chain injection vector from external CI.
Raw rule rules/explicit/gcp-artifactregistry.yaml
id: gcp-ar-wif-binding
emits: TrustsExternalIdentity
applies_to:
- gcp
match_record:
resource_type: google.artifactregistry.Repository
field: iamPolicy.bindings
where:
- binding member starts with principalSet://iam.googleapis.com/ or principal://iam.googleapis.com/
- binding role includes artifactregistry.repositories.uploadArtifacts
emit:
source_type: ResourcePolicy
target_type: FederatedIdentity
source: <ResourcePolicy of the Artifact Registry repository>
target: <FederatedIdentity / WIF principalSet or principal node>
api_source: artifactregistry.projects.locations.repositories.getIamPolicy
evidence_field: iamPolicy.bindings[].members (principalSet:// or principal://)
properties:
wif_member: <principalSet:// or principal:// string>
role: <binding role>
grants_upload: 'true'
narrative: "Repository {repo.name} grants {role} to WIF identity {wif_member}; an external OIDC workload\
\ (e.g. GitHub Actions) satisfying the attribute condition in the WIF pool can push to {repo.name}\
\ without a GCP service account key \u2014 supply-chain injection vector from external CI."