azure-snapshot-cmk-gated-read

An attacker who can SAS-export a CMK-encrypted snapshot downloads encrypted blobs; plaintext read requires decrypt on the wrapping DES key (CONDITIONAL). When the same principal also holds CanDecrypt on the DES Key Vault key the decrypt-gates-secret-read rule in credential-chains.yaml upgrades to ACTIVE.

derived azure emits CanReadData

match

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

{'principal': None} CanExfiltrate {'snapshot': None}

where

node_type(?snapshot) == Snapshot ?snapshot.encryption.type == EncryptionAtRestWithCustomerKey ?snapshot.encryption.diskEncryptionSetId != null

emit

source typeIdentity
target typeSnapshot
source?principal
target?snapshot
permissionsMicrosoft.Compute/snapshots/beginGetAccess/action
conditionskey_permission
state logicCONDITIONAL(key_permission): the snapshot download is feasible (CanExfiltrate ACTIVE) but plaintext data is unavailable without decrypting the data-encryption key via the DES's Key Vault key. The decrypt-gates-secret-read rule in /rules/derived/credential-chains.yaml upgrades this to ACTIVE when the same principal holds CanDecrypt on the wrapping EncryptionKey (DES key). If CanExfiltrate is BLOCKED or CONDITIONAL(network_reachability), inherit that state (weakest-contributor rule).

Narrative

{principal.name} can download the snapshot {target.name} via SAS, but the source disk is CMK-encrypted (DES-wrapped Key Vault key); plaintext readability is gated on holding Key Vault decrypt on the wrapping key (CONDITIONAL(key_permission) - see decrypt-gates-secret-read in credential-chains.yaml).

Raw rule rules/derived/azure/disks.yaml

id: azure-snapshot-cmk-gated-read
emits: CanReadData
description: An attacker who can SAS-export a CMK-encrypted snapshot downloads encrypted blobs; plaintext
  read requires decrypt on the wrapping DES key (CONDITIONAL). When the same principal also holds CanDecrypt
  on the DES Key Vault key the decrypt-gates-secret-read rule in credential-chains.yaml upgrades to ACTIVE.
match:
- - principal: null
  - CanExfiltrate
  - snapshot: null
where:
- node_type(?snapshot) == Snapshot
- ?snapshot.encryption.type == EncryptionAtRestWithCustomerKey
- ?snapshot.encryption.diskEncryptionSetId != null
emit:
  source_type: Identity
  target_type: Snapshot
  source: ?principal
  target: ?snapshot
  permissions:
  - Microsoft.Compute/snapshots/beginGetAccess/action
  conditions:
  - key_permission
  state_logic: 'CONDITIONAL(key_permission): the snapshot download is feasible (CanExfiltrate ACTIVE)
    but plaintext data is unavailable without decrypting the data-encryption key via the DES''s Key Vault
    key. The decrypt-gates-secret-read rule in /rules/derived/credential-chains.yaml upgrades this to
    ACTIVE when the same principal holds CanDecrypt on the wrapping EncryptionKey (DES key). If CanExfiltrate
    is BLOCKED or CONDITIONAL(network_reachability), inherit that state (weakest-contributor rule).'
  confidence: 0.8
  derived_from:
  - <CanExfiltrate edge_id for ?snapshot> (with encryption.diskEncryptionSetId property linking to DES)
  false_positive_note: '1) Platform-managed key (PMK): Azure decrypts transparently; no Key Vault decrypt
    needed. 2) EncryptionAtRestWithPlatformAndCustomerKeys (double encryption): both layers apply. 3)
    If the DES is not linked to the snapshot (encryption.diskEncryptionSetId absent/null), do not emit
    this rule. Cite credential-chains.yaml for the upgrade pattern.'
  narrative: "{principal.name} can download the snapshot {target.name} via SAS, but the source disk is\
    \ CMK-encrypted (DES-wrapped Key Vault key); plaintext readability is gated on holding Key Vault decrypt\
    \ on the wrapping key (CONDITIONAL(key_permission) \u2014 see decrypt-gates-secret-read in credential-chains.yaml)."
move · open · esc close