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).

derived gcp emits CanExecuteAs

match

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

{'principal': None} CanCreateWorkloadAs {'sa': None}

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 typeIdentity
target typeIdentity
source<principal>
target<runtime service account>
permissionsbatch.jobs.create iam.serviceAccounts.actAs
conditionsiam_permission
state logicACTIVE 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.'
move · open · esc close