Back to blog
AzureBest PracticesCloud SecurityOperations & ComplianceStorage

Blob Storage Has No Immutability Policy: Securing Azure Data Against Tampering

Learn why missing immutability on Azure Blob Storage is a ransomware and compliance risk, and how to apply WORM policies via CLI, portal, and Terraform.

TL;DR

This check flags Azure Storage accounts that store blob data without an immutability policy, leaving critical records open to tampering or deletion. Apply a time-based or legal hold immutability policy at the container or version level to make blobs write-once, read-many.

Immutability is one of those features that nobody thinks about until an auditor asks for it or a ransomware operator deletes a backup. Azure Blob Storage supports write-once, read-many (WORM) policies that prevent blobs from being modified or deleted for a defined period. This Lensix check, storage_immutability, fires when a Storage account holds blob data without any immutability policy configured.

Below we cover what the check looks at, why an unprotected blob store is a real liability, and how to fix and prevent it across the CLI, the portal, and infrastructure as code.


What this check detects

The check inspects your Azure Storage accounts and their blob containers for an active immutability policy. Azure offers two flavors:

  • Time-based retention policies — blobs cannot be modified or deleted until a configured retention interval expires.
  • Legal holds — blobs are locked indefinitely until the named hold is explicitly cleared, useful for litigation or investigations.

Both can be scoped at the container level (applies to all blobs in the container) or, with version-level immutability enabled, at the individual blob version level. When neither is present on an account that stores blobs, Lensix reports the account as failing storage_immutability.

Note: Immutability in Azure is enforced by the storage platform itself, not by IAM. Even an account owner with full RBAC permissions cannot overwrite or delete a blob protected by a locked time-based policy until retention expires. That separation is exactly what makes it valuable against insider threats and compromised credentials.


Why it matters

Blob storage is where organizations park the data that needs to survive: database backups, audit logs, financial records, medical images, security camera footage, and CI artifacts. The shared risk across all of these is that a single delete or overwrite, whether accidental or malicious, can destroy data you legally or operationally cannot afford to lose.

Ransomware and credential compromise

Modern ransomware crews do not just encrypt data, they hunt down and delete backups first so you cannot recover without paying. If your backup blobs live in a container with no immutability policy and an attacker obtains a storage account key or a privileged service principal, your last line of defense disappears in a single API call. A locked time-based retention policy makes those blobs undeletable for the retention window, neutralizing that play.

Danger: A storage account key grants full control over every blob in the account. Without immutability, anyone holding that key can permanently delete your backups. Combine immutability with soft delete and disable shared key access wherever possible.

Compliance and legal exposure

Regulations such as SEC 17a-4, FINRA, HIPAA, and GDPR record-keeping rules expect certain data to be retained in a non-erasable, non-rewritable form for fixed periods. Azure time-based retention with a locked policy is specifically designed to satisfy SEC 17a-4(f) requirements. Without it, you may pass functional tests but fail an audit, and that failure can carry fines well beyond the cost of the storage itself.

Accidental loss and faulty automation

Not every loss is an attack. A misconfigured lifecycle rule, a buggy cleanup script, or a copy-paste mistake in a delete command can wipe production data just as effectively. Immutability gives you a hard floor that no automation can punch through.


How to fix it

You can apply immutability at the container level or, for finer control, at the version level. Here is how to do both.

Option 1: Container-level time-based retention (Azure CLI)

First, set an unlocked policy so you can validate behavior before committing. Unlocked policies can be shortened, extended, or deleted up to five times.

az storage container immutability-policy create \
  --account-name mystorageacct \
  --container-name backups \
  --period 365 \
  --allow-protected-append-writes false

This sets a 365-day retention. To then lock it, fetch the current ETag and lock against it:

# Get the policy's ETag
ETAG=$(az storage container immutability-policy show \
  --account-name mystorageacct \
  --container-name backups \
  --query etag -o tsv)

# Lock the policy (irreversible)
az storage container immutability-policy lock \
  --account-name mystorageacct \
  --container-name backups \
  --if-match $ETAG

Danger: Locking a time-based retention policy is irreversible. Once locked, you cannot delete the policy or shorten the retention period, and blobs cannot be deleted until retention expires. Validate the retention interval carefully with an unlocked policy first. A mistakenly locked 10-year retention on a high-churn container can become very expensive.

