azure-storage-generate-user-delegation-key

generateUserDelegationKey/action returns user-delegation key material (not a pre-formed SAS token) - the caller can sign arbitrary user-delegation SAS URLs offline within the key's validity window.

derived azure emits CanReadCredential

match

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

{'principal': None} HasPermission {'account': None}

where

node_class(?account) == Storage and node_type(?account) == ObjectStorage node_type(?account) matched provider_type == 'Microsoft.Storage/storageAccounts' ?principal has EFFECTIVE Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action at ?account scope

emit

source typeIdentity
target typeAccessKey
source?principal
target<user-delegation AccessKey node (signing key material) derived from ?account>
permissionsMicrosoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action
conditionsiam_permission
state logicif a deny assignment or deny Azure Policy covers generateUserDelegationKey/action: BLOCKED; else ACTIVE. ARM-plane call — not gated by storage network firewall. The minted token is bounded by the principal's effective Entra RBAC scope; cannot exceed the principal's own data-plane permissions. However, the token is a separable credential object that can be shared externally.

Narrative

{principal.name} can call generateUserDelegationKey on {account.name} (Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action), minting user-delegation SAS tokens for blob access. These tokens are bounded by {principal.name}'s effective Entra permissions but can be shared with external parties or stored insecurely, creating a delegable credential exposure.

Raw rule rules/derived/azure/storage.yaml

id: azure-storage-generate-user-delegation-key
emits: CanReadCredential
description: "generateUserDelegationKey/action returns user-delegation key material (not a pre-formed\
  \ SAS token) \u2014 the caller can sign arbitrary user-delegation SAS URLs offline within the key's\
  \ validity window."
match:
- - principal: null
  - HasPermission
  - account: null
where:
- node_class(?account) == Storage and node_type(?account) == ObjectStorage
- node_type(?account) matched provider_type == 'Microsoft.Storage/storageAccounts'
- ?principal has EFFECTIVE Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action
  at ?account scope
emit:
  source_type: Identity
  target_type: AccessKey
  source: ?principal
  target: <user-delegation AccessKey node (signing key material) derived from ?account>
  permissions:
  - Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action
  conditions:
  - iam_permission
  state_logic: "if a deny assignment or deny Azure Policy covers generateUserDelegationKey/action: BLOCKED;\
    \ else ACTIVE. ARM-plane call \u2014 not gated by storage network firewall. The minted token is bounded\
    \ by the principal's effective Entra RBAC scope; cannot exceed the principal's own data-plane permissions.\
    \ However, the token is a separable credential object that can be shared externally."
  confidence: '0.75'
  derived_from:
  - rule_id: azure-storage-generate-user-delegation-key-permission
    binding: ?principal HasPermission ?account
  false_positive_note: "generateUserDelegationKey is an ARM control-plane action callable regardless of\
    \ storage networkAcls. Do NOT apply network_reachability. The REST API returns a UserDelegationKey\
    \ JSON object containing the raw signing key material (Value field, base64-encoded). The caller uses\
    \ this key material client-side to sign user-delegation SAS URLs; the action does NOT return a pre-formed\
    \ SAS token. The returned key is BOUNDED BY the minting principal's effective Entra RBAC permissions\
    \ \u2014 any SAS signed with it cannot grant access beyond the principal's own RBAC scope. This is\
    \ distinct from listKeys (unscoped) and listAccountSas (account-scoped). Confidence is ~0.75 because\
    \ the key scope is inherently restricted. The attack value is realized when the principal signs and\
    \ shares SAS URLs with external parties or stores the key material insecurely. The key can be used\
    \ OFFLINE to sign arbitrary SAS URLs within the key's validity window (SignedExpiry), which is a higher\
    \ impact than a single pre-formed token."
  narrative: '{principal.name} can call generateUserDelegationKey on {account.name} (Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action),
    minting user-delegation SAS tokens for blob access. These tokens are bounded by {principal.name}''s
    effective Entra permissions but can be shared with external parties or stored insecurely, creating
    a delegable credential exposure.'
move · open · esc close