gcp-wif-add-workload-user-binding

setIamPolicy on a ServiceAccount lets a principal add/loosen the workloadIdentityUser binding that maps an external WIF subject to the SA.

derived gcp emits CanModifyTrust

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanModifyTrust {'sa': None}

where

node_type(?sa) == ServiceAccount ?principal has EFFECTIVE iam.serviceAccounts.setIamPolicy on ?sa a WIF pool/provider exists whose principalSet:// members could be bound to ?sa

emit

source typeIdentity
target typeServiceAccount
source?principal
target?sa
permissionsiam.serviceAccounts.setIamPolicy roles/iam.workloadIdentityUser
conditionsiam_permission
state logicACTIVE for the trust-write when the principal has effective iam.serviceAccounts.setIamPolicy on ?sa and no deny policy denies it. Becomes a realized federation only once a WIF provider accepts an attacker-controllable subject the new/loosened principalSet:// binding resolves — chain via rule 1. BLOCKED if an IAM deny policy denies setIamPolicy at the SA scope.

Narrative

{principal.name} can set the IAM policy of {sa.name} (iam.serviceAccounts.setIamPolicy) and add or broaden a roles/iam.workloadIdentityUser binding for a principalSet:// member an attacker-controlled external subject satisfies - wiring WIF impersonation of {sa.name}.

Raw rule rules/derived/gcp/wif.yaml

id: gcp-wif-add-workload-user-binding
emits: CanModifyTrust
description: setIamPolicy on a ServiceAccount lets a principal add/loosen the workloadIdentityUser binding
  that maps an external WIF subject to the SA.
applies_to:
- gcp
match:
- - principal: null
  - CanModifyTrust
  - sa: null
where:
- node_type(?sa) == ServiceAccount
- ?principal has EFFECTIVE iam.serviceAccounts.setIamPolicy on ?sa
- a WIF pool/provider exists whose principalSet:// members could be bound to ?sa
emit:
  source_type: Identity
  target_type: ServiceAccount
  source: ?principal
  target: ?sa
  permissions:
  - iam.serviceAccounts.setIamPolicy
  - roles/iam.workloadIdentityUser
  conditions:
  - iam_permission
  state_logic: "ACTIVE for the trust-write when the principal has effective iam.serviceAccounts.setIamPolicy\
    \ on ?sa and no deny policy denies it. Becomes a realized federation only once a WIF provider accepts\
    \ an attacker-controllable subject the new/loosened principalSet:// binding resolves \u2014 chain\
    \ via rule 1. BLOCKED if an IAM deny policy denies setIamPolicy at the SA scope."
  confidence: min(contributing_confidences) * 0.95
  derived_from:
  - ?principal CanModifyTrust ?sa (Phase-2 gcp-sa-set-iam-policy, iam.serviceAccounts.setIamPolicy)
  false_positive_note: "Config-side primitive only \u2014 adding a workloadIdentityUser binding yields\
    \ federation only if a pool provider will ALSO accept a subject the attacker controls (rule 1 / rule\
    \ 3). This CanModifyTrust reuses the same iam.serviceAccounts.setIamPolicy permission as Phase-2 gcp-sa-set-iam-policy\
    \ (which already emits CanModifyTrust for the SA-token-creator self-grant case); dedupe on (CanModifyTrust,\
    \ ?principal, ?sa) and do not double-count weight. This rule exists to make the WIF-binding-write\
    \ intent explicit in the narrative."
  narrative: "{principal.name} can set the IAM policy of {sa.name} (iam.serviceAccounts.setIamPolicy)\
    \ and add or broaden a roles/iam.workloadIdentityUser binding for a principalSet:// member an attacker-controlled\
    \ external subject satisfies \u2014 wiring WIF impersonation of {sa.name}."
move · open · esc close