gcp-eventarc-cross-project-trust

An IAM binding on an Eventarc trigger granting eventarc.triggers.update (or .create in the project) to a principal in a different project is cross-project trigger-management trust - that external principal can redirect the trigger or bind new sources to consumers in this project.

derived gcp emits CrossProjectTrust

match (record)

{ "field": "iamPolicy.bindings", "resource_type": "google.cloud.eventarc.v1.Trigger" }

where

a binding member (user:, serviceAccount:) belongs to a different project than the trigger the binding grants roles/eventarc.developer or roles/eventarc.admin (containing eventarc.triggers.update)

emit

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

Narrative

The IAM policy of trigger {trigger.name} grants a principal in project {ext_project.name} the ability to update or create Eventarc triggers (roles/eventarc.developer), creating cross-project trigger-management trust; an attacker in that project can redirect this trigger's event stream to attacker-chosen compute in this project.

Raw rule rules/derived/gcp/eventarc.yaml

id: gcp-eventarc-cross-project-trust
emits: CrossProjectTrust
description: "An IAM binding on an Eventarc trigger granting eventarc.triggers.update (or .create in the\
  \ project) to a principal in a different project is cross-project trigger-management trust \u2014 that\
  \ external principal can redirect the trigger or bind new sources to consumers in this project."
match_record:
  resource_type: google.cloud.eventarc.v1.Trigger
  field: iamPolicy.bindings
where:
- a binding member (user:, serviceAccount:) belongs to a different project than the trigger
- the binding grants roles/eventarc.developer or roles/eventarc.admin (containing eventarc.triggers.update)
emit:
  source_type: ResourcePolicy
  target_type: Project
  source: <trigger IAM allow policy (ResourcePolicy)>
  target: <external project of the granted principal>
  permissions: []
  conditions:
  - resource_policy
  - condition_expression
  state_logic: ACTIVE when the binding unconditionally grants eventarc.triggers.update or eventarc.triggers.create
    to an external principal. CONDITIONAL(condition_expression) when scoped by an IAM condition (resource
    tag, request time, originating network). BLOCKED by an org policy or IAM deny that overrides the grant.
  derived_from:
  - "trigger.iamPolicy.bindings \u2014 cross-project member with trigger-update/create grant"
  false_positive_note: "CITE, DO NOT DUPLICATE can-control: this rule asserts ONLY the cross-project trigger\
    \ management trust \u2014 it does NOT emit CanEnterProject. The CanEnterProject consequence (external\
    \ principal updates trigger \u2192 redirected CanTrigger \u2192 CanExecuteAs runtime SA in this project)\
    \ is produced by can-control consuming this CrossProjectTrust together with CanModifyConfiguration\
    \ / CanTrigger / ExecutesAs edges. Honor IAM conditions."
  narrative: The IAM policy of trigger {trigger.name} grants a principal in project {ext_project.name}
    the ability to update or create Eventarc triggers (roles/eventarc.developer), creating cross-project
    trigger-management trust; an attacker in that project can redirect this trigger's event stream to
    attacker-chosen compute in this project.
move · open · esc close