azure-kv-decrypt-gates-readdata

CanDecrypt on the wrapping KV key completes CanReadData on an externally-stored, CMK-wrapped store.

derived azure emits CanReadData

match

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

{'principal': None} CanReadData {'store': None} {'principal': None} CanDecrypt {'key': None}

where

?store data-plane control-plane read is present but the store is encrypted with customer-managed key ?key (storage/disk/SQL TDE wrapped by this KV key)

emit

source?principal
target?store
permissionsMicrosoft.KeyVault/vaults/keys/unwrap/action
conditionskey_permission
state logicif ?principal lacks keys/unwrap|decrypt on ?key: CONDITIONAL(key_permission); else ACTIVE

Narrative

{principal.name} can read CMK-encrypted store {store.name} because it can unwrap the wrapping key {key.name} (keys/unwrap).

Raw rule rules/derived/azure/keyvault.yaml

id: azure-kv-decrypt-gates-readdata
emits: CanReadData
description: CanDecrypt on the wrapping KV key completes CanReadData on an externally-stored, CMK-wrapped
  store.
match:
- - principal: null
  - CanReadData
  - store: null
- - principal: null
  - CanDecrypt
  - key: null
where:
- ?store data-plane control-plane read is present but the store is encrypted with customer-managed key
  ?key (storage/disk/SQL TDE wrapped by this KV key)
emit:
  source: ?principal
  target: ?store
  permissions:
  - Microsoft.KeyVault/vaults/keys/unwrap/action
  conditions:
  - key_permission
  state_logic: 'if ?principal lacks keys/unwrap|decrypt on ?key: CONDITIONAL(key_permission); else ACTIVE'
  confidence: min(contributing_confidences) * 0.9
  derived_from:
  - <CanReadData edge_id>
  - <CanDecrypt edge_id>
  false_positive_note: "This gate is for EXTERNAL stores wrapped by a Key Vault key \u2014 NOT for reading\
    \ secrets inside Key Vault itself (those decrypt transparently). Only apply when the store's CMK is\
    \ this key; do not gate on unrelated keys."
  narrative: '{principal.name} can read CMK-encrypted store {store.name} because it can unwrap the wrapping
    key {key.name} (keys/unwrap).'
move · open · esc close