Storage Account - consider disabling public network access

·

By

Infracost

Storage Account - consider disabling public network access

·

By

Infracost

This FinOps policy recommends disabling public network access on an Azure Storage Account, restricting access to private endpoints and approved virtual networks only. By default, an Azure Storage Account accepts connections from any public IP address, which widens the attack surface for data exfiltration and unauthorized use. This applies to any Storage Account holding data that has no legitimate need to be reachable directly from the internet.

Attribute

Detail

Cloud Provider

Microsoft Azure

Resource Type

Azure Storage Account

Terraform Attribute

public_network_access_enabled on azurerm_storage_account

Compliant Value

false

Cost Impact

Reduces exposure to unauthorized access, data exfiltration, and the incident response cost of a public storage account breach

Why This Policy Matters

How It Helps Reduce Cloud Costs

Disabling public network access on an Azure Storage Account does not reduce the account's own compute or storage bill. It reduces the financial exposure that comes from a preventable security incident.

An exposed Storage Account is a common target for automated internet scanning tools. Unauthorized listing or download activity against a public Storage Account quietly drives up egress costs, and a resulting security incident can require an expensive forensic investigation.

Restricting public network access to private endpoints and approved virtual networks closes that exposure. This does not materially change egress cost patterns for legitimate, in-network traffic.

This policy is about avoiding the cost that a security incident creates, not about lowering a line item on the monthly Azure bill.

Potential Savings

The savings from this policy are avoided-cost savings, not a lower monthly bill for the Storage Account itself.

A publicly exposed Storage Account that gets scraped by automated bots can generate outbound data transfer charges well above the account's normal monthly baseline.

Disabling public network access removes that exposure at close to zero added infrastructure cost. The private endpoint and virtual network resources needed to replace public access are frequently already in place for other workloads in the same environment.

Teams that treat this as a one-time setting, rather than an ongoing review, tend to see accounts reopen to the public internet over time as new integrations get added.

Implementation Guide

Infrastructure-as-Code Example (Terraform)

The following examples show an Azure Storage Account left at its default public setting, and the corrected configuration that restricts it to a private endpoint.

Non-compliant configuration: public network access left at its default

resource "azurerm_storage_account" "reports" {
  name                     = "topcoreportsdata"
  resource_group_name      = azurerm_resource_group.data.name
  location                 = azurerm_resource_group.data.location
  account_tier             = "Standard"
  account_replication_type = "GRS"
  min_tls_version          = "TLS1_2"
}
resource "azurerm_storage_account" "reports" {
  name                     = "topcoreportsdata"
  resource_group_name      = azurerm_resource_group.data.name
  location                 = azurerm_resource_group.data.location
  account_tier             = "Standard"
  account_replication_type = "GRS"
  min_tls_version          = "TLS1_2"
}
resource "azurerm_storage_account" "reports" {
  name                     = "topcoreportsdata"
  resource_group_name      = azurerm_resource_group.data.name
  location                 = azurerm_resource_group.data.location
  account_tier             = "Standard"
  account_replication_type = "GRS"
  min_tls_version          = "TLS1_2"
}

The public_network_access_enabled attribute is not set here, so it defaults to true. This Storage Account accepts connections from any public IP address on the internet. This is a common source of unreviewed exposure on newly created accounts.

Compliant configuration: public network access disabled, private endpoint added

resource "azurerm_storage_account" "reports" {
  name                           = "topcoreportsdata"
  resource_group_name            = azurerm_resource_group.data.name
  location                       = azurerm_resource_group.data.location
  account_tier                   = "Standard"
  account_replication_type       = "GRS"
  min_tls_version                = "TLS1_2"
  public_network_access_enabled  = false

  network_rules {
    default_action             = "Deny"
    bypass                     = ["AzureServices"]
    virtual_network_subnet_ids = [azurerm_subnet.data.id]
  }
}

