Back to blog
AzureBest PracticesCloud SecurityIdentity & AccessNetworking

Key Vault Has No Network ACL: Locking Down Azure Secrets Access

Learn why an Azure Key Vault with no network ACL exposes your secrets, and how to lock it down with deny rules, private endpoints, Azure Policy, and IaC.

TL;DR

This check flags Azure Key Vaults that accept traffic from any network because no firewall or network ACL is configured. That leaves your secrets, keys, and certificates reachable from the public internet, gated only by authentication. Fix it by setting the vault's default network action to Deny and allowlisting specific virtual networks, private endpoints, or IP ranges.

Azure Key Vault is where a lot of your most sensitive material lives: TLS certificates, storage account keys, database connection strings, signing keys, and application secrets. By default, a brand new Key Vault is reachable from any network. The only thing standing between an attacker and your secrets is Azure AD authentication and your access policies or RBAC assignments.

That is one layer. The Key Vault Has No Network ACL check exists because relying on a single layer is a bad idea when the resource holds the keys to everything else.


What this check detects

The check looks at the networkAcls configuration on each Key Vault in your subscription and flags a vault when either of these is true:

  • No network ACL block is configured at all, which means the vault accepts traffic from every network.
  • A network ACL exists but the defaultAction is set to Allow, which effectively does the same thing while looking like a firewall is in place.

In Azure terms, a properly locked-down vault has networkAcls.defaultAction set to Deny, with explicit allow rules for the networks that actually need access. Anything else gets flagged.

Note: Network ACLs are separate from access policies and RBAC. Network rules decide where a request can come from. Access policies and RBAC decide who can read or write data once the request arrives. You need both. Locking down the network does not remove the need for least-privilege access control, and vice versa.


Why it matters

An open Key Vault is not automatically a breach. Authentication still applies. But it removes a layer of defense that is cheap to add and expensive to live without.

The realistic attack path

Consider how most Key Vault compromises actually unfold. An attacker rarely walks straight up to the vault. They get there through a leaked credential:

  1. A service principal secret ends up in a public GitHub repo, a CI log, or a stolen developer laptop.
  2. That identity has access to the vault, often broader access than it needed.
  3. Because the vault accepts traffic from anywhere, the attacker authenticates directly from their own machine and pulls every secret the identity can read.

Now flip the network switch. If that same vault only accepts traffic from your virtual network or through a private endpoint, the leaked credential is far less useful. The attacker has the key but cannot reach the door. They would also need to be inside your network, which raises the bar considerably.

Warning: A network ACL is not a substitute for rotating leaked credentials or scoping access tightly. It is defense in depth. Treat it as one of several controls, not a single point you can rely on.

Business and compliance impact

Secrets stored in Key Vault tend to unlock other systems: databases, storage accounts, third-party APIs. A single exposed vault can cascade into a full environment compromise. Beyond the direct risk, frameworks like PCI DSS, SOC 2, and CIS Microsoft Azure Foundations all expect sensitive data stores to restrict network access. An open vault is a common audit finding.


How to fix it

The fix is to set the default action to Deny and then allowlist only the networks that legitimately need access. Order matters here: add your allow rules before you flip the default to deny, or you risk locking out the very applications that depend on the vault.

Danger: Setting defaultAction to Deny blocks all traffic that is not explicitly allowed, including your own deployment pipelines and running applications. If you skip the allow rules, your apps will start failing with 403 errors immediately. Test in a non-production vault first and confirm which networks need access.

Step 1: Identify what currently needs access

Before changing anything, find out who is talking to the vault. Enable Key Vault diagnostic logging if you have not already, then review the AuditEvent logs to see the source IPs and identities making requests. This tells you exactly which networks to allow.

Step 2: Add allow rules with the CLI

Add the IP ranges and virtual network subnets that need access. The subnet must have the Microsoft.KeyVault service endpoint enabled first.

# Enable the Key Vault service endpoint on the subnet
az network vnet subnet update \
  --resource-group my-rg \
  --vnet-name my-vnet \
  --name app-subnet \
  --service-endpoints Microsoft.KeyVault

# Allow that subnet to reach the vault
az keyvault network-rule add \
  --resource-group my-rg \
  --name my-keyvault \
  --subnet /subscriptions/SUB_ID/resourceGroups/my-rg/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/app-subnet

# Allow a specific public IP range (for example, an office or NAT gateway)
az keyvault network-rule add \
  --resource-group my-rg \
  --name my-keyvault \
  --ip-address 203.0.113.0/24

Step 3: Flip the default action to Deny

Once your allow rules are in place and verified, deny everything else.

az keyvault update \
  --resource-group my-rg \
  --name my-keyvault \
  --default-action Deny \
  --bypass AzureServices

