Skip to main content
KBY Technologies Logo
cd ../config-traps
risk/register/storage-account-keys-still-bypass-azure-rbac.html
Azure Storage Securityhigh severityAzure Storage

Storage Account Keys Still Bypass Azure RBAC

Overview

A storage account with fine-grained Azure RBAC still grants full data-plane access to anyone holding its account key, because Azure Storage's shared-key authentication path never consults Azure AD. Conditional Access, MFA and RBAC scoping are silently skipped whenever a leaked key or classic SAS token reaches blob, queue or table endpoints.

At a glance

Unsafe setting
allowSharedKeyAccess (Allow storage account key access) left set to true on the storage account.
Failure trigger
A leaked account key or classic SAS token is presented to the data plane, bypassing Azure AD RBAC and Conditional Access entirely.
Blast radius
Full read, write and delete access to blobs, queues and tables regardless of RBAC role assignments, with no Conditional Access or MFA enforcement.
Recommended control
Set shared_access_key_enabled/allowSharedKeyAccess to false and enforce it via Azure Policy definition 6b1cbf55-e8b6-442f-ba4c-a25a6ba1c99a.

Fix commands and configuration

az storage account update --name <name> --resource-group <rg> --allow-shared-key-access false
shared_access_key_enabled = false
azurerm_storage_account

The Trap

The allowSharedKeyAccess property on an Azure Storage Account, exposed in the portal as “Allow storage account key access”, remains set to true long after teams have layered Azure RBAC roles such as Storage Blob Data Reader or Storage Blob Data Contributor on top. Engineers treat those role assignments as the access control boundary and never realise that a completely separate, older authentication path is still live on the same account.

The Default State

Every new storage account, whether provisioned via the Azure Portal, CLI, ARM template, or the azurerm_storage_account Terraform resource, ships with shared key authorisation enabled unless a value is explicitly set. Most Terraform modules omit the shared_access_key_enabled argument entirely, inheriting the provider default of true. Developers also routinely pull the primary or secondary key from the Access Keys blade to build connection strings for App Service, Functions, or local development, cementing key-based access as the working pattern rather than the exception.

The Blast Radius

Shared key authentication does not authenticate against Azure AD at all. It validates a symmetric HMAC signature derived from the account key, so it has no concept of RBAC role assignments, Conditional Access policies, MFA, or sign-in risk. Anyone holding the key, whether pulled from a Key Vault secret, a pipeline variable, a stale .env file, or a leaked application setting, gets full read, write and delete access to every blob, queue, and table in the account regardless of how tightly RBAC has been scoped. Classic SAS tokens minted from that key inherit the same bypass, since they are not tied to an Azure AD identity like a user delegation SAS is. Key rotation is frequently neglected for months or years, so a single historic leak stays exploitable indefinitely, and Defender for Storage anomaly detection is built around unusual access patterns, not correctly signed key-based requests that look entirely legitimate.

The Lead Mechanic Fix

Disable shared key authorisation directly on the resource: az storage account update --name <name> --resource-group <rg> --allow-shared-key-access false, or in Terraform set shared_access_key_enabled = false on azurerm_storage_account. Enforce this fleet-wide with an Azure Policy assignment against definition 6b1cbf55-e8b6-442f-ba4c-a25a6ba1c99a in Deny mode, targeting the Microsoft.Storage/storageAccounts field properties.allowSharedKeyAccess. Before flipping the switch, audit every App Service connection string, Function App setting, and Terraform state file for AccountKey= references, since this change breaks any workload still authenticating via shared key the moment it is applied, with no grace period.