Back to blog
AzureBest PracticesCloud SecurityOperations & ComplianceStorage

Storage Account Not HTTPS-Only: Enforce Secure Transfer on Azure Storage

Learn why Azure Storage accounts must enforce HTTPS-only connections, the risks of allowing HTTP, and how to fix and prevent this misconfiguration with CLI, Terraform, and Azure Policy.

TL;DR

This check flags Azure Storage accounts that allow plain HTTP connections, which exposes data and access keys to interception. Fix it by setting --https-only true on the storage account so every request is forced over TLS.

Azure Storage is one of those services that quietly underpins half of what runs in a subscription: blob containers feeding static sites, file shares mounted by VMs, queues passing messages between functions, and table storage holding application state. Because it sits at the center of so much, the transport security on a storage account matters more than people give it credit for.

The Storage Account Not HTTPS-Only check catches accounts that have the "secure transfer required" setting turned off, meaning Azure will happily accept connections over unencrypted HTTP.


What this check detects

Every Azure Storage account has a property called supportsHttpsTrafficOnly (surfaced in the portal as Secure transfer required). When it is enabled, the storage service rejects any request that arrives over plain HTTP. When it is disabled, both HTTP and HTTPS endpoints work.

Lensix flags the account as failing when supportsHttpsTrafficOnly is set to false. You can confirm the current state yourself:

az storage account show \
  --name mystorageaccount \
  --resource-group my-rg \
  --query "enableHttpsTrafficOnly"

A return value of false means the account accepts cleartext traffic and will fail the check.

Note: Storage accounts created through the portal after late 2019 default to HTTPS-only. The accounts that usually trip this check are older ones, accounts provisioned by scripts or Terraform with the flag left unset, or accounts where someone disabled it to debug a connection issue and never turned it back on.


Why it matters

When a connection runs over HTTP, everything in it travels in the clear: the request, the response body, and critically the authentication material. Azure Storage authenticates requests in a few ways, and most of them are exposed by unencrypted transport:

  • Shared Key authentication signs requests with the account access key. Anyone able to read the traffic can capture the signature and, depending on the request, replay it.
  • SAS tokens are passed as URL query parameters. Over HTTP, the entire token sits in the request line in plaintext, ready to be lifted and reused until it expires.
  • The data itself, whether that is customer records in a blob or messages in a queue, is readable by anything on the network path.

The attacker does not need to break encryption here. They need to be on the path: a compromised router, a rogue access point, a misconfigured VPN, a man-in-the-middle on a shared network segment, or a poisoned DNS entry pointing your app at a proxy. In any of those cases, HTTP storage traffic is an open book.

Warning: A leaked SAS token or account key does not just expose one file. Account keys grant full control over the entire storage account, and broad SAS tokens can read or write across containers. One captured credential can turn into data exfiltration or ransomware-style overwrites.

There is a compliance angle too. PCI DSS, HIPAA, ISO 27001, and the CIS Microsoft Azure Foundations Benchmark all expect data in transit to be encrypted. CIS control 3.1 specifically requires "Secure transfer required" to be enabled on storage accounts. An account failing this check is a finding waiting to show up in your next audit.


How to fix it

The fix is a single property change, and it does not move or re-encrypt any data. It only changes which connections the service will accept going forward.

Azure CLI

az storage account update \
  --name mystorageaccount \
  --resource-group my-rg \
  --https-only true

Verify it took effect:

az storage account show \
  --name mystorageaccount \
  --resource-group my-rg \
  --query "enableHttpsTrafficOnly" \
  --output tsv

Warning: Before flipping this, confirm nothing is connecting over HTTP. Legacy clients, hard-coded http:// URLs, or older SDKs that default to insecure transport will start failing immediately once the flag is on. Grep your codebase and config for http:// storage endpoints first.

Azure Portal

  1. Open the storage account in the Azure portal.
  2. Under Settings, select Configuration.
  3. Set Secure transfer required to Enabled.
  4. Click Save.

PowerShell

Set-AzStorageAccount `
  -ResourceGroupName "my-rg" `
  -Name "mystorageaccount" `
  -EnableHttpsTrafficOnly $true

Terraform

For infrastructure as code, the property lives directly on the storage account resource. On recent versions of the AzureRM provider this defaults to secure, but pin it explicitly so the intent is documented and drift is caught:

resource "azurerm_storage_account" "example" {
  name                     = "mystorageaccount"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  https_traffic_only_enabled = true
  min_tls_version            = "TLS1_2"
}

Tip: While you are in the storage account configuration, set min_tls_version to TLS1_2. Enforcing HTTPS still allows TLS 1.0 and 1.1 by default, both of which are deprecated. Requiring TLS 1.2 closes that gap in the same change.

Fixing many accounts at once

If the check flagged a pile of older accounts, loop over them rather than clicking through the portal one by one:

for acct in $(az storage account list --query "[?enableHttpsTrafficOnly==\`false\`].name" -o tsv); do
  rg=$(az storage account show --name "$acct" --query "resourceGroup" -o tsv)
  echo "Enabling HTTPS-only on $acct in $rg"
  az storage account update --name "$acct" --resource-group "$rg" --https-only true
done

How to prevent it from happening again

Fixing the accounts you have today is half the job. The other half is making sure new accounts can never ship without this setting.

Azure Policy

Azure ships a built-in policy named Secure transfer to storage accounts should be enabled. Assign it with a Deny effect at the subscription or management group level and non-compliant accounts simply cannot be created.

az policy assignment create \
  --name "require-storage-https" \
  --display-name "Require HTTPS-only on storage accounts" \
  --policy "404c3081-a854-4457-ae30-26a93ef643f9" \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000" \
  --params '{"effect":{"value":"Deny"}}'

Note: The GUID 404c3081-a854-4457-ae30-26a93ef643f9 is the built-in policy definition ID for secure transfer. Using Deny blocks new violations outright; if you want to clean up the existing estate gradually, start with Audit and review the compliance report before switching to Deny.

CI/CD gates

Catch the misconfiguration before it ever reaches Azure by scanning IaC in the pipeline. Tools like Checkov, tfsec, and Trivy all carry rules for this. A Checkov run on a Terraform plan fails the build if https_traffic_only_enabled is missing or false:

checkov -d . --check CKV_AZURE_3

Wire that into your pull request checks so a reviewer never has to remember to look for it.

Continuous monitoring

Policy and pipeline checks cover the resources you create through approved paths. Someone with the right permissions can still disable secure transfer manually in the portal. Continuous scanning with Lensix re-evaluates every storage account on a schedule and re-raises the finding the moment the setting drifts, so a temporary debug change does not become a permanent hole.


Best practices

  • Always enable HTTPS-only on new accounts. Treat it as a non-negotiable default in every template and module, not something to bolt on later.
  • Pair it with TLS 1.2 minimum. Encrypted transport on a weak protocol version is only a partial win.
  • Prefer Microsoft Entra ID over account keys. Key-based and SAS auth are the credentials most exposed by HTTP. Using Azure AD identity for data plane access shrinks the blast radius even further.
  • Rotate account keys regularly and audit who can read them. If a key was ever transmitted over HTTP, rotate it.
  • Restrict network access with private endpoints or storage firewall rules so the account is not reachable from the open internet at all, HTTP or otherwise.
  • Audit your whole estate, not just the account you happened to look at. Older subscriptions accumulate accounts from years of different teams and standards.

Tip: Combine the secure transfer policy with policies for minimum TLS version, public network access, and blob public access into a single initiative. Assigning them together gives you a baseline storage security posture you can apply to every subscription with one assignment.

Enforcing HTTPS on storage accounts is one of the cheapest security wins in Azure. It costs nothing, takes seconds, and removes an entire class of credential theft and data interception. Turn it on everywhere, deny anything that lacks it, and keep scanning so it stays that way.