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