What does public network access actually mean on a managed data service?
A managed data service in Azure does not sit inside your virtual network. An Azure SQL logical server, a key vault, a cache and a PostgreSQL flexible server each get a globally resolvable name and a listener on the public internet the moment they are created, and what differs is the default rule set in front of that listener. A new key vault has its firewall disabled, so any caller reaches the data plane and is stopped only by Microsoft Entra authentication. A new logical SQL server carries no rules and refuses every connection until somebody adds one.
The property people quote in reviews is public network access, and it is narrower than it sounds. On a logical SQL server it holds enabled or disabled, and the portal's selected networks option is still enabled with firewall rules attached. An export showing it enabled tells you the public endpoint is live and the firewall decides who reaches it, and nothing about how permissive those rules are. Disabled is the value that takes the public path out of the picture.
While the endpoint is live, authentication is doing the work people assume a network boundary is doing, so a connection string recovered from a repository or a compromised laptop is usable from any machine on the internet. The posture survives because the create wizard puts networking between the resource name and the review page, and templates get cloned from older projects. By the time somebody with a security remit looks, several integrations depend on the public path and none are written down.
The firewall rule that admits every tenant in Azure
On an Azure SQL logical server there is a checkbox labelled Allow Azure services and resources to access this server. Switching it on creates a server level firewall rule named AllowAllWindowsAzureIps with a start and end address of 0.0.0.0. Microsoft's warning on it is blunt: the server allows communications from all resources inside the Azure boundary regardless of whether they are part of your subscription, and the rule does not restrict access to your subscription or resource group. It occupies one of the 256 server level rules and appears in the master database through the sys.firewall_rules view, which is where to confirm it.
Read against a threat model, the setting removes the network control and leaves the database login as the entire perimeter, exposed to anything running anywhere in Azure. New logical servers created through the portal default to having it off, so the estates carrying it were built years ago, or built from a template that carried the value forward through Bicep, Terraform or ARM. What keeps it enabled is the set of services quietly depending on it, and Microsoft names App Service and Functions, Data Factory, Logic Apps, Stream Analytics and Power BI as common users.
Two platform features break outright when the setting goes off. The import and export service stops working, and has to be replaced by running SqlPackage from a virtual machine in Azure or calling the DACFx API from code. Data sync needs individual firewall rules built from the Sql service tag for the region hosting the hub database, on the servers holding both the hub and the member databases. Neither replacement is hard, and neither happens on its own, which is why the checkbox survives audits.
Three ways to restrict access, and what each one proves
The three mechanisms get presented as three strengths of one control, which is the wrong frame: each demonstrates something different to a reviewer. An IP firewall rule filters on the caller's public source address. A virtual network service endpoint changes the source the service sees, so a rule can name a subnet instead of an address. A private endpoint puts a network interface with a private address from your own subnet in front of one specific resource instance.
The gap that matters is scope. A service endpoint is configured for a service type, so a workload in that subnet can reach any instance of that type willing to admit it, including instances in subscriptions you do not own. Microsoft's data exfiltration walkthrough for Azure SQL works through that case: with service endpoints and network security group service tags you can narrow a virtual machine to SQL in one region, and it still connects to any database in that region. A private endpoint maps to one resource and offers no route to a second, at the cost of a billed resource and a dependency on DNS being correct in every network that resolves the name.
| Control | Destination address | DNS change needed | Works from on-premises | What it proves |
|---|---|---|---|---|
| IP firewall rule | The service's public address | None | Yes, if your egress address is fixed | That the caller's public address was on a list when it connected |
| Virtual network service endpoint | The service's public address, with your subnet as the source | None | No | That traffic came from an approved subnet, and nothing about which instances of that type it can reach |
| Private endpoint | A private address in your subnet mapped to that one resource | A private DNS zone linked to every network that resolves the name | Yes, over VPN or ExpressRoute | That the resource has an address inside your network, and with public access disabled, that no other route exists |
What each network control gives you and what it demonstrates to a reviewer
Why does a private endpoint still resolve to a public IP?
Creating a private endpoint updates the public DNS record so the resource name becomes a CNAME pointing at an equivalent name in a privatelink subdomain. Inside a virtual network linked to the matching private DNS zone, that privatelink name carries an A record holding the endpoint's private address, so the same hostname resolves to a private IP. Outside that network the chain continues on to the public address. The design exists so connection strings never have to change, which is also what makes it hard to audit: nothing in the application or the portal reports which path a connection took.
Nothing looks broken while this is wrong. The application connects, health checks pass, the private endpoint reads as approved, and traffic leaves over the public endpoint with a firewall rule admitting it. The symptom appears later, when the firewall is tightened or public access is disabled and an application that has worked for months stops. The change then gets rolled back and blamed for an outage it only revealed.
Diagnose it by reading the whole resolution chain instead of the final answer. If the name produces no privatelink CNAME, the endpoint's DNS integration was never created and no zone record will fix it. If the chain includes the privatelink name and still ends at a public address, the query is being answered outside your zone, and the causes are a short list.
- The zone holds the right A record but is not linked to the virtual network the client sits in, so the query falls through to public resolution.
- The virtual network uses custom DNS servers, such as a domain controller or a firewall acting as a DNS proxy, and those do not forward privatelink queries to Azure DNS at 168.63.129.16.
- The A record is stale because the private endpoint was deleted and recreated with a different address while the old record stayed behind.
- The caller is not inside the virtual network at all. A hosted build agent, a laptop and a portal session all resolve publicly by design.
- An App Service or Function App has virtual network integration with route all disabled, so only private destination ranges go through the network.
Turning public network access off without an outage
The order is add the private path, prove it carries the traffic, then close the public one. Adding a private endpoint closes nothing by itself, and Microsoft states it plainly: when you add a private endpoint connection, public routing to your logical server is not blocked, and Deny public network access is a separate checkbox left clear by default. Teams that treat the endpoint as the finish line run both paths live with no evidence about which one production uses.
Start with the resource's own audit or diagnostic logs, which record the caller's address on every connection, and read several weeks of them before removing anything. Then create the endpoint, approve the connection, create the private DNS zone and link it to every network that resolves the name. Prove the path from inside before touching the public setting: resolve the hostname from the application subnet, confirm a private address, connect, and read back the address the service saw. On Azure SQL, sys.dm_exec_connections returns the client address the server observed.
Linking the zone has a blast radius of its own. A privatelink zone linked to a virtual network becomes authoritative for that namespace inside the network, and any name whose public record already redirects into the namespace resolves against your zone. Link privatelink.blob.core.windows.net for one storage account and every other storage account with a private endpoint of its own elsewhere starts returning a non-existent domain response inside your network, because your zone holds no record for it. The fix is the virtual network link's resolution policy set to NxDomainRedirect, shown in the portal as fallback to internet.
Two more specifics ruin this change often enough to plan around. Microsoft recommends the Redirect connection policy with private endpoints on Azure SQL, and Redirect needs inbound communication to the network hosting the endpoint and outbound from the client's network across the 1433 to 65535 range, because the handshake starts on 1433 and the session moves to a higher port. Existing private endpoints on the Default policy behave as Proxy on 1433 alone, so a team that tightens security groups to 1433 and later switches to Redirect breaks every connection at once. Azure Database for PostgreSQL flexible server also fixes its networking mode at creation, and a server deployed with virtual network integration is not eligible for a private endpoint.
What still needs the public path after you close it
Everything reaching the resource from outside your virtual network stops at the same instant, so enumerate those callers first. Deployment pipelines are the usual casualty, because hosted build agents run on infrastructure with no relationship to your network, and a migration step or a seed script starts failing. The durable answers are a self hosted agent or a deployment job on compute inside the network. A scripted temporary address rule added at the start of a run and removed at the end also works, provided removal is not conditional on the run succeeding.
Application platforms need more than integration. An App Service or Function App with virtual network integration routes only private destination ranges through the network until route all is turned on, through the site property or the equivalent application setting, so without it the app resolves the public hostname and is rejected by the resource it was just given private access to. It also inherits DNS from the virtual network, so custom resolvers there have to answer privatelink queries.
The trusted service bypasses deserve their own look. On Key Vault, the exception allowing trusted Microsoft services to bypass the firewall continues to apply when public network access is disabled, and the services on that list reach the vault without a private endpoint, so public access disabled does not mean that only your network can reach the resource. The list covers services where Microsoft controls all the code that runs, which is why a platform that lets you run your own code, Azure DevOps among them, needs its own rule or endpoint. Associating the vault with a network security perimeter overrides the bypass and blocks even listed services unless a perimeter rule admits them.
How do you verify it from outside?
Resolution from outside your network keeps returning a public address after you disable public access, and that is not a finding. Microsoft's private endpoint DNS guidance states that the CNAME chain in the public privatelink zone is deliberately resolvable from anywhere so hybrid and phased migrations keep working, and that a successful public lookup confirms only that a resource of that name exists, revealing neither the private address nor any access to it. Reviewers who report a resolving hostname as an exposure spend a remediation cycle on nothing.
The test that settles the matter is a connection attempt from a host with no relationship to your environment. Open a socket to the service port on the public endpoint and try to authenticate with a credential you control. A resource with public access disabled refuses the connection before authentication happens, so the expected result is a network level refusal or a firewall error. An authentication response means the public path is live and something is still admitting you, usually a leftover address rule or an allow Azure services rule nobody removed.
Run the inside test from every network meant to have a path, including the application subnet, the deployment network and the on-premises range across the VPN, because each resolves through a different chain and one is usually missing a zone link. Record the result for each resource as a decision with a name against it, since the ones that stay open are choices somebody has to own. A deny policy at management group scope keeps the next resource from being created open while that list is worked through.
What we check in an Azure security review
The network posture of the data tier changes what a finding is worth, which is why we settle it early. In a penetration test of a cloud hosted application, a connection string recovered from a client side bundle or a pipeline variable is either the end of the engagement or a footnote, and the difference is whether the database answers from the internet. Reporting the credential without establishing that gives a client half an answer, so we probe the data services from an unrelated network in the same exercise.
In an Azure security review the estate pass is mechanical and worth running on a schedule. We query every subscription for the resource types that carry a public network access property, then check each one for a 0.0.0.0 rule or an equivalent platform bypass, for whether a private endpoint exists with its zone linked to the networks using it, and for whether resolution from inside matches what the configuration claims. Where a service is open, the output that gets the change made is the list of callers that would break.
We run the same pass over the systems we build and operate, including Aurii, our own clinical software venture, which is Australian hosted on Azure and handles tenant health data. Australian Privacy Principle 11 requires reasonable steps to protect personal information from unauthorised access, and a data service answering the whole internet because the question was never asked at creation time is hard to defend as reasonable once it is written down. Our approach and trust pages set out how we work.
