gcp-run-execute-as-via-create
Create a new Cloud Run resource bound to a chosen SA (actAs) and invoke/run it.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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 type | Identity |
|---|---|
| target type | Identity |
| source | <principal> |
| target | <chosen runtime service account> |
| permissions | iam.serviceAccounts.actAs run.services.create run.jobs.create run.workerpools.create run.routes.invoke run.jobs.run |
| state logic | if 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}.'