Note: The --bypass AzureServices flag lets trusted Microsoft services (like Azure Backup, Azure Disk Encryption, and certain App Service integrations) reach the vault even with the deny rule in place. Set it to None if you want zero exceptions, but confirm no platform features depend on that access first.

Step 4 (recommended): Use a private endpoint instead of public IPs

The strongest configuration removes public access entirely and routes vault traffic through a private endpoint inside your VNet. This gives the vault a private IP and keeps traffic off the internet altogether.

az network private-endpoint create \
  --resource-group my-rg \
  --name kv-private-endpoint \
  --vnet-name my-vnet \
  --subnet app-subnet \
  --private-connection-resource-id $(az keyvault show -n my-keyvault -g my-rg --query id -o tsv) \
  --group-id vault \
  --connection-name kv-connection

After the private endpoint is set up, you can disable public network access entirely:

az keyvault update \
  --resource-group my-rg \
  --name my-keyvault \
  --public-network-access Disabled

Tip: Pair private endpoints with a private DNS zone (privatelink.vaultcore.azure.net) so your applications resolve the vault hostname to its private IP automatically. Without the DNS zone, clients inside the VNet may still resolve the public endpoint and fail.


Fixing it with infrastructure as code

If your vaults are managed with IaC, fix the template so the configuration sticks across deployments rather than drifting back to open.

Terraform

resource "azurerm_key_vault" "main" {
  name                = "my-keyvault"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  tenant_id           = data.azurerm_client_config.current.tenant_id
  sku_name            = "standard"

  public_network_access_enabled = false

  network_acls {
    default_action = "Deny"
    bypass         = "AzureServices"
    ip_rules       = ["203.0.113.0/24"]
    virtual_network_subnet_ids = [azurerm_subnet.app.id]
  }
}

Bicep

resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = {
  name: 'my-keyvault'
  location: location
  properties: {
    tenantId: tenant().tenantId
    sku: { family: 'A', name: 'standard' }
    networkAcls: {
      defaultAction: 'Deny'
      bypass: 'AzureServices'
      ipRules: [ { value: '203.0.113.0/24' } ]
      virtualNetworkRules: [ { id: appSubnet.id } ]
    }
  }
}

How to prevent it from happening again

Fixing one vault is fine. Making sure the next twenty vaults are never open in the first place is what actually moves the needle.

Enforce with Azure Policy

Azure has a built-in policy definition, Azure Key Vault should disable public network access, plus one for requiring private endpoints. Assign these in Deny mode so non-compliant vaults cannot be created at all.

az policy assignment create \
  --name 'deny-kv-public-access' \
  --display-name 'Deny Key Vaults with public network access' \
  --policy 'a049bf6f-d6f0-4c1d-87a2-cab33ed29bef' \
  --scope /subscriptions/SUB_ID \
  --enforcement-mode Default

Tip: Roll out new deny policies in DoNotEnforce mode first. You get a compliance report showing what would have been blocked without breaking anyone, then switch to enforcement once you have cleaned up existing offenders.

Gate it in CI/CD

Catch the misconfiguration before it ever reaches Azure by scanning IaC in your pipeline. Tools like Checkov, tfsec, or terrascan flag open Key Vault network rules on pull requests.

# Fail the build if a Key Vault network rule is misconfigured
checkov -d ./infra --check CKV_AZURE_109

Monitor continuously

Policies and pipeline checks cover what you provision. Continuous monitoring catches drift, manual changes made in the portal during an incident, and resources created outside your normal process. Running the Key Vault Has No Network ACL check on a schedule in Lensix gives you that ongoing coverage and surfaces a vault the moment its rules loosen.


Best practices

  • Default to deny, always. Treat Deny as the baseline for every vault and allowlist deliberately. An open default is a decision you should never have to make.
  • Prefer private endpoints over IP allowlists. Public IP rules work, but they drift as offices move and NAT gateways change. Private endpoints keep traffic off the internet entirely.
  • Separate vaults by environment and blast radius. Do not share one vault between production and development. Scope vaults so a compromise of one does not expose everything.
  • Combine network rules with RBAC and least privilege. Network controls limit where requests come from. RBAC limits what each identity can do. Use both, and grant the narrowest access each app needs.
  • Turn on diagnostic logging. Send AuditEvent logs to a Log Analytics workspace so you can see who accessed what, from where, and when. This is essential for both incident response and tuning your allow rules.
  • Enable soft delete and purge protection. Network rules stop unauthorized reads, but purge protection stops an attacker or a mistake from permanently destroying your keys and certificates.

Locking down Key Vault network access is one of the higher-value, lower-effort security wins in an Azure environment. It takes minutes to configure, costs nothing, and meaningfully shrinks the attack surface around the resource that protects everything else.