Skip to main content
emnode
Compliance Medium severity MCSB NS-2

Microsoft Defender for Cloud · Azure SQL Database

Private endpoint connections on Azure SQL Database should be enabled

Written and reviewed by Emnode · Last reviewed

What does the recommendation "Private endpoint connections on Azure SQL Database should be enabled" check?

Flags any logical Azure SQL Database server (Microsoft.Sql/servers) that has no approved private endpoint connection, meaning clients reach it over its public endpoint or service endpoints rather than a private IP inside your virtual network. The check is about the presence of a Private Link connection on the server, which covers every database under it. It does not turn the public endpoint off on its own, does not evaluate firewall rules or 'Deny public network access', and does not apply to Azure SQL Managed Instance or to the flexible-server databases (PostgreSQL or MySQL), which have their own separate recommendations.

Why does "Private endpoint connections on Azure SQL Database should be enabled" matter?

Without a private endpoint, the server is reachable on a public Azure SQL gateway address, so its security depends entirely on firewall rules and credentials that are easy to get wrong: a stray 0.0.0.0 rule or the 'Allow Azure services' toggle quietly opens it to the whole internet or to every other tenant's workloads. A leaked connection string then becomes a direct path to your data from anywhere. A private endpoint pins traffic to a private IP that is only routable from your own network, so even valid credentials are useless to an attacker who cannot reach the address, shrinking the exposed surface and keeping database traffic off the public internet.

How do I fix "Private endpoint connections on Azure SQL Database should be enabled"?

  1. Create a private endpoint against the logical server with az network private-endpoint create, using --private-connection-resource-id pointing at the Microsoft.Sql/servers resource and --group-id sqlServer, then link it to a Private DNS zone (privatelink.database.windows.net) so the server FQDN resolves to the private IP.
  2. Once private connectivity is verified, set 'Deny public network access' on the server (az sql server update --set publicNetworkAccess=Disabled) so clients can no longer reach it over the public endpoint.
  3. Enforce it estate-wide by assigning the built-in audit policy 'Private endpoint connections on Azure SQL Database should be enabled' rather than pasting a GUID: pid=$(az policy definition list --query "[?displayName=='Private endpoint connections on Azure SQL Database should be enabled'].name" -o tsv); az policy assignment create --name sql-pe-required --policy "$pid" --scope <subscription-or-mg-scope>.

Remediation script · bash

# 1. Stand up a private endpoint for a storage account's blob sub-resource,
#    then wire private DNS so the existing hostname resolves to the private IP.
SA_ID=$(az storage account show -g rg-data -n custexportsprod --query id -o tsv)

az network private-endpoint create \
  --name pe-blob-prod \
  --resource-group rg-data \
  --vnet-name vnet-app \
  --subnet snet-privatelink \
  --private-connection-resource-id "$SA_ID" \
  --group-id blob \
  --connection-name pe-blob-prod-conn

# Link the matching private DNS zone and register the A record automatically.
az network private-dns zone create -g rg-data -n privatelink.blob.core.windows.net
az network private-dns link vnet create -g rg-data \
  --zone-name privatelink.blob.core.windows.net \
  --name link-vnet-app --virtual-network vnet-app --registration-enabled false
az network private-endpoint dns-zone-group create \
  --resource-group rg-data --endpoint-name pe-blob-prod \
  --name zg-blob --private-dns-zone privatelink.blob.core.windows.net --zone-name blob

# 2. Only after verifying the app resolves and connects privately, close the public door.
az storage account update -g rg-data -n custexportsprod --public-network-access Disabled

# 3. Ratchet it shut: assign the AUDIT private-link policy by its exact display name,
#    looking up the definition id at runtime (never paste a hardcoded GUID).
pid=$(az policy definition list \
  --query "[?displayName=='Storage account should use a private link connection'].name" -o tsv)
az policy assignment create \
  --name audit-storage-private-link \
  --policy "$pid" \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Full walkthrough (console steps, edge cases and verification) in the lesson Require private endpoints for Azure PaaS services.

Is "Private endpoint connections on Azure SQL Database should be enabled" a false positive?

A server that is only ever reached over a VNet service endpoint, with public network access already denied, still flags here because the control specifically wants a Private Link connection rather than service endpoints. If that design is deliberate and documented, it is a reasonable exception to accept, since service endpoints keep the traffic on the Azure backbone but do not give the server a private IP the way this recommendation expects.