gcp-batch-execute-as-via-create
Create a job with an attacker runnable bound to an actAs-able SA; ExecutesAs completes it. ACTIVE on create (no invoke/trigger).
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?principal has batch.jobs.create in the target project/location
?principal has iam.serviceAccounts.actAs on ?sa
?sa.privilege_level >= ?principal.privilege_level
emit
| source type | Identity |
|---|---|
| target type | Identity |
| source | <principal> |
| target | <runtime service account> |
| permissions | batch.jobs.create iam.serviceAccounts.actAs |
| conditions | iam_permission |
| state logic | ACTIVE only when iam.serviceAccounts.actAs on ?sa is confirmed present (the job then runs immediately -- Batch has no invoke step and no trigger_exists condition). If actAs is not confirmed on ?sa -> POTENTIAL(iam_permission). Never downgrade to CONDITIONAL(trigger_exists). |
Narrative
{principal.name} can create a Batch job (batch.jobs.create) whose VMs run attacker code as {sa.name} (iam.serviceAccounts.actAs); the job runs on creation, no invocation needed.
Raw rule rules/derived/gcp/batch.yaml
id: gcp-batch-execute-as-via-create
emits: CanExecuteAs
description: Create a job with an attacker runnable bound to an actAs-able SA; ExecutesAs completes it.
ACTIVE on create (no invoke/trigger).
match:
- - principal: null
- CanCreateWorkloadAs
- sa: null
where:
- ?principal has batch.jobs.create in the target project/location
- ?principal has iam.serviceAccounts.actAs on ?sa
- ?sa.privilege_level >= ?principal.privilege_level
emit:
source_type: Identity
target_type: Identity
source: <principal>
target: <runtime service account>
permissions:
- batch.jobs.create
- iam.serviceAccounts.actAs
conditions:
- iam_permission
state_logic: ACTIVE only when iam.serviceAccounts.actAs on ?sa is confirmed present (the job then runs
immediately -- Batch has no invoke step and no trigger_exists condition). If actAs is not confirmed
on ?sa -> POTENTIAL(iam_permission). Never downgrade to CONDITIONAL(trigger_exists).
conditions_from:
- sa: null
false_positive_note: No trigger/invoke gating -- unlike GCF, do NOT downgrade to CONDITIONAL(trigger_exists).
Escalation only when SA privilege exceeds caller's; the default Compute Engine editor SA qualifies
(but still requires actAs on it). actAs is per-SA.
narrative: '{principal.name} can create a Batch job (batch.jobs.create) whose VMs run attacker code
as {sa.name} (iam.serviceAccounts.actAs); the job runs on creation, no invocation needed.'