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.
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 type | ResourcePolicy |
|---|---|
| target type | Project |
| source | <workflow IAM allow policy> |
| target | <external project of the granted principal> |
| 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. |
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.