Anti-Primer: Azure Blob Storage¶
Everything that can go wrong, will — and in this story, it does.
The Setup¶
A team migrates a file-upload service from S3 to Blob Storage. The engineer has years of S3 experience and treats the storage account the way they'd treat a bucket: a single unit to create once and forget about.
The Timeline¶
Day 1: One Account, Every Workload¶
To move fast, the team puts user uploads, application logs, and a nightly database export all in the same storage account with GZRS redundancy.
Footgun #1: Redundancy is account-wide — six weeks later, finance flags the storage bill. The multi-terabyte log archive and database export didn't need geo-redundant storage, but they're paying GZRS prices because they share an account with data that does.
Day 3: The Contributor Role "Should Be Enough"¶
An engineer is granted Contributor on the storage account to build a reporting pipeline and can't understand why every blob read call returns 403.
Footgun #2: Confusing management-plane Contributor with data access — two hours are lost before someone realizes the management plane and data plane are separate, and a
Storage Blob Data Readerrole assignment was needed all along.
Day 5: The Account Key in the Config File¶
Under deadline pressure, the account key gets pasted directly into an app settings file "temporarily, just to unblock the demo."
Footgun #3: Using account keys in application configuration — the key ships to three environments before anyone remembers to remove it. Rotating it now means coordinating a deploy across all three, in production, during business hours.
Day 10: Archive Tier Looked Free¶
To cut costs fast, a script tiers a month-old batch of "probably unused" blobs straight to Archive without checking retention math.
Footgun #4: Early deletion charges — a customer requests one of those files two weeks later. Not only does it take 12 hours to rehydrate, but deleting the now-inconvenient blob to "clean up" triggers an early-deletion charge because it hadn't met the 180-day minimum retention.
Day 14: Soft Delete Was "Just a Safety Net"¶
Versioning and soft delete get turned on everywhere, on every container, with no retention limits, "just to be safe."
Footgun #5: Versioning/soft delete cost explosion — the high-churn upload container, where users overwrite the same file dozens of times a day, quietly triples in storage size. Every overwrite kept a full billable copy.
Day 18: The Private Endpoint That Didn't Actually Go Private¶
To lock things down, a private endpoint is added for the blob subresource. The team declares the account "private now" and moves on.
Footgun #6: Private endpoint creation does not disable public access — nobody disabled public network access on the account itself. The private endpoint is real, but so is the still-open public endpoint sitting right next to it.
The Aftermath¶
None of these were exotic mistakes. Every one of them is what happens when S3 instincts get applied one-to-one to a service that only looks similar on the surface.
What Should Have Happened¶
- Split storage accounts by redundancy/durability requirement instead of defaulting everything into one account.
- Assign data-plane roles (
Storage Blob Data Reader/Contributor) explicitly — management-plane roles don't imply data access. - Never put an account key in application config; use managed identity plus a scoped data-plane role instead.
- Check minimum retention duration before tiering to Cool/Cold/Archive, and budget for rehydration time when data might be needed again.
- Set explicit, container-appropriate retention on versioning and soft delete rather than turning them on uniformly with no limits.
- Treat "disable public access" as a separate, required step from "add a private endpoint" — the private endpoint doesn't do it for you.