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