gcp-run-execute-as-via-create

Create a new Cloud Run resource bound to a chosen SA (actAs) and invoke/run it.

derived gcp emits CanExecuteAs

match

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

?principal CanAttachIdentity ?resource ?resource ExecutesAs ?sa

where

?principal held iam.serviceAccounts.actAs on ?sa (via CanPassIdentity) AND run.services.create OR run.jobs.create OR run.workerpools.create

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

?principal CanInvoke ?resource

emit

source typeIdentity
target typeIdentity
source<principal>
target<chosen runtime service account>
permissionsiam.serviceAccounts.actAs run.services.create run.jobs.create run.workerpools.create run.routes.invoke run.jobs.run
state logicif node_type(?resource)==ContainerService AND provider_type(?resource)==google.cloud.run.WorkerPool: ACTIVE (worker pools run continuously once created — no invoke/trigger needed); elif matched(optional[0]) or public service: ACTIVE; elif job AND ?principal has effective run.jobs.run on ?resource: ACTIVE (self-run) else CONDITIONAL(iam_permission)

Narrative

{principal.name} can create a Cloud Run resource bound to {sa.name} (actAs + run.*.create) and invoke/run it, executing code as {sa.name}.

Raw rule rules/derived/gcp/cloudrun.yaml

id: gcp-run-execute-as-via-create
emits: CanExecuteAs
description: Create a new Cloud Run resource bound to a chosen SA (actAs) and invoke/run it.
match:
- - ?principal
  - CanAttachIdentity
  - ?resource
- - ?resource
  - ExecutesAs
  - ?sa
where:
- ?principal held iam.serviceAccounts.actAs on ?sa (via CanPassIdentity) AND run.services.create OR run.jobs.create
  OR run.workerpools.create
optional:
- - ?principal
  - CanInvoke
  - ?resource
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <chosen runtime service account>
  state_logic: "if node_type(?resource)==ContainerService AND provider_type(?resource)==google.cloud.run.WorkerPool:\
    \ ACTIVE (worker pools run continuously once created \u2014 no invoke/trigger needed); elif matched(optional[0])\
    \ or public service: ACTIVE; elif job AND ?principal has effective run.jobs.run on ?resource: ACTIVE\
    \ (self-run) else CONDITIONAL(iam_permission)"
  permissions:
  - iam.serviceAccounts.actAs
  - run.services.create
  - run.jobs.create
  - run.workerpools.create
  - run.routes.invoke
  - run.jobs.run
  conditions_from:
  - ?resource
  - ?sa
  escalation: Deploy a new Cloud Run service/job/worker-pool running attacker code as a privileged SA,
    then invoke/run it.
  derived_from:
  - <CanAttachIdentity edge_id>
  - <ExecutesAs edge_id>
  - <optional CanInvoke edge_id>
  false_positive_note: Only emit for an SA the principal can actAs. run.jobs.create does NOT implicitly
    grant run.jobs.run (run is a separate permission, part of roles/run.invoker or roles/run.developer/run.admin);
    a principal with only create cannot necessarily run the job it created, so the self-run ACTIVE branch
    requires the principal to hold effective run.jobs.run on the created job, else CONDITIONAL(iam_permission).
    A worker pool runs continuously once created (ACTIVE). A service needs invoke or a trigger.
  narrative: '{principal.name} can create a Cloud Run resource bound to {sa.name} (actAs + run.*.create)
    and invoke/run it, executing code as {sa.name}.'
move · open · esc close