gcp-workflows-cross-project-trust

An IAM binding on the workflow's allow policy granting workflows.executions.create to a principal in a different project is cross-project publish/trigger trust.

derived gcp emits CrossProjectTrust

match (record)

{ "field": "iamPolicy.bindings", "resource_type": "google.workflows.type.Workflow" }

where

a binding member (user/SA) belongs to a different project than the workflow the binding grants workflows.executions.create (roles/workflows.invoker or roles/workflows.editor)

emit

source typeResourcePolicy
target typeProject
source<workflow IAM allow policy>
target<external project of the granted principal>
conditionsresource_policy
state logicACTIVE when the binding unconditionally grants executions.create to an external principal. CONDITIONAL(condition_expression) when scoped by an IAM condition (resource tag, request time, originating IP). BLOCKED by an org policy or IAM deny that overrides the grant.

Narrative

The IAM policy of {workflow.name} grants a principal in project {ext_project.name} the ability to start executions (workflows.executions.create), creating cross-project trigger trust; an attacker in that project can drive the workflow's runtime service account.

Raw rule rules/derived/gcp/workflows.yaml

id: gcp-workflows-cross-project-trust
emits: CrossProjectTrust
description: An IAM binding on the workflow's allow policy granting workflows.executions.create to a principal
  in a different project is cross-project publish/trigger trust.
match_record:
  resource_type: google.workflows.type.Workflow
  field: iamPolicy.bindings
where:
- a binding member (user/SA) belongs to a different project than the workflow
- the binding grants workflows.executions.create (roles/workflows.invoker or roles/workflows.editor)
emit:
  source_type: ResourcePolicy
  target_type: Project
  source: <workflow IAM allow policy>
  target: <external project of the granted principal>
  permissions: []
  derived_from:
  - "workflow.iamPolicy.bindings \u2014 cross-project member with executions.create"
  conditions:
  - resource_policy
  state_logic: ACTIVE when the binding unconditionally grants executions.create to an external principal.
    CONDITIONAL(condition_expression) when scoped by an IAM condition (resource tag, request time, originating
    IP). BLOCKED by an org policy or IAM deny that overrides the grant.
  false_positive_note: "CITE, DO NOT DUPLICATE can-control: this rule asserts ONLY the cross-project messaging\
    \ trust fact \u2014 it does NOT emit CanEnterProject. The CanEnterProject consequence (external principal\
    \ triggers workflow -> CanExecuteAs runtime SA in the workflow's project) is produced by can-control\
    \ consuming this CrossProjectTrust together with CanInvoke/CanTrigger and ExecutesAs. Honor IAM conditions\
    \ that narrow the grant."
  narrative: The IAM policy of {workflow.name} grants a principal in project {ext_project.name} the ability
    to start executions (workflows.executions.create), creating cross-project trigger trust; an attacker
    in that project can drive the workflow's runtime service account.
move · open · esc close