Skip to content

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 Reader role 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.