6. Integrations
No Azure service is an island, and Blob Storage is the least island-like of all of them — it is the default meeting point between systems that don't know about each other. "Write a file, fire an event" is one of the most-used patterns on the platform.
[Image Prompt: 2D minimalistic hub-and-spoke diagram with Azure Blob Storage at the centre connected by labelled edges to Event Grid, Azure Functions, Azure Data Factory, Azure Databricks, Front Door and CDN, Key Vault, Microsoft Entra ID, and Azure Monitor, flat design, clean vector art style, white background]
The two glue mechanisms that answer most questions
Before the specific pairings, the two patterns that recur across nearly every Azure integration. If you know these, you can usually derive the wiring for a pairing that isn't listed here.
Managed identity + a role assignment — the keyless way one Azure resource authenticates to another. The consuming resource (Function App, Data Factory, VM, AKS workload) gets a system- or user-assigned identity in Microsoft Entra ID; you assign that identity a data-plane role on the storage account or container. No connection string, no key, nothing to rotate, nothing to leak.
# The canonical three lines, for any consumer.
PRINCIPAL=$(az functionapp identity assign -n func-ingest -g rg-app --query principalId -o tsv)
SCOPE=$(az storage account show -n stacmeprod -g rg-data --query id -o tsv)
az role assignment create --assignee-object-id $PRINCIPAL --assignee-principal-type ServicePrincipal \
--role "Storage Blob Data Contributor" --scope "$SCOPE/blobServices/default/containers/raw"
Note the scope: assigning at the container rather than the account is the difference between least privilege and a habit you'll regret.
Private endpoint + Private DNS zone — the way one Azure resource reaches another without traversing
the public internet. For storage, the endpoint targets a specific sub-resource, and you need one per
sub-resource you use: blob, dfs (ADLS Gen2), file, queue, table, web (static website). The
DNS zone is privatelink.blob.core.windows.net, and the mechanism is nothing more than a DNS override
that makes the public hostname resolve to a private IP. When a private endpoint "doesn't work", it is a
DNS problem 90% of the time — check what the client actually resolves before checking anything else.
The pairings
| Pairs with | Why | The glue |
|---|---|---|
| Event Grid | React when a blob is created, deleted, or tiered | A system topic on the storage account emits BlobCreated / BlobDeleted events to any subscriber. This is the modern replacement for polling |
| Azure Functions | Run code when a blob lands | An Event Grid–triggered Function (prefer this over the legacy polling blob trigger), plus a managed identity with Storage Blob Data Contributor |
| Azure Data Factory / Synapse pipelines | Move and transform data at scale | A linked service using the factory's managed identity; the copy activity reads and writes blobs directly. Self-hosted integration runtime if the account is private-only |
| Azure Databricks / Fabric / Synapse Spark | Analytics over a data lake | The ABFS driver against the dfs endpoint on an HNS-enabled account, authenticated by managed identity or Unity Catalog storage credential. Do not mount with account keys |
| Azure Front Door / CDN | Serve objects fast and globally, and cut egress | The blob or static-website endpoint as an origin, optionally via private link origin so the account stays firewalled. Custom domain TLS lives here, not on storage |
| Key Vault | Customer-managed encryption keys, and the secrets you shouldn't be holding | Account encryption configured with a CMK from Key Vault, unwrapped via the storage account's managed identity with Key Vault Crypto Service Encryption User. Requires purge protection on the vault |
| Microsoft Entra ID | Control who reads and writes | Data-plane RBAC roles (Storage Blob Data Reader/Contributor/Owner) — not control-plane Contributor. See Architecture |
| Azure Monitor + Log Analytics | See what's happening | A diagnostic setting on <account>/blobServices/default routing StorageRead/Write/Delete and the Transaction metric to a workspace. Off by default |
| Azure Virtual Network | Keep traffic off the internet | Private endpoint (preferred) or a service endpoint with a VNet rule in the account firewall |
| Azure Backup | Operational and vaulted backup of blob data | A backup vault with a blob backup policy; relies on point-in-time restore for operational tier, so versioning and change feed must be enabled |
| Azure Logic Apps / Power Automate | Low-code file workflows | Built-in Blob connector, ideally with a managed identity connection rather than a key-based one |
| Azure AI Search | Make blob contents actually searchable | A blob indexer crawls the container, cracks documents, and builds an index — the honest answer to "I need to search my blobs" |
| Azure Container Registry, AKS, App Service | Persistent storage for workloads | CSI driver (blob.csi.azure.com) in AKS with workload identity; App Service path mounts. Prefer SDK access over mounting where you control the code |
| Azure Storage Queue / Service Bus | Decouple the processing of uploaded files | Event Grid → queue → worker, so a slow consumer doesn't lose events and you get a dead-letter path |
| Microsoft Defender for Storage | Detect malware uploads and anomalous access | Enable at subscription or account level; findings surface in Defender for Cloud and can gate a quarantine container pattern |
The three patterns worth knowing by heart
1. Drop a file, fire an event
The workhorse. A device, partner, or upstream job writes a blob; Event Grid emits BlobCreated; a
Function, Logic App, or queue consumer picks it up.
[uploader] → [blob container: raw/] → [Event Grid system topic] → [Function / queue] → [curated/]
Three things to get right:
- Filter on the subject. An event subscription can filter by prefix and suffix, so subscribe to
/blobServices/default/containers/raw/blobs/and.csvrather than filtering in code. Cheaper and clearer. - Handle duplicates. Event Grid guarantees at-least-once delivery. Your handler must be idempotent — keying work by blob name plus ETag is the usual approach.
- Prefer Event Grid over the legacy polling blob trigger. The old Functions blob trigger scans the container and can take minutes to notice a file on a large container. The Event Grid–based trigger is push-based and near-immediate.
2. The data lake medallion layout
For an HNS-enabled account, the near-universal convention:
abfss://raw@stacmeprod.dfs.core.windows.net/ ← as-landed, immutable, tiered to Cool at 30 days
abfss://curated@stacmeprod.dfs.core.windows.net/ ← cleaned, conformed, parquet/delta
abfss://published@stacmeprod.dfs.core.windows.net/ ← serving layer, read by BI and applications
Grant each compute identity the narrowest role per container — the ingestion job is Contributor on
raw and nothing else; the BI service principal is Reader on published and nothing else. Directory
ACLs refine it further beneath RBAC, but reach for RBAC at container granularity first: ACLs are
powerful and are also how people end up with permission models nobody can reason about.
3. Public content without a public account
The pattern that satisfies both the CDN team and the security team:
[user] → [Front Door: custom domain, TLS, WAF, caching]
↓ private link origin
[storage account: publicNetworkAccess = Disabled, no anonymous access]
Anonymous public container access stays off. Front Door authenticates to the origin over Private Link,
caches at the edge, terminates your custom domain's certificate, and absorbs the traffic that would
otherwise be egress on your storage bill. The alternative — flipping the container to public — is how
data leaks happen, and allowBlobPublicAccess = false at the account level exists precisely to make it
impossible by accident.
Anti-patterns in integration
- Connection strings in app settings. Every one is a credential with no expiry that ends up in a screenshot eventually. Use a managed identity; if you truly cannot, use a Key Vault reference so the secret at least has one owner and an audit trail.
- Assigning roles at subscription scope because container scope was fiddly. The role assignment you make in five seconds is the one that shows up in an audit in five months.
- A single account shared by every integration. The account is the throughput boundary — see Architecture. An analytics burst that throttles the API tier is the most common self-inflicted outage in the topic.
- Mounting blob storage so a legacy app can use a path, when the real requirement was a file share. BlobFuse and NFS 3.0 are real, and they are also emulation with consistency and locking caveats.
- Polling a container to find new files.
Listis a paged, lexicographic scan. Use events.
Next: Production →
← Back to the Blob Storage overview · ← Previous: Deployment