Back to blog
AzureBest PracticesCloud SecurityDatabasesNetworking

Cosmos DB Has Public Network Access: Risks and Remediation

Learn why Azure Cosmos DB public network access is risky and how to lock it down with Private Endpoints, IP firewalls, Terraform, and Azure Policy.

TL;DR

This check flags Cosmos DB accounts that accept connections from any public IP on the internet. That exposes your data plane to credential-stuffing, leaked-key abuse, and broad attack surface. Fix it by setting publicNetworkAccess to Disabled and routing traffic through Private Endpoints or scoped firewall rules.

Azure Cosmos DB is a fully managed NoSQL database that, by default, exposes its account endpoint over the public internet. That convenience is also the problem. When an account has public network access enabled with no IP firewall or private networking in place, anyone who reaches the endpoint and holds a valid key or token can read and write your data. The Lensix check cosmosdb_publicaccess catches exactly this configuration so you can lock it down before it becomes an incident.


What this check detects

The check inspects each Cosmos DB account in your subscription and evaluates the publicNetworkAccess property. If it is set to Enabled, the account accepts inbound connections from public IP addresses, subject to any IP firewall rules you may have configured.

An important nuance: publicNetworkAccess being Enabled does not mean wide open to the entire internet on its own. Cosmos DB also has an IP firewall (the ipRules list) and a virtual network rules list. But many accounts leave both empty, which means the firewall allows all source IPs. The combination of public access enabled and no IP restrictions is what creates real exposure.

Note: Cosmos DB authentication uses account keys, resource tokens, or Azure AD (Entra ID) RBAC. Network access controls are a separate layer. Even with valid credentials, a request still has to reach the endpoint. Disabling public access removes the network path for everyone outside your private network.


Why it matters

The endpoint of a Cosmos DB account follows a predictable pattern: https://<account-name>.documents.azure.com. Account names are not secret, and they show up in client config, application logs, browser network traces, and sometimes public repositories. Once an attacker has the endpoint and a key, the only thing between them and your data is the network layer. If that layer is open to the world, you have removed a defense you can't easily add back after a breach.

Here are the concrete ways this goes wrong:

  • Leaked keys become full database access. Cosmos DB primary keys are long-lived and grant complete control over the account. A key committed to a Git repo, baked into a mobile app, or pasted into a support ticket gives an attacker direct access if the endpoint is reachable.
  • Connection strings in CI/CD. Build pipelines and serverless functions frequently store connection strings in environment variables. A compromised pipeline secret plus public access equals data exfiltration with no network hurdle.
  • Broad attack surface for enumeration. A public endpoint can be probed, fuzzed, and targeted by automated scanners looking for misconfigured RBAC or weak token handling.
  • Compliance failures. Frameworks like PCI DSS, HIPAA, and SOC 2 expect data stores to enforce network segmentation. A publicly reachable database with no IP filtering is a common audit finding.

Warning: Rotating a leaked key does not help if you only notice after the attacker has already dumped your collections. Network controls give you a second line of defense that holds even when a credential is compromised.


How to fix it

There are two solid remediation paths. Pick based on how your clients connect.

Option 1: Disable public access and use Private Endpoints

This is the strongest configuration. The account becomes unreachable from the public internet, and traffic flows over a Private Endpoint inside your virtual network.

Danger: Disabling public network access will immediately break any client that connects over the public internet, including App Service apps without VNet integration, on-prem services, and developer laptops. Set up the Private Endpoint and verify connectivity before you disable public access in production.

First, create the Private Endpoint:

az network private-endpoint create \
  --name pe-cosmos-prod \
  --resource-group rg-data-prod \
  --vnet-name vnet-prod \
  --subnet snet-data \
  --private-connection-resource-id "$(az cosmosdb show \
      --name mycosmosaccount \
      --resource-group rg-data-prod \
      --query id -o tsv)" \
  --group-id Sql \
  --connection-name cosmos-connection

Wire up private DNS so clients resolve the endpoint to the private IP:

az network private-dns zone create \
  --resource-group rg-data-prod \
  --name "privatelink.documents.azure.com"

