Sequence 7 โ Microsoft Entra ID, RBAC & Anonymous Access
Prerequisites: Sequence 6 (the authorization model โ Access Keys & SAS). ยท What you'll be able to do: explain how Microsoft Entra ID + OAuth 2.0 authorize data requests with no secret in code; tell apart management-plane roles from data-plane RBAC roles and assign the right one at the right scope; disable Shared Key to enforce Entra; lock down anonymous public access org-wide. ยท Est. time: ~14 min.
1. Why Microsoft Entra ID for data access
In Sequence 6 you saw Shared Key (account keys) and SAS โ both rely on a secret that must be stored, rotated, and protected. Microsoft Entra ID is the third and recommended way to authorize requests to Blob, Queue, and Table data. Its advantage: no secret lives in your code. Identities are managed centrally, access is granted through Azure role-based access control (Azure RBAC), and you get full auditing.
Authorization with Entra is a two-step process:
- Authenticate โ the security principal proves its identity to Microsoft Entra ID, which returns a short-lived OAuth 2.0 access token.
- Authorize โ the token is sent with each request to the storage service, which checks whether the principal has an RBAC role granting the requested operation at the relevant scope.
Key facts to memorize:
- Supported on all general-purpose v2 and Blob storage accounts, in all public regions and national clouds.
- Only accounts using the Azure Resource Manager (ARM) deployment model support Entra authorization (not the legacy "classic" model).
- In code, acquire the token with the Azure Identity client library (the
DefaultAzureCredentialclass is the simple, recommended path โ same code works locally and in Azure). MSAL is for advanced scenarios. - For apps running inside an Azure resource (VM, scale set, Functions), use a managed identity so there is no credential at all in the app.
Azure Files data does not use this token model for SMB access โ it uses identity-based authentication over Kerberos, covered in Sequence 9. SAS is Sequence 6.
2. The crucial split: management plane vs. data plane
This is the single most tested concept in this episode. Azure has two planes, and a role on one does not automatically grant the other.
| Management plane (control) | Data plane | |
|---|---|---|
| What it controls | The storage account resource โ create, delete, configure, read keys, set networking | The data inside โ read/write/delete blobs, queue messages, table entities |
| Example roles | Owner, Contributor, Storage Account Contributor, Reader | Storage Blob Data Owner/Contributor/Reader, Storage Queue Data ..., Storage File Data SMB ... |
| Operations | Microsoft.Storage/storageAccounts/* (ARM) | Blob/Queue/Table data operations |
[!IMPORTANT] Owner and Contributor can manage the account but do NOT grant access to blob/queue/table data via Microsoft Entra ID. Only roles explicitly defined for data access let a principal touch the data through Entra.
The dangerous subtlety: a management role that includes the Microsoft.Storage/storageAccounts/listKeys/action permission (Owner, Contributor, Storage Account Contributor all have it) lets the holder fetch the account keys and then reach data via Shared Key โ a back door that bypasses data-plane RBAC entirely. This is exactly why disabling Shared Key (Section 5) matters, and why the Azure portal picks its auth method based on whether you hold listKeys (Section 6).
3. Built-in data-plane roles
Azure Storage ships built-in data roles per service. The blob trio is the one to know cold:
| Role | Grants | Typical use |
|---|---|---|
| Storage Blob Data Reader | Read blobs and containers | Read-only consumers, reporting |
| Storage Blob Data Contributor | Read, write, delete blob data | Apps and users that manage objects |
| Storage Blob Data Owner | Full data access + POSIX ACL management for Azure Data Lake Storage | Owners / ADLS Gen2 access control |
| Storage Blob Delegator | Get a user delegation key to sign an Entra-backed SAS (see Seq 6) | Issuing user-delegation SAS |
Parallel families exist for the other services (same Reader/Contributor pattern):
| Service | Data roles (examples) |
|---|---|
| Queue | Storage Queue Data Reader / Contributor / Message Processor / Message Sender |
| Table | Storage Table Data Reader / Contributor |
| Files (SMB) | Storage File Data SMB Share Reader / Contributor / Elevated Contributor โ see Sequence 9 |
You can also build custom roles for granular needs, and refine access with Azure attribute-based access control (Azure ABAC) โ adding conditions on a role assignment (e.g., only blobs with a given tag/path). ABAC for blobs is (Preview).
4. Choosing the scope, then assigning the role
A role assignment = who (principal) + what (role) + where (scope). A security principal can be a user, group, application service principal, or managed identity.
Scope is inherited downward โ a role set at a broad scope applies to everything beneath it. Always grant the narrowest scope that works (least privilege).
| Scope | Assignment applies to... |
|---|---|
| Management group | every container/queue in every account in every RG in every subscription beneath it |
| Subscription | all accounts (and their data) in the subscription |
| Resource group | all accounts in that RG |
| Storage account | all containers and their blobs in that account |
| Container / queue / table | just that one container/queue (narrowest, preferred) |
[!NOTE] Creating a storage account gives you no data permissions automatically โ you must explicitly assign yourself a data role.
Assign via the portal: open the storage account (or a container) โ Access Control (IAM) โ Add โ Add role assignment โ pick a data role (e.g., Storage Blob Data Contributor) โ select the member โ Review + assign. You need a role with Microsoft.Authorization/roleAssignments/write (e.g., Owner or User Access Administrator) at that scope or higher.
Azure CLI โ scope a container to honor least privilege:
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee user@contoso.com \
--scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>/blobServices/default/containers/<container>"
Assigning to a managed identity or service principal (use the object ID + principal type, which avoids ambiguity):
az role assignment create \
--role "Storage Blob Data Reader" \
--assignee-object-id "aaaaaaaa-0000-1111-2222-bbbbbbbbbbbb" \
--assignee-principal-type "ServicePrincipal" \
--scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>"
Az PowerShell equivalent:
New-AzRoleAssignment -SignInName user@contoso.com `
-RoleDefinitionName "Storage Blob Data Contributor" `
-Scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>/blobServices/default/containers/<container>"
Propagation delay โ exam favorite: role changes can take up to ~10 minutes to take effect (the source page elsewhere cites up to 30 minutes as a worst case โ allow time before troubleshooting). At management-group scope, data-action permissions can rarely take up to 12 hours โ so do not use management-group scope for time-sensitive grant/revoke (e.g., PIM). If you set allow permissions but still get AuthorizationPermissionMismatch, first wait for replication, then check for deny assignments and read-only resource locks (a read-only lock blocks new role assignments scoped to the account/container).
5. Forcing Entra: disable Shared Key
Because anyone who can read the account keys (via listKeys) can bypass data RBAC through Shared Key, the hardening step is to disable Shared Key authorization on the account. Then every request to Blob/Queue/Table/Files must use Microsoft Entra ID (SAS signed with the account key also stops working; user-delegation SAS still works because it is Entra-backed โ see Seq 6).
az storage account update \
--name <account> --resource-group <rg> \
--allow-shared-key-access false
Before flipping this, confirm nothing depends on keys/SAS, and ensure principals already hold the right data roles โ otherwise you lock everyone out.
6. How the portal chooses Entra vs. key
When you browse data in the Azure portal, it decides the auth method for you:
- If your role includes
Microsoft.Storage/storageAccounts/listkeys/actionโ the portal uses the account key (Shared Key). - If not โ it falls back to your Microsoft Entra account.
To browse data with your Entra identity, you need both:
- a data role (e.g., Storage Blob Data Reader/Contributor), and
- the ARM management-plane Reader role (or higher) scoped to the account โ so you can navigate to the account in the portal. Data roles grant data access but not the ability to see the account resource in the portal tree.
7. Anonymous (public) read access
Separate from all of the above: blobs can optionally be served to anyone, with no credential โ useful for public websites/assets, but a security risk that is the source of many data leaks. Anonymous access is controlled at two levels, and both must allow it for public reads to work:
| Level | Setting | Effect |
|---|---|---|
| Account | AllowBlobPublicAccess (True/False) | Master switch. False = no container can ever be public, regardless of its own setting |
| Container | Private (default) | All access requires authorization |
| Container | Blob | Anonymous read of blobs you know the URL of; cannot list the container |
| Container | Container | Anonymous read + list all blobs in the container |
Defaults & guidance:
- By default anonymous access is never permitted โ every request must be authorized unless you explicitly opt in.
- Microsoft recommends disabling anonymous access on all accounts. New accounts default AllowBlobPublicAccess appropriately; the safe posture is False.
- Setting the account switch to False is the org-wide remediation โ it immediately overrides any per-container setting.
Disable anonymous access on an account (remediation):
az storage account update \
--name <account> --resource-group <rg> \
--allow-blob-public-access false
If you genuinely need public content: isolate it โ put those containers in a dedicated storage account reserved for anonymous access, and keep AllowBlobPublicAccess = False everywhere else. Enforce this at scale with Azure Policy (deny accounts where public access is enabled).
Key takeaways
- Entra = no secret in code. Two steps: authenticate โ OAuth 2.0 token โ authorize via RBAC. Use managed identity inside Azure;
DefaultAzureCredentialin code. - "Owner โ data owner." Management roles (Owner/Contributor) manage the account but grant no data access via Entra. You need a Storage Data role.
- Blob trio mnemonic โ R-C-O = Read / Read+Write+Delete / +ACLs(ADLS): Reader โ Contributor โ Owner.
- Scope inherits downward; grant the narrowest. MG โ Sub โ RG โ Account โ Container.
- Wait ~10 min for role propagation (worst case longer; up to 12 h at MG scope).
AuthorizationPermissionMismatchusually means wait, or check deny assignments / locks. listKeysis the back door โ disable Shared Key (--allow-shared-key-access false) to force Entra.- Anonymous access = two gates: account AllowBlobPublicAccess AND container level (Private / Blob / Container). Account False wins. Default-deny; isolate public content in its own account.
Exercises
- (Recall) A developer is assigned Contributor on a storage account and is surprised they can't read blobs via their Entra identity from an app using
DefaultAzureCredential. Why, and what role fixes it? - (Recall) List the three core blob data roles from least to most privilege, and say what extra capability the most privileged one adds.
- (Applied) Write the Azure CLI command to grant a managed identity (object ID
1111...) read-only data access to a single container namedimages. - (Scenario) You enabled the correct data role 3 minutes ago but still get
AuthorizationPermissionMismatch. Give two distinct causes and how to resolve each. - (Scenario) A marketing team needs one container of public images, but security mandates no anonymous access anywhere. Describe the architecture you'd recommend.
- (Applied) Your org wants to guarantee that no account in a subscription can ever serve data anonymously. Name two complementary controls and the exact property each relies on.
Answers
- Contributor is a management-plane role: it manages the account but grants no blob data access via Microsoft Entra ID. Assign a data-plane role such as Storage Blob Data Reader (read) or Storage Blob Data Contributor (read/write/delete) at the account or container scope. (Note: Contributor could still reach data by pulling keys via
listKeys+ Shared Key, but not through the app's Entra token.) - Storage Blob Data Reader (read) โ Storage Blob Data Contributor (read, write, delete) โ Storage Blob Data Owner, which adds full data access plus POSIX ACL management for Azure Data Lake Storage.
-
az role assignment create \ --role "Storage Blob Data Reader" \ --assignee-object-id "1111..." \ --assignee-principal-type "ServicePrincipal" \ --scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>/blobServices/default/containers/images" - (a) Propagation delay โ assignments take up to ~10 minutes (longer at MG scope); simply wait and retry. (b) A deny assignment or read-only resource lock, or an inherited assignment, is overriding/blocking access; inspect IAM deny assignments and locks and remove or rescope as needed. (Also verify the role is a data role and the scope actually covers the target container.)
- Put the public images in a dedicated storage account reserved for anonymous access, with its container set to public Blob (or Container) level. Keep AllowBlobPublicAccess = False on all other accounts. This isolates the risk while satisfying the org-wide no-anonymous mandate.
- (1) Set each account's AllowBlobPublicAccess = False (the account master switch overrides every container's level). (2) Enforce it with Azure Policy that denies creation/update of any storage account where
allowBlobPublicAccessis true โ relying on the same AllowBlobPublicAccess ARM property at scale.
Coming up next
Sequence 8 โ Network Security: Firewalls, VNets & Private Endpoints โ restricting where requests may originate, the network-layer complement to the identity controls you just learned.