resource "azurerm_private_endpoint" "reports_blob" {
  name                = "topcoreportsdata-blob-pe"
  resource_group_name = azurerm_resource_group.data.name
  location            = azurerm_resource_group.data.location
  subnet_id           = azurerm_subnet.data.id

  private_service_connection {
    name                           = "topcoreportsdata-blob-psc"
    private_connection_resource_id = azurerm_storage_account.reports.id
    subresource_names              = ["blob"]
    is_manual_connection           = false
  }
}
resource "azurerm_storage_account" "reports" {
  name                           = "topcoreportsdata"
  resource_group_name            = azurerm_resource_group.data.name
  location                       = azurerm_resource_group.data.location
  account_tier                   = "Standard"
  account_replication_type       = "GRS"
  min_tls_version                = "TLS1_2"
  public_network_access_enabled  = false

  network_rules {
    default_action             = "Deny"
    bypass                     = ["AzureServices"]
    virtual_network_subnet_ids = [azurerm_subnet.data.id]
  }
}

resource "azurerm_private_endpoint" "reports_blob" {
  name                = "topcoreportsdata-blob-pe"
  resource_group_name = azurerm_resource_group.data.name
  location            = azurerm_resource_group.data.location
  subnet_id           = azurerm_subnet.data.id

  private_service_connection {
    name                           = "topcoreportsdata-blob-psc"
    private_connection_resource_id = azurerm_storage_account.reports.id
    subresource_names              = ["blob"]
    is_manual_connection           = false
  }
}
resource "azurerm_storage_account" "reports" {
  name                           = "topcoreportsdata"
  resource_group_name            = azurerm_resource_group.data.name
  location                       = azurerm_resource_group.data.location
  account_tier                   = "Standard"
  account_replication_type       = "GRS"
  min_tls_version                = "TLS1_2"
  public_network_access_enabled  = false

  network_rules {
    default_action             = "Deny"
    bypass                     = ["AzureServices"]
    virtual_network_subnet_ids = [azurerm_subnet.data.id]
  }
}

resource "azurerm_private_endpoint" "reports_blob" {
  name                = "topcoreportsdata-blob-pe"
  resource_group_name = azurerm_resource_group.data.name
  location            = azurerm_resource_group.data.location
  subnet_id           = azurerm_subnet.data.id

  private_service_connection {
    name                           = "topcoreportsdata-blob-psc"
    private_connection_resource_id = azurerm_storage_account.reports.id
    subresource_names              = ["blob"]
    is_manual_connection           = false
  }
}

Setting public_network_access_enabled to false blocks the account's public endpoint entirely. The azurerm_private_endpoint resource becomes the only path in for anything outside the approved virtual network.

Infracost's Cloud Security Policies include a named check for this exact pattern, Azure Storage Account - consider disabling public network access, which evaluates the public_network_access_enabled attribute on azurerm_storage_accountresources in pull requests and flags any Storage Account left at its default public setting before the change merges. This policy is available in Infracost, including in the free trial.

Step-by-Step Fix Instructions

  1. List every azurerm_storage_account resource in Terraform state or configuration and check whether public_network_access_enabled is set.

  2. For any account missing the attribute, or set to true, confirm with the owning team that the account does not need direct public access.

  3. Add an azurerm_private_endpoint resource and, where required, network_rules that route traffic through an approved virtual network subnet.

  4. Set public_network_access_enabled to false and run terraform plan to confirm the change does not break a dependent workload.

  5. Apply the change and confirm in the Azure Portal, under the Storage Account's Networking settings, that public network access shows as disabled.

  6. Add Infracost to CI/CD so any future azurerm_storage_account resource that leaves this attribute unset, or sets it to true, gets flagged for review before merge.

Best Practices

  • Default new Storage Account modules to public_network_access_enabled = false, and require an explicit, documented exception before allowing true.

  • Provision the private endpoint and virtual network subnet in the same module as the Storage Account, so both changes land together rather than in a follow-up pull request.

  • Add any Azure service that legitimately needs to reach the Storage Account, such as trusted Microsoft services, to the bypass list on network_rules instead of leaving public access open.

  • This policy does not apply to a Storage Account intentionally configured for static website hosting or another use case that requires public reachability.

  • Review existing Storage Accounts on a recurring basis. Accounts created before this policy was enforced can still have public access enabled.

Tools and Scripts

This check is one of Infracost's built-in Cloud Security Policies. When Infracost runs in CI/CD, it evaluates azurerm_storage_account resources introduced or modified in a pull request and surfaces a finding in the PR comment whenever public_network_access_enabled is missing or set to true, before the change merges.

This gives platform teams a pre-deployment signal instead of discovering an exposed Storage Account after it is already live. Infracost enables teams to track how many Storage Accounts are brought into compliance with this policy over time, and to report that progress to engineering leadership.

