gcp-deploy-rollout-approve-unblocks

clouddeploy.rollouts.approve unblocks a NEEDS_APPROVAL rollout, triggering the deploy Cloud Build worker (no actAs required).

derived gcp emits CanTrigger

match (effective permission)

{ "action": "clouddeploy.rollouts.approve", "resource_type": "google.cloud.deploy.DeliveryPipeline" }

where

a rollout is in NEEDS_APPROVAL state on a target in this pipeline

emit

source typeIdentity
target typeBuildWorker
source<principal>
target<deploy-phase Cloud Build worker (BuildWorker) for the approved rollout>
permissionsclouddeploy.rollouts.approve
conditionsiam_permission trigger_exists
state logicCONDITIONAL(trigger_exists) — the trigger only fires when a pending rollout exists in NEEDS_APPROVAL state. ACTIVE if a rollout is currently pending approval for a target in this pipeline. BLOCKED when an IAM deny policy denies clouddeploy.rollouts.approve. Note: an attacker who has BOTH rollouts.create (to create the rollout) and rollouts.approve (to approve it) on the same target can complete the full chain unilaterally; when both permissions are confirmed, the approval gate provides no separation — the CanExecuteAs edge (from gcp-deploy-rollout-promote-executes-as) becomes ACTIVE instead of CONDITIONAL(approval_required).

Narrative

{principal.name} can approve a pending Cloud Deploy rollout (clouddeploy.rollouts.approve) in pipeline {pipeline.name}, unblocking the deploy Cloud Build worker. If a pending rollout exists and {principal.name} also created it (holding both rollouts.create + iam.serviceAccounts.actAs on the deploy SA), the approval gate provides no isolation and the full execution chain is ACTIVE.

Raw rule rules/derived/gcp/clouddeploy.yaml

id: gcp-deploy-rollout-approve-unblocks
emits: CanTrigger
description: clouddeploy.rollouts.approve unblocks a NEEDS_APPROVAL rollout, triggering the deploy Cloud
  Build worker (no actAs required).
applies_to:
- gcp
match_effective_permission:
  action: clouddeploy.rollouts.approve
  resource_type: google.cloud.deploy.DeliveryPipeline
where:
- a rollout is in NEEDS_APPROVAL state on a target in this pipeline
emit:
  source_type: Identity
  target_type: BuildWorker
  source: <principal>
  target: <deploy-phase Cloud Build worker (BuildWorker) for the approved rollout>
  permissions:
  - clouddeploy.rollouts.approve
  conditions:
  - iam_permission
  - trigger_exists
  state_logic: "CONDITIONAL(trigger_exists) \u2014 the trigger only fires when a pending rollout exists\
    \ in NEEDS_APPROVAL state. ACTIVE if a rollout is currently pending approval for a target in this\
    \ pipeline. BLOCKED when an IAM deny policy denies clouddeploy.rollouts.approve. Note: an attacker\
    \ who has BOTH rollouts.create (to create the rollout) and rollouts.approve (to approve it) on the\
    \ same target can complete the full chain unilaterally; when both permissions are confirmed, the approval\
    \ gate provides no separation \u2014 the CanExecuteAs edge (from gcp-deploy-rollout-promote-executes-as)\
    \ becomes ACTIVE instead of CONDITIONAL(approval_required)."
  confidence: 0.88
  derived_from:
  - clouddeploy.rollouts.approve effective permission
  false_positive_note: "clouddeploy.rollouts.approve alone is the approval capability \u2014 it does NOT\
    \ require actAs or create permissions. A pure approver (holding only approve, not create) can still\
    \ trigger rollout execution. The full execute-as chain requires a rollout to exist in NEEDS_APPROVAL\
    \ state (someone must have called rollouts.create first, which DOES require actAs). The dangerous\
    \ case is when the SAME principal holds both rollouts.create and rollouts.approve, defeating role\
    \ separation. Confirm that a pending rollout exists before emitting ACTIVE."
  narrative: '{principal.name} can approve a pending Cloud Deploy rollout (clouddeploy.rollouts.approve)
    in pipeline {pipeline.name}, unblocking the deploy Cloud Build worker. If a pending rollout exists
    and {principal.name} also created it (holding both rollouts.create + iam.serviceAccounts.actAs on
    the deploy SA), the approval gate provides no isolation and the full execution chain is ACTIVE.'
move · open · esc close