azure-synapse-execute-as-via-pipeline

Publish a pipeline with attacker code (CanModifyCode on workspace) + trigger it (CanTrigger) + workspace ExecutesAs MI => execute as workspace MI. Cites cicd-chains.yaml cicd-modify-buildspec-executes-as and can-execute-as.yaml.

derived azure emits CanExecuteAs

match

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

{'principal': None} CanModifyCode {'workspace': None} {'principal': None} CanTrigger {'workspace': None} {'workspace': None} ExecutesAs {'mi': None}

where

node_type(?workspace) == AnalyticsService node_type(?mi) == ManagedIdentity ?mi.privilege_level >= ?principal.privilege_level

emit

source typeIdentity
target typeIdentity
source<principal>
target<workspace managed identity>
permissionsSynapse RBAC: Synapse Artifact Publisher Synapse RBAC: Synapse Compute Operator
state logicACTIVE: principal can both publish (CanModifyCode) and trigger (CanTrigger) the pipeline, so the full modify+run chain is closed. Inherit weakest from CanModifyCode and CanTrigger contributors. If principal only has CanModifyCode but NOT CanTrigger, CONDITIONAL(trigger_exists) — see cicd-chains rule 1. If principal only has CanTrigger but NOT CanModifyCode, CONDITIONAL(attacker_influenced_definition) — see cicd-chains rule 2.

Narrative

{principal.name} can publish attacker-controlled pipeline code to Synapse workspace {workspace.name} (Artifact Publisher) and trigger it (Compute Operator), executing as workspace MI {mi.name}.

Raw rule rules/derived/azure/synapse.yaml

id: azure-synapse-execute-as-via-pipeline
emits: CanExecuteAs
description: Publish a pipeline with attacker code (CanModifyCode on workspace) + trigger it (CanTrigger)
  + workspace ExecutesAs MI => execute as workspace MI. Cites cicd-chains.yaml cicd-modify-buildspec-executes-as
  and can-execute-as.yaml.
match:
- - principal: null
  - CanModifyCode
  - workspace: null
- - principal: null
  - CanTrigger
  - workspace: null
- - workspace: null
  - ExecutesAs
  - mi: null
where:
- node_type(?workspace) == AnalyticsService
- node_type(?mi) == ManagedIdentity
- ?mi.privilege_level >= ?principal.privilege_level
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <workspace managed identity>
  permissions:
  - 'Synapse RBAC: Synapse Artifact Publisher'
  - 'Synapse RBAC: Synapse Compute Operator'
  conditions: []
  state_logic: "ACTIVE: principal can both publish (CanModifyCode) and trigger (CanTrigger) the pipeline,\
    \ so the full modify+run chain is closed. Inherit weakest from CanModifyCode and CanTrigger contributors.\
    \ If principal only has CanModifyCode but NOT CanTrigger, CONDITIONAL(trigger_exists) \u2014 see cicd-chains\
    \ rule 1. If principal only has CanTrigger but NOT CanModifyCode, CONDITIONAL(attacker_influenced_definition)\
    \ \u2014 see cicd-chains rule 2."
  derived_from:
  - <CanModifyCode edge_id>
  - <CanTrigger edge_id>
  - <ExecutesAs edge_id>
  note: "CITES cicd-chains.yaml cicd-modify-buildspec-executes-as (rule 1). The generic linchpin does\
    \ NOT apply here because it checks node_class(?compute) == Compute; AnalyticsService is Data class.\
    \ This rule is the sole authoritative emitter for the pipeline-modification path; there is no deduplication\
    \ with the generic linchpin. Dedupes on (CanExecuteAs, ?principal, ?mi). The escalation roll-up is\
    \ can-control.yaml escalate-via-execute-as \u2014 CITE, DO NOT re-derive."
  false_positive_note: Requires BOTH publish AND trigger roles; if only one is held, downgrade state as
    above. The Synapse RBAC roles are independent of Azure RBAC. Verify that Managed VNet exfiltration
    protection does not block the pipeline's outbound calls (does not affect execution-as-MI). Deny assignments
    on Synapse workspaces -> BLOCKED.
  narrative: '{principal.name} can publish attacker-controlled pipeline code to Synapse workspace {workspace.name}
    (Artifact Publisher) and trigger it (Compute Operator), executing as workspace MI {mi.name}.'
move · open · esc close