Option 2: Version-level immutability

For granular control, enable version-level immutability on the account, which lets you set policies on individual blob versions and even configure account-wide or container-wide defaults.

# Enable blob versioning (prerequisite)
az storage account blob-service-properties update \
  --account-name mystorageacct \
  --resource-group my-rg \
  --enable-versioning true

# Migrate the container to support version-level immutability
az storage container-rm migrate-vlw \
  --storage-account mystorageacct \
  --resource-group my-rg \
  --name backups

Option 3: Azure Portal

  1. Open your Storage account in the Azure Portal.
  2. Under Data storage, select Containers and choose the target container.
  3. Click the ... menu and select Access policy.
  4. Under Immutable blob storage, click Add policy.
  5. Choose Time-based retention, set the retention period in days, and save.
  6. Review behavior, then return and choose Lock policy when ready.

Warning: Immutable blobs still incur storage costs for the full retention period, and you cannot delete them early to save money. A long retention window on a large or fast-growing container can drive bills up significantly. Pair immutability with a lifecycle policy that moves older, still-locked data to the Cool or Archive tier.

Infrastructure as code (Terraform)

Bake immutability into your provisioning so containers are protected from day one:

resource "azurerm_storage_container" "backups" {
  name                  = "backups"
  storage_account_name  = azurerm_storage_account.main.name
  container_access_type = "private"
}

resource "azurerm_storage_container_immutability_policy" "backups" {
  storage_container_resource_manager_id = azurerm_storage_container.backups.resource_manager_id
  immutability_period_in_days           = 365
  protected_append_writes_enabled       = false
  locked                                = false
}

Tip: Keep locked = false in Terraform until your retention values are confirmed in a staging environment. Flipping to locked = true through code is permanent, and Terraform cannot reverse it on a later apply. Treat the lock step as a deliberate, reviewed change rather than something that ships in a routine deploy.


How to prevent it from happening again

One-off fixes drift. The goal is to make unprotected blob storage impossible to ship in the first place.

Azure Policy enforcement

Use Azure Policy to audit or deny storage accounts that lack version-level immutability support. A custom policy can flag any new container that does not carry an immutability configuration, and you can target it at the subscription or management group level.

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Storage/storageAccounts"
      },
      {
        "field": "Microsoft.Storage/storageAccounts/immutableStorageWithVersioning.enabled",
        "notEquals": "true"
      }
    ]
  },
  "then": {
    "effect": "audit"
  }
}

CI/CD policy-as-code gates

Run a policy scanner against your Terraform or Bicep before it merges. Tools like Checkov, tfsec, or Conftest can fail a pull request when a storage container has no immutability block. A minimal Conftest rule using Rego:

# In your pipeline
conftest test plan.json --policy ./policies/

# Example Rego check
# deny if a storage container lacks an immutability policy

Tip: Wire Lensix into your deployment pipeline so the storage_immutability check runs against live infrastructure after every apply, not just against the IaC plan. Drift, manual portal changes, and resources created outside Terraform all get caught when you scan the running account.

Continuous monitoring

Configuration changes happen outside your pipeline more often than anyone admits. Continuous scanning catches a container that was created by hand, a policy that was set unlocked and never locked, or an account spun up by a team that skipped the module. Make this a recurring, automated scan rather than a quarterly manual review.


Best practices

  • Match retention to the data, not a default. Backups, audit logs, and regulated records each have different required retention periods. Pick the value from your compliance obligation, not a round number.
  • Layer your defenses. Immutability protects against deletion, but combine it with blob soft delete, container soft delete, and point-in-time restore for accidental overwrites within the retention window.
  • Disable shared key access where you can. Force Azure AD authentication so a leaked storage account key cannot be used to manipulate data at all.
  • Test before you lock. Always run an unlocked policy first, confirm your applications can still append or write as expected, and only then lock.
  • Mind the cost. Locked blobs cannot be deleted early. Use lifecycle management to tier aging immutable data to Cool or Archive so retention does not become a runaway bill.
  • Document the lock decision. Because locking is irreversible, record who approved it, the retention value, and the business reason. Auditors will ask, and so will the engineer who later wonders why a blob will not delete.

Immutability is cheap insurance against expensive problems. Apply it to the containers that hold your irreplaceable data, enforce it through policy so new accounts inherit it automatically, and let continuous scanning confirm nothing slipped through.