gcp-dataproc-jobs-create-execute-command
dataproc.jobs.create on an existing cluster lets the principal submit arbitrary Spark/PySpark/Hive code that runs on cluster VMs -> RCE as the cluster SA.
match (effective permission)
{
"action": "dataproc.jobs.create",
"resource_type": "google.dataproc.Cluster"
}
where
cluster is RUNNING (state == RUNNING); submit to a STOPPED cluster returns an error
the effective permission may be scoped at project OR cluster level (per-resource IAM)
emit
| source type | Identity |
|---|---|
| target type | AnalyticsService |
| source | <principal> |
| target | <Dataproc cluster> |
| permissions | dataproc.jobs.create |
| conditions | iam_permission service_state |
| state logic | ACTIVE when dataproc.jobs.create is confirmed (effective permission; honor project- and cluster-level IAM) and the cluster is RUNNING. CONDITIONAL(service_state) when the cluster is STOPPED or CREATING (job submit fails). BLOCKED if an IAM deny or org policy denies dataproc.jobs.create at the effective scope. Per-resource IAM on the cluster (dataproc.clusters.use or jobs.create binding) narrows or expands access — resolve both project-level and cluster-level bindings. |
Narrative
{principal.name} can submit a Dataproc job (dataproc.jobs.create) to {cluster.name}, executing arbitrary Spark/PySpark/Hive/Pig code on the cluster VMs as cluster SA {sa.name}. CITE can-execute-as execute-as-via-command for the CanExecuteAs collapse.
Raw rule rules/derived/gcp/dataproc.yaml
id: gcp-dataproc-jobs-create-execute-command
emits: CanExecuteCommand
description: dataproc.jobs.create on an existing cluster lets the principal submit arbitrary Spark/PySpark/Hive
code that runs on cluster VMs -> RCE as the cluster SA.
match_effective_permission:
action: dataproc.jobs.create
resource_type: google.dataproc.Cluster
where:
- cluster is RUNNING (state == RUNNING); submit to a STOPPED cluster returns an error
- the effective permission may be scoped at project OR cluster level (per-resource IAM)
emit:
source_type: Identity
target_type: AnalyticsService
source: <principal>
target: <Dataproc cluster>
permissions:
- dataproc.jobs.create
conditions:
- iam_permission
- service_state
state_logic: "ACTIVE when dataproc.jobs.create is confirmed (effective permission; honor project- and\
\ cluster-level IAM) and the cluster is RUNNING. CONDITIONAL(service_state) when the cluster is STOPPED\
\ or CREATING (job submit fails). BLOCKED if an IAM deny or org policy denies dataproc.jobs.create\
\ at the effective scope. Per-resource IAM on the cluster (dataproc.clusters.use or jobs.create binding)\
\ narrows or expands access \u2014 resolve both project-level and cluster-level bindings."
false_positive_note: "Only ACTIVE for RUNNING clusters; STOPPED/CREATING clusters reject job submissions.\
\ Resolve the cluster-level IAM policy (dataproc.clusters.getIamPolicy) \u2014 a cluster-level DENY\
\ for the principal overrides a project-level allow. dataproc.jobs.create alone gives RCE but only\
\ yields privilege escalation if the cluster SA is more privileged than the attacker (resolve actual\
\ SA roles). Submit to the CORRECT cluster \u2014 cross-cluster job submission is not possible with\
\ only a project-level binding if a cluster-level IAM deny blocks it. CITE can-control escalate-via-execute-as\
\ for the privilege-level check; CanEscalateTo is derived automatically when the cluster SA privilege_level\
\ > principal.privilege_level."
narrative: '{principal.name} can submit a Dataproc job (dataproc.jobs.create) to {cluster.name}, executing
arbitrary Spark/PySpark/Hive/Pig code on the cluster VMs as cluster SA {sa.name}. CITE can-execute-as
execute-as-via-command for the CanExecuteAs collapse.'