azure-disk-cmk-gated-read

An attacker who can SAS-export a CMK-encrypted managed disk downloads encrypted VHD 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 {'disk': None}

where

node_type(?disk) == BlockStorage ?disk.encryption.type == EncryptionAtRestWithCustomerKey ?disk.encryption.diskEncryptionSetId != null

emit

source typeIdentity
target typeBlockStorage
source?principal
target?disk
permissionsMicrosoft.Compute/disks/beginGetAccess/action
conditionskey_permission
state logicCONDITIONAL(key_permission): the VHD 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 VHD for disk {target.name} via SAS, but the 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-disk-cmk-gated-read
emits: CanReadData
description: An attacker who can SAS-export a CMK-encrypted managed disk downloads encrypted VHD 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
  - disk: null
where:
- node_type(?disk) == BlockStorage
- ?disk.encryption.type == EncryptionAtRestWithCustomerKey
- ?disk.encryption.diskEncryptionSetId != null
emit:
  source_type: Identity
  target_type: BlockStorage
  source: ?principal
  target: ?disk
  permissions:
  - Microsoft.Compute/disks/beginGetAccess/action
  conditions:
  - key_permission
  state_logic: 'CONDITIONAL(key_permission): the VHD 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 ?disk> (with disk.encryption.diskEncryptionSetId property linking to DES)
  false_positive_note: "1) Platform-managed key (PMK) or server-side encryption with platform key\n  \
    \ (EncryptionAtRestWithPlatformKey): Azure decrypts transparently; the caller\n   does NOT need Key\
    \ Vault decrypt -> emit CanReadData as ACTIVE (no key gate).\n2) EncryptionAtRestWithPlatformAndCustomerKeys\
    \ (double encryption): both platform\n   and customer key must be satisfied; the key_permission gate\
    \ still applies to\n   the CMK layer.\n3) Do NOT emit CanReadData for a PMK-only disk; it is subsumed\
    \ by CanExfiltrate. 4) If the DES is not linked (diskEncryptionSetId absent/null), do not emit this\
    \ rule. Cite credential-chains.yaml for the upgrade pattern."
  narrative: "{principal.name} can download the VHD for disk {target.name} via SAS, but the 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