Azure Blob Storage: Fix Access, Upload & Config Errors
Why This Is Happening
I've seen this exact situation play out dozens of times: you set up an Azure Blob Storage account, everything looks fine in the portal, and then your application spits out a 403 Forbidden or a vague "access denied" message with zero useful context. Or maybe your AzCopy transfer just stalls. Maybe blobs that were publicly accessible yesterday are now returning 404s. It's maddening , especially when your storage account clearly exists and you can see it right there in the Azure portal.
Here's the reality: Azure Blob Storage is Microsoft's object storage solution for the cloud, built to store massive amounts of unstructured data, images, videos, log files, backups, binary blobs of every kind. It's powerful. It's also a system with several independent permission layers, network rules, redundancy settings, and protocol configurations that all have to line up correctly. When even one layer is misconfigured, you hit a wall.
The three most common reasons Azure Blob Storage stops working the way you expect:
- Authorization mismatches. Azure Storage supports multiple auth methods, shared key, shared access signatures (SAS), Microsoft Entra ID with RBAC, and anonymous public access. If your app is using one method but the account is configured for another, you get a silent 403. Azure's error messages rarely tell you which auth method failed or why, just that access was denied.
- Network and firewall rules. Storage accounts can be locked down to specific virtual networks, IP ranges, or service endpoints. If a new firewall rule was added (or a default was changed), traffic that worked yesterday gets dropped today. This is especially common in enterprise environments where a network team manages those rules separately from the app team.
- Public access settings changed by policy. Microsoft has been progressively tightening default security posture. Newer storage accounts have anonymous public access disabled by default. If your application assumes public read access to containers, a policy change or new account will break it instantly, no warning, no migration path, just a 404 where there used to be a 200.
There are also secondary causes worth knowing about: CORS configuration blocking browser-based uploads, expired SAS tokens, BlobFuse2 mount errors on Linux, NFS 3.0 protocol not enabled, and lifecycle management policies archiving blobs faster than expected. I'll cover all of these.
The good news: every single one of these issues has a concrete fix. You just need to know which layer is broken. Browse all Microsoft fix guides →
The Quick Fix, Try This First
Before you go deep into RBAC roles and firewall rules, try this. It resolves the majority of Azure Blob Storage access denied errors I encounter, especially for developers who are connecting for the first time or after a subscription change.
Verify your identity has the right storage data role assigned. This is separate from subscription-level ownership. Being an Owner or Contributor on the subscription does not automatically give you access to blob data. You need a specific data-plane role.
Here's how to check and fix it in under two minutes:
- Open the Azure portal and navigate to your storage account.
- In the left menu, click Access Control (IAM).
- Click Check access, then search for your user account, service principal, or managed identity.
- Look for one of these roles: Storage Blob Data Owner, Storage Blob Data Contributor, or Storage Blob Data Reader. If none appear, that's your problem.
- Click Add role assignment, select Storage Blob Data Contributor, assign it to your identity, and click Review + assign.
After saving, wait 60–90 seconds for the role assignment to propagate, Azure RBAC changes are not instant. Then retry your operation. If you're using the Azure CLI to test access:
az storage blob list \
--account-name YOUR_ACCOUNT_NAME \
--container-name YOUR_CONTAINER \
--auth-mode login
The --auth-mode login flag forces the CLI to use your Azure AD credentials rather than a shared key. If this now works, your role assignment was the issue.
This sounds obvious, but Azure Blob Storage 404 errors don't always mean the blob is missing, they can also appear when the storage account itself is in a state where it rejects all requests. Before chasing permissions, confirm the account is healthy.
In the Azure portal, go to Storage accounts and find your account. Check the Overview blade for any warnings. Specifically look at:
- Status field: should read "Available." If it shows "Degraded" or an error, this is a service-level issue.
- Redundancy: note whether you're on LRS, GRS, ZRS, or GZRS. Redundancy determines which regions can serve your data and how failover works.
- Primary endpoint: your blob endpoint should look like
https://ACCOUNTNAME.blob.core.windows.net. If you're calling a different URL, that's your first problem.
You can also ping the health of your storage account via PowerShell:
Get-AzStorageAccount -ResourceGroupName "YOUR_RG" -Name "YOUR_ACCOUNT" | Select-Object StorageAccountName, StatusOfPrimary, StatusOfSecondary
If StatusOfPrimary returns anything other than available, open the Azure Service Health blade in the portal (search for it in the top bar). Filter by your region and look for active incidents under Azure Storage. Microsoft posts real-time service degradation notices there, and if there's a regional outage, no amount of config changes will fix your access issues until the platform recovers.
If the account is healthy and reachable, move on to the next step. You should see the storage account overview load without errors, and the primary endpoint should respond to a basic HTTP HEAD request with a 400 or 403 (not a network timeout).
Azure Blob Storage supports several authorization methods, and picking the wrong one for your scenario is the single most common source of Azure Blob Storage access denied errors I see in the field. According to Microsoft's official documentation, you can authorize access using Microsoft Entra ID (formerly Azure AD), shared access signatures (SAS), or shared key authorization. Microsoft explicitly recommends Entra ID with RBAC as the most secure option.
Here's how to verify and fix your Entra ID auth setup end to end:
Check current role assignments:
az role assignment list \
--scope "/subscriptions/SUB_ID/resourceGroups/RG_NAME/providers/Microsoft.Storage/storageAccounts/ACCOUNT_NAME" \
--output table
Look for assignments that include Storage Blob Data in the role name. Standard read/write/owner roles at the resource level, like Contributor, do not grant data-plane access to blobs. This trips up almost every developer who's new to Azure Storage.
Assign the right role via PowerShell:
New-AzRoleAssignment `
-ObjectId "YOUR_USER_OR_SP_OBJECT_ID" `
-RoleDefinitionName "Storage Blob Data Contributor" `
-Scope "/subscriptions/SUB_ID/resourceGroups/RG_NAME/providers/Microsoft.Storage/storageAccounts/ACCOUNT_NAME"
If you're running an application that uses a managed identity, assign the role to the managed identity's object ID instead of a user account. To find that ID, go to Your App Service / VM / Function App → Identity → System assigned → Object (principal) ID.
After assigning the role, verify your access with:
az storage container list --account-name YOUR_ACCOUNT --auth-mode login
A successful response returns a JSON array of containers. If you still get 403, check that you're not being blocked by a Deny assignment, these take precedence over role assignments and are often set by Azure Policy or Blueprints in enterprise tenants.
One of the quietest ways Azure Blob Storage breaks is through network-level firewall rules. Your credentials are valid, your role assignments are correct, but the storage account's network configuration is silently dropping your traffic. The error you get, typically a 403 with the code AuthorizationFailure, looks identical to an auth error, which is why this is so hard to diagnose.
Navigate to your storage account in the portal. In the left menu, click Networking (under Security + networking). You'll see the Firewalls and virtual networks tab.
If Public network access is set to Disabled, only traffic from approved private endpoints can reach your blobs. If it's set to Enabled from selected virtual networks and IP addresses, only whitelisted sources get through.
To add your current IP quickly for testing:
- On the Networking blade, select Enabled from selected virtual networks and IP addresses.
- Under Firewall, check Add your client IP address.
- Click Save at the top.
To add a specific IP range via Azure CLI:
az storage account network-rule add \
--resource-group YOUR_RG \
--account-name YOUR_ACCOUNT \
--ip-address 203.0.113.0/24
If you're running workloads inside Azure (VMs, App Services, Functions), the right approach is to add your VNet and subnet as an approved network, not to open public access. Use the Add existing virtual network option on the Networking blade and select your VNet. You'll need to enable the Microsoft.Storage service endpoint on the subnet first, the portal will prompt you to do this inline.
After saving firewall changes, wait 30–60 seconds and retry your request. A successful result means traffic is now reaching the account and auth is taking over.
If you're building a web application that uploads files directly to Azure Blob Storage from the browser, without going through your backend server, CORS is almost certainly going to bite you at some point. The browser will block the upload with an error like Access to fetch at 'https://ACCOUNT.blob.core.windows.net/...' from origin 'https://yourapp.com' has been blocked by CORS policy. This shows up in the browser console, not in Azure logs, which is why developers often think it's an Azure-side permission issue.
CORS rules on a storage account tell Azure which browser origins, HTTP methods, and headers are allowed when making cross-origin requests. By default, CORS is not configured, meaning all browser-originated requests are blocked regardless of auth.
To configure CORS via Azure CLI:
az storage cors add \
--account-name YOUR_ACCOUNT \
--services b \
--methods GET PUT POST DELETE OPTIONS \
--origins "https://yourapp.com" \
--allowed-headers "*" \
--exposed-headers "*" \
--max-age 200
The --services b flag targets the blob service specifically. For development, you might temporarily use --origins "*" to confirm CORS is the issue, but never leave wildcard origins in production.
To check your current CORS rules via PowerShell:
$ctx = New-AzStorageContext -StorageAccountName "YOUR_ACCOUNT" -UseConnectedAccount
Get-AzStorageCORSRule -ServiceType Blob -Context $ctx
You can also set CORS rules in the portal: go to your storage account → Resource sharing (CORS) under Settings → Blob service tab. Add a row with your allowed origin, methods, and headers, then click Save.
One thing I've seen trip up teams: CORS rules are cached aggressively by browsers. After adding a rule, do a hard refresh (Ctrl+Shift+R) or test in an incognito window. If the CORS preflight OPTIONS request now returns a 200 with the correct Access-Control-Allow-Origin header, you're fixed.
Shared Access Signatures (SAS) are time-limited, permission-scoped tokens that let you grant temporary access to specific blobs or containers without exposing your storage account key. They're incredibly useful, and incredibly fragile if not generated correctly. I've seen production apps go down at 3 AM because a SAS token expired and no one set up renewal logic.
Common SAS-related error codes you'll encounter:
AuthenticationFailed, the SAS token signature doesn't match, usually because it was generated with a different account key than the one currently active.SignedAccessNotPermitted, the operation you're attempting isn't included in the SAS token's allowed operations.AuthorizationPermissionMismatch, the SAS token grants less access than the operation requires (e.g., read-only token used for an upload).
To generate a new service-level SAS token for a container via Azure CLI:
az storage container generate-sas \
--account-name YOUR_ACCOUNT \
--name YOUR_CONTAINER \
--permissions rwdl \
--expiry 2026-05-01T00:00:00Z \
--auth-mode login \
--as-user \
--output tsv
The --as-user flag generates a user delegation SAS, signed with Entra ID credentials instead of the account key. This is Microsoft's recommended approach because it doesn't expose your storage key and can be revoked by revoking the identity's access.
If your storage account has Allow storage account key access set to Disabled (which Azure Policy often enforces in enterprise environments), shared key and SAS tokens generated from shared keys will fail entirely. You'll need to switch to Entra ID auth or user delegation SAS tokens exclusively.
Check whether shared key access is enabled:
az storage account show \
--name YOUR_ACCOUNT \
--resource-group YOUR_RG \
--query "allowSharedKeyAccess"
If this returns false, you can't use connection strings or shared key auth at all. Re-architect your app to use DefaultAzureCredential from the Azure SDK, which automatically picks up managed identity, environment credentials, or CLI login depending on the environment.
Advanced Troubleshooting
If the five steps above didn't resolve your Azure Blob Storage problem, you're likely dealing with something deeper, Azure Policy enforcement, enterprise network topology, or a subtle misconfiguration in lifecycle management or redundancy settings. Here's where to look.
Azure Policy Blocking Your Configuration
In enterprise tenants, Azure Policy can silently override your configuration changes. You try to enable public blob access, you save, and it flips back to disabled within seconds. That's Policy enforcing a compliance baseline. To see which policies are affecting your storage account:
- Go to your storage account in the portal.
- Click Policies in the left menu (under Governance).
- Look for policies in a Non-compliant or Deny state.
If you see a Deny policy blocking a setting you need, you'll have to work with your Azure administrator to create an exemption, you can't override Policy assignments without the right permissions at the management group or subscription level.
Diagnosing with Azure Storage Diagnostic Logs
Azure Storage has built-in logging that captures every request, including the exact auth method used, the response code, and the reason for failure. Turn this on immediately when you're troubleshooting:
az monitor diagnostic-settings create \
--name "StorageDiagnostics" \
--resource "/subscriptions/SUB_ID/resourceGroups/RG/providers/Microsoft.Storage/storageAccounts/ACCOUNT/blobServices/default" \
--logs '[{"category":"StorageRead","enabled":true},{"category":"StorageWrite","enabled":true},{"category":"StorageDelete","enabled":true}]' \
--workspace YOUR_LOG_ANALYTICS_WORKSPACE_ID
Once logs flow into Log Analytics, you can query them:
StorageBlobLogs
| where StatusCode == 403
| project TimeGenerated, OperationName, AuthenticationType, StatusText, CallerIpAddress
| order by TimeGenerated desc
The AuthenticationType column tells you exactly what auth method the failing request used, AccountKey, SAS, OAuth, or Anonymous. The StatusText column gives you the specific sub-reason for the failure. This combination tells you in seconds what would take 30 minutes of guessing to figure out otherwise.
BlobFuse2 Mount Failures on Linux
If you're mounting Azure Blob Storage as a filesystem on Linux using BlobFuse2 and getting mount errors, check three things: (1) your config file has valid credentials or a managed identity reference, (2) the allow_other option is set in /etc/fuse.conf if non-root users need access, and (3) your storage account's firewall allows the Linux VM's subnet or IP. BlobFuse2 mount errors often surface as errno 13 (Permission denied) or errno 5 (Input/output error), the former is almost always auth, the latter is usually a network or endpoint issue.
Blob Lifecycle Policy Archiving Data Unexpectedly
If blobs that were in Hot or Cool tier are suddenly returning 403 or appearing inaccessible, check your lifecycle management policy. Blobs moved to Archive tier cannot be read directly, they must be rehydrated first. In the portal, go to Data management → Lifecycle management and review your rules. A misconfigured rule with an overly aggressive "last modified" condition can archive blobs within hours of upload. To rehydrate an archived blob, change its access tier to Hot or Cool explicitly, this can take up to 15 hours for standard priority rehydration.
Escalate to Microsoft Support if: your storage account shows a degraded primary status that persists for more than 30 minutes with no active service health incident; you're seeing data integrity issues (blobs returning corrupted content after a confirmed successful upload); you've lost access to a storage account due to subscription movement or tenant transfer; or your geo-redundant storage failover completed but the secondary endpoint is still returning errors. These are platform-level issues that Microsoft Support has direct tooling to investigate, no amount of portal configuration will fix them from your side.
Prevention & Best Practices
The best Azure Blob Storage troubleshooting session is the one you never have to do. After working with Azure Storage across dozens of enterprise deployments, I've found a handful of practices that prevent the vast majority of access, upload, and configuration problems before they happen.
Use managed identities instead of connection strings wherever possible. Connection strings contain your storage account key, if that string leaks (and they do leak, into git repositories and log files constantly), anyone with it has full access to your storage account until you rotate the key. Managed identities have no secret to leak. They're supported across App Service, Functions, VMs, AKS, and most other Azure compute services. The Azure SDK's DefaultAzureCredential class makes adopting managed identities a one-line change in most cases.
Set up Azure Monitor alerts on your storage account now, not after an incident. At minimum, alert on: availability dropping below 99.9%, egress spiking unexpectedly (potential data exfiltration), and 4xx error rates climbing above your baseline. These alerts give you early warning before a problem becomes a user-facing outage. You can set them up under Monitoring → Alerts on your storage account, use the built-in metric signals, they're pre-defined and accurate.
Document your redundancy choice and test failover annually. Azure Blob Storage offers LRS (3 copies in one datacenter), ZRS (3 copies across availability zones), GRS (LRS + async copy to a secondary region), and GZRS (ZRS + async copy to secondary). Most teams pick GRS because it sounds safest, then discover during an actual regional outage that read access to the secondary endpoint has to be enabled separately via RA-GRS, and failover is manual. Know your redundancy config, know how to trigger failover, and test it before you need it.
Rotate storage account keys on a schedule and version your SAS tokens. If your application still uses shared key auth, rotate your keys quarterly at minimum using Security + networking → Access keys → Rotate key in the portal. When you rotate, the old key immediately stops working, so make sure your app is updated to use the new key before rotating, or use a two-key rotation strategy (update app to key2, rotate key1, update app back to key1, rotate key2).
- Enable soft delete for blobs and containers (Data management → Data protection), it's your undo button for accidental deletions, with a configurable retention period of 1–365 days.
- Tag your storage accounts with environment, team, and cost-center tags from day one, Azure Cost Management uses these tags to break down storage costs by team, which prevents billing surprises at month-end.
- Enable Defender for Storage on all production storage accounts, it detects anomalous access patterns, malware in uploaded files, and sensitive data exposure in real time.
- Use immutability policies (WORM, Write Once, Read Many) on any storage account holding compliance data, audit logs, or regulatory records, once enabled, not even subscription owners can delete the data during the retention period.
Frequently Asked Questions
What is Azure Blob Storage actually used for, is it just file storage?
Azure Blob Storage is Microsoft's cloud object storage for unstructured data, think anything that doesn't fit neatly into rows and columns. In practice, teams use it for serving images and documents directly to browsers, storing video and audio files for streaming, writing application log files, holding backups and disaster recovery snapshots, and as the data layer behind big data analytics pipelines through Azure Data Lake Storage Gen2. It's not a traditional file system (no folder hierarchy by default), though you can simulate folder structure with blob name prefixes and enable hierarchical namespace for true directory semantics with Data Lake Storage Gen2.
Why am I getting a 403 error on Azure Blob Storage even though I'm the subscription owner?
This is the number one question I get on this topic. Being a subscription Owner gives you control over Azure resources, but it does not automatically give you access to the data inside those resources. For blob data specifically, you need one of the storage data-plane roles: Storage Blob Data Owner, Storage Blob Data Contributor, or Storage Blob Data Reader. Go to your storage account → Access Control (IAM) → Add role assignment and assign one of those roles to your identity. Also check that the storage account's firewall rules aren't blocking your IP, and that Allow storage account key access is enabled if you're using a connection string. After adding the role, wait 60–90 seconds before retrying, RBAC propagation isn't instant.
How do I enable public read access to Azure Blob Storage containers?
First, check whether public access is allowed at the storage account level, newer accounts have it disabled by default. Go to Settings → Configuration on your storage account and look for Allow Blob anonymous access. Set it to Enabled and save. Then go to the specific container, click the three-dot menu → Change access level, and set it to Blob (anonymous read access for blobs only) or Container (anonymous read access for the container and its blobs). Note that many enterprise Azure tenants enforce a policy that keeps anonymous access disabled, if your setting keeps reverting, an Azure Policy is overriding you and you'll need your admin to create an exemption.
My AzCopy transfer keeps failing or stalling, how do I fix it?
AzCopy failures almost always come down to one of three things: auth issues, network throttling, or service-side concurrency limits. Start by running azcopy login to authenticate with Entra ID rather than using a SAS token, this removes token expiry as a variable. If transfers stall partway through, check your network for firewall rules blocking outbound HTTPS to *.blob.core.windows.net on port 443. For large transfers that keep getting throttled, add --cap-mbps 100 to limit AzCopy's throughput and avoid hitting storage account egress limits. You can also resume a failed transfer by re-running the same AzCopy command, it will pick up from the last checkpoint automatically using the job log stored in %USERPROFILE%/.azcopy/ on Windows or ~/.azcopy/ on Linux.
What's the difference between Hot, Cool, and Archive storage tiers, and why can't I read my blob?
Azure Blob Storage has three access tiers: Hot for data you access frequently (higher storage cost, lower access cost), Cool for data you access infrequently and store for at least 30 days, and Archive for data you rarely access and can wait hours to retrieve. The key thing to know: blobs in Archive tier are offline, they can't be read directly. When you try to access one, you get a 409 error with code BlobArchived. To read it, you must rehydrate the blob by changing its tier to Hot or Cool. Standard-priority rehydration takes up to 15 hours; high-priority rehydration completes within an hour for blobs under 10 GB. Change the tier in the portal by finding the blob, clicking the three-dot menu, and selecting Change tier.
How do I access Azure Blob Storage from a Linux VM without storing credentials in a config file?
The cleanest way is to assign a system-assigned managed identity to your Linux VM and grant that identity the Storage Blob Data Contributor role on your storage account. Once that's done, you can use BlobFuse2 with managed identity auth, no credentials in any config file, nothing to rotate, nothing to leak. In your BlobFuse2 config file, set auth-type: msi under the azstorage section and leave out account keys entirely. Alternatively, use the Azure CLI from the VM (az login --identity) and then call az storage blob download with --auth-mode login. Both approaches use the VM's managed identity to get a short-lived OAuth token automatically.