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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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). |
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)."