az network private-dns link vnet create \
  --resource-group rg-data-prod \
  --zone-name "privatelink.documents.azure.com" \
  --name dns-link-prod \
  --virtual-network vnet-prod \
  --registration-enabled false

Once the Private Endpoint is confirmed working, disable public access:

az cosmosdb update \
  --name mycosmosaccount \
  --resource-group rg-data-prod \
  --public-network-access DISABLED

Option 2: Keep public access but lock down the IP firewall

If you genuinely need public reachability (for example, a managed service that doesn't support Private Link), scope the firewall to known IPs and enable VNet rules. Never leave the firewall empty while public access is on.

az cosmosdb update \
  --name mycosmosaccount \
  --resource-group rg-data-prod \
  --ip-range-filter "203.0.113.10,198.51.100.0/24" \
  --enable-virtual-network true

Note: Cosmos DB requires you to allow the Azure Portal IP ranges (and sometimes Azure datacenter ranges) if you want to browse data in the portal or use certain Azure services. Check the current Microsoft documentation for the exact ranges rather than guessing.

Terraform example

For teams managing infrastructure as code, set the property explicitly so the secure state is enforced on every apply:

resource "azurerm_cosmosdb_account" "main" {
  name                          = "mycosmosaccount"
  resource_group_name           = azurerm_resource_group.data.name
  location                      = azurerm_resource_group.data.location
  offer_type                    = "Standard"
  kind                          = "GlobalDocumentDB"
  public_network_access_enabled = false

  consistency_policy {
    consistency_level = "Session"
  }

  geo_location {
    location          = azurerm_resource_group.data.location
    failover_priority = 0
  }
}

Tip: If you pair this with a private endpoint resource in the same Terraform module, you get a self-documenting, reproducible secure setup. New environments inherit the locked-down posture automatically instead of relying on someone remembering to flip a flag.


How to prevent it from happening again

Manual fixes drift. The goal is to make the insecure state impossible to create or to catch it before it ships.

Azure Policy

Use a built-in or custom Azure Policy to deny or audit Cosmos DB accounts with public access. Microsoft ships a built-in policy named "Cosmos DB should disable public network access". Assign it in Deny mode on production subscriptions:

az policy assignment create \
  --name deny-cosmos-public \
  --display-name "Deny public Cosmos DB accounts" \
  --policy "797b37f7-06b8-444c-b1ad-fc62867f335a" \
  --scope "/subscriptions/<sub-id>" \
  --params '{"effect":{"value":"Deny"}}'

CI/CD gate

Catch the misconfiguration in pull requests before it reaches Azure. A simple Terraform plan scan with a policy-as-code tool like Checkov or Conftest works well:

# Fail the build if any Cosmos account has public access enabled
checkov -d ./infra --check CKV_AZURE_99 --compact

Tip: Run Lensix continuously alongside your CI gates. Policy-as-code catches what's in your IaC, but Lensix catches drift introduced through the portal, scripts, or third-party tools that bypass your pipeline entirely.


Best practices

  • Default to private. Disable public network access for every account unless you have a documented reason to keep it on. Treat exceptions as deliberate, reviewed decisions.
  • Prefer Entra ID RBAC over account keys. Account keys are long-lived and over-privileged. Use Azure AD authentication with the Cosmos DB data plane RBAC so access is identity-scoped and revocable.
  • Disable key-based metadata write access where possible to reduce the blast radius of a leaked key.
  • Combine layers. Network controls, identity, and key rotation are complementary. None of them is sufficient alone, and the strongest setups use all three.
  • Audit continuously. A one-time fix decays. Schedule recurring scans so a future deployment or a manual portal change doesn't quietly reopen the door.
  • Document your firewall rules. If you use the IP firewall path, keep the allowed ranges in version control with comments explaining why each entry exists. Stale rules are how "temporary" public access becomes permanent.

Disabling public network access on Cosmos DB is one of those changes that costs little and removes an entire category of risk. Get it set, enforce it with policy, and verify it on a schedule so it stays that way.