To check the current public network access setting using the Azure CLI:

az storage account show --name <storage-account-name> --resource-group <resource-group-name> --query "publicNetworkAccess" -o
az storage account show --name <storage-account-name> --resource-group <resource-group-name> --query "publicNetworkAccess" -o
az storage account show --name <storage-account-name> --resource-group <resource-group-name> --query "publicNetworkAccess" -o

Examples of Impact

Illustrative example: an unreviewed integration project. A team provisions a new Storage Account for a data export job and does not set public_network_access_enabled, leaving it at its default of true. An automated internet scanner discovers the account within days and begins issuing anonymous list and download requests against it. The unexpected egress traffic shows up as an unusual line item on the next billing cycle. Setting public_network_access_enabled to false and requiring a named private endpoint keeps this from recurring.

Illustrative example: a legacy account outside the standard module. An older Storage Account, provisioned before this policy was enforced, is still reachable from the internet. Bringing it into a private endpoint configuration during a routine security review removes the exposure without changing anything for the workloads that depend on it.

(These are illustrative, composite scenarios, not specific customer accounts.)

Considerations and Caveats

  • Breaking existing clients: disabling public network access can break any client that connects to the Storage Account directly over the internet without a private endpoint or an approved virtual network path.

  • Static website hosting is an exception: a Storage Account configured for static website hosting generally requires public access, so this policy does not apply to that use case.

  • Private endpoints need supporting infrastructure: a private endpoint requires a virtual network, subnet, and DNS configuration. Accounts without an existing virtual network need that infrastructure in place first.

  • Trusted services need explicit bypass: some Azure services that access the Storage Account, such as Azure Backup, rely on the AzureServices value in the bypass list on network_rules rather than on public access.

  • Provider-specific: this policy targets the azurerm Terraform provider. Other cloud providers have equivalent public-access controls on their storage services, but the resource and attribute names differ.

Related Policies and Concepts

  • EC2 - consider disabling associate public IP address in launch templates: another FinOps policy focused on removing default public network exposure, applied to AWS EC2 instances rather than Azure Storage Accounts.

  • App Service - consider using latest TLS version: a related Azure-focused FinOps policy covering network and transport security configuration for a different Azure resource type.

  • PostgreSQL - consider using backup retention in non-production projects: a FinOps policy in a different Group focused on the same underlying discipline, closing a default configuration gap before it becomes a cost or risk problem.

  • "How to Enforce Cloud Cost Policies in Your CI/CD Pipeline": a planned Infracost resource article covering the broader workflow of catching configuration issues like this one at the pull request stage, before they reach production.

Frequently Asked Questions (FAQs)

Is this policy supported in Infracost?

Yes. Azure Storage Account - consider disabling public network access is one of Infracost's built-in Cloud Security Policies. It evaluates the public_network_access_enabled attribute on azurerm_storage_account resources in pull requests and flags any Storage Account left at its default public setting. This check is available in the free trial and all paid plans.

Can this policy be customized?

Yes. Teams can scope this policy in Infracost, for example limiting the check to specific resource groups or subscriptions, rather than applying it to every Storage Account by default.

Does Infracost automatically fix violations?

No. Infracost identifies and reports an azurerm_storage_account resource that is missing public_network_access_enabled or has it set to true. Setting up the corresponding private endpoint and applying the fix is a decision the team makes and applies manually.

Is this policy cloud-agnostic?

No. This specific policy targets the Azure Storage Account and its azurerm Terraform provider. Other cloud providers have similar public-access controls on their storage services, but the resource and attribute names differ.

How often should I review Storage Account network access settings?

Teams running Infracost in CI/CD get a check on every pull request that touches an azurerm_storage_account resource. For Storage Accounts already in production, reviewing network access settings quarterly is a reasonable cadence for most teams.

Does disabling public network access affect existing applications?

It can. Disabling public network access on a Storage Account blocks any client that connects over the public internet without a private endpoint or an approved virtual network path. Test connectivity from every dependent workload before applying this change in production.

Create Free Account

This policy is supported in Infracost and available in the free trial. Sign up today and scan your code using our entire library of FinOps policies.

Get started
with Infracost

© 2026 Infracost Inc

Manage cookies

Get started
with Infracost

© 2026 Infracost Inc

Manage cookies

Get started
with Infracost

© 2026 Infracost Inc

Manage cookies