Because the fixed charge is linear in the number of endpoints, the monthly floor climbs in a straight line as you add resources behind Private Link. Six endpoints is about 43.80 US dollars a month before a single request. That is the real argument for a shared endpoint strategy in a hub VNet rather than one endpoint per resource per spoke.
How I would phase in private networking
I do not flip everything private in one change window, because the failure modes hide until the last flag and then you are debugging DNS and trust at once. I phase it. First, add the private endpoint on the account and wire the DNS zones, but leave public access on behind an IP allowlist. Prove that a VM inside the VNet resolves the hostname to the private IP and gets a real completion back. Only then disable public access. If On Your Data is in play, fix the trust settings, the Storage bypass, the Search managed identity and the OpenAI trust, in the same window you go private, not after. Do that and the cutover is a non event.
The verdict for this part is short. Private networking on Azure OpenAI is three moving pieces, an endpoint, its DNS, and the public access flag, and the only hard rule is that the flag comes last. Everything else is checkable. Next up is the identity side of the same problem, Entra ID and managed identities, in Part 10, which is what actually decides who the private caller is allowed to be. Before you close public access anywhere, resolve the hostname from inside the VNet and confirm you get a private address. If that one check passes, the rest holds.
References
Configure a managed virtual network for Microsoft Foundry, Microsoft Learn
Network and access configuration for Azure OpenAI On Your Data, Microsoft Learn
Azure Private Link pricing, Microsoft Azure
| Question | Your own VNet | Foundry managed VNet |
|---|---|---|
| Who builds the endpoints | You do, per resource | Foundry, for the project stores |
| Outbound control | Whatever your NSG and firewall say | Isolation mode, approved FQDN rules |
| Best fit | Direct calls to the resource | Foundry Agent Service, multi store agents |
| Effort | Higher, you own DNS and NSGs | Lower, less to tune |
When On Your Data goes private
This is the failure I see most often, and it only appears once everything is locked down, which is the worst time to find it. The On Your Data feature has Azure OpenAI call Azure AI Search, which in turn reads from a Storage account. Make all three private and turn public access off, and those service to service hops stop working, because a service calling another over a private boundary is not a client on your VNet. It is another Azure service, and it needs an explicit trust path.
Three settings fix it. On the Storage account, allow trusted Azure services to bypass the firewall so Search and OpenAI can reach it by managed identity. On Azure AI Search, switch the API access control to role based so it accepts identity rather than only keys, and give it a system assigned managed identity. On Azure OpenAI, allow Azure AI Search as a trusted service, which shows up as the Microsoft.CognitiveServices trust, so Search can call the embedding endpoint even though the model has no public access. Skip any one of these and the query returns an error that never names the real cause.
Gotcha
If you disabled public access on Azure OpenAI and On Your Data now fails, check trust before you touch DNS. Nine times out of ten the endpoints resolve fine and the real problem is that Azure AI Search has no managed identity, or the model was never told to trust Search. The error message points at neither.
What the private path costs each month
Private Link is not free, and the bill is easy to model because it has only two parts. Every private endpoint carries a fixed hourly charge, and every gigabyte that flows through one carries a data processing fee. At the public list rate that is 0.01 US dollars per endpoint hour and 0.01 US dollars per gigabyte, though the exact figure varies by region, so confirm your region before you promise a number [VERIFY]. A month is about 730 hours, so one endpoint runs roughly 7.30 US dollars a month whether it moves a byte or not.
Worked example
A private RAG stack needs three private endpoints: one for Azure OpenAI, one for Azure AI Search, one for Storage. That is 3 endpoints times 730 hours times 0.01, which is 21.90 US dollars a month in fixed charges before any traffic. Assume 200 GB in and 200 GB out through the endpoints in a month, 400 GB times 0.01, which is 4.00 US dollars. Total, about 25.90 US dollars a month for the private path, on top of model and search costs. The fixed part dominates, so consolidating endpoints matters more than shaving traffic.
Because the fixed charge is linear in the number of endpoints, the monthly floor climbs in a straight line as you add resources behind Private Link. Six endpoints is about 43.80 US dollars a month before a single request. That is the real argument for a shared endpoint strategy in a hub VNet rather than one endpoint per resource per spoke.
How I would phase in private networking
I do not flip everything private in one change window, because the failure modes hide until the last flag and then you are debugging DNS and trust at once. I phase it. First, add the private endpoint on the account and wire the DNS zones, but leave public access on behind an IP allowlist. Prove that a VM inside the VNet resolves the hostname to the private IP and gets a real completion back. Only then disable public access. If On Your Data is in play, fix the trust settings, the Storage bypass, the Search managed identity and the OpenAI trust, in the same window you go private, not after. Do that and the cutover is a non event.
The verdict for this part is short. Private networking on Azure OpenAI is three moving pieces, an endpoint, its DNS, and the public access flag, and the only hard rule is that the flag comes last. Everything else is checkable. Next up is the identity side of the same problem, Entra ID and managed identities, in Part 10, which is what actually decides who the private caller is allowed to be. Before you close public access anywhere, resolve the hostname from inside the VNet and confirm you get a private address. If that one check passes, the rest holds.
References
Configure a managed virtual network for Microsoft Foundry, Microsoft Learn
Network and access configuration for Azure OpenAI On Your Data, Microsoft Learn
Azure Private Link pricing, Microsoft Azure
| Private DNS zone | Covers |
|---|---|
privatelink.openai.azure.com | The classic Azure OpenAI data plane calls |
privatelink.cognitiveservices.azure.com | Account and control surface for the Cognitive Services resource |
privatelink.services.ai.azure.com | The unified Foundry inference surface |
If you run your own DNS, a hub resolver or a custom forwarder, do not link the private zones straight to the spoke VNet. Point conditional forwarders at the resolver and let it own the private zones centrally. This is where split-horizon DNS matters. Inside the VNet the name must return the private IP, everywhere else the public one. When something resolves to the wrong side, this is almost always the cause.
Turn off public access, but not first
Closing the public door is a single flag, --public-network-access Disabled. The mistake is treating it as step one. Flip it before the private endpoint and the DNS zone group exist and you have locked yourself and your app out in the same instant, because the hostname still resolves to a public IP that no longer answers. The fix is boring and it works. Build the private path, prove it resolves, then and only then close the public one.
# 1. Create the private DNS zone for the OpenAI data plane az network private-dns zone create -g rg-ai -n privatelink.openai.azure.com # 2. Link the zone to the VNet that hosts your app az network private-dns link vnet create -g rg-ai -n dns-link --zone-name privatelink.openai.azure.com --virtual-network vnet-ai --registration-enabled false # 3. Create the private endpoint against the Azure OpenAI resource az network private-endpoint create -g rg-ai -n pe-openai --vnet-name vnet-ai --subnet snet-pe --private-connection-resource-id $(az cognitiveservices account show -g rg-ai -n my-openai --query id -o tsv) --group-id account --connection-name openai-conn # 4. Wire a DNS zone group so A records are written automatically az network private-endpoint dns-zone-group create -g rg-ai --endpoint-name pe-openai -n zg-openai --private-dns-zone privatelink.openai.azure.com --zone-name openai # 5. Only now, close the public door az cognitiveservices account update -g rg-ai -n my-openai --public-network-access Disabled
nslookup my-openai.openai.azure.com returns a 10.x address. Failure mode: run step 5 before steps 1 to 4 and every request from the app fails with a connection error, because the name still resolves to the public IP that is now shut.Managed VNet or your own VNet?
There are two ways to get private. In the first you own everything: you create the VNet, the subnet, the private endpoints and the DNS, exactly as the script above does. Full control, more moving parts, and it is the right choice when you call the bare Azure OpenAI resource from your own services. In the second, Azure AI Foundry provisions a managed virtual network around the project compute for you. You pick an isolation mode and Foundry handles the plumbing, including private endpoints to Storage, Cosmos DB and Azure AI Search that the agent uses. Foundry offers two outbound modes: AllowInternetOutbound, which lets the managed compute reach the internet, and AllowOnlyApprovedOutbound, which drops everything except the private endpoints and FQDN rules you approve. Projects created after 25 June 2026 also get a network secured container registry with public access off by default.
My rule is simple. For a plain chat or retrieval app that calls the resource directly, a private endpoint on the account is enough, and the managed VNet is overhead you do not need. Reach for the managed VNet when you run Foundry Agent Service, where the agent executes code and pulls from several backing stores and you want that whole blast radius fenced in one place. The same split shows up on AWS, where a VPC endpoint on Bedrock plays the role of the private endpoint here; I compared that path in the AWS series on Bedrock PrivateLink.
| Question | Your own VNet | Foundry managed VNet |
|---|---|---|
| Who builds the endpoints | You do, per resource | Foundry, for the project stores |
| Outbound control | Whatever your NSG and firewall say | Isolation mode, approved FQDN rules |
| Best fit | Direct calls to the resource | Foundry Agent Service, multi store agents |
| Effort | Higher, you own DNS and NSGs | Lower, less to tune |
When On Your Data goes private
This is the failure I see most often, and it only appears once everything is locked down, which is the worst time to find it. The On Your Data feature has Azure OpenAI call Azure AI Search, which in turn reads from a Storage account. Make all three private and turn public access off, and those service to service hops stop working, because a service calling another over a private boundary is not a client on your VNet. It is another Azure service, and it needs an explicit trust path.
Three settings fix it. On the Storage account, allow trusted Azure services to bypass the firewall so Search and OpenAI can reach it by managed identity. On Azure AI Search, switch the API access control to role based so it accepts identity rather than only keys, and give it a system assigned managed identity. On Azure OpenAI, allow Azure AI Search as a trusted service, which shows up as the Microsoft.CognitiveServices trust, so Search can call the embedding endpoint even though the model has no public access. Skip any one of these and the query returns an error that never names the real cause.
Gotcha
If you disabled public access on Azure OpenAI and On Your Data now fails, check trust before you touch DNS. Nine times out of ten the endpoints resolve fine and the real problem is that Azure AI Search has no managed identity, or the model was never told to trust Search. The error message points at neither.
What the private path costs each month
Private Link is not free, and the bill is easy to model because it has only two parts. Every private endpoint carries a fixed hourly charge, and every gigabyte that flows through one carries a data processing fee. At the public list rate that is 0.01 US dollars per endpoint hour and 0.01 US dollars per gigabyte, though the exact figure varies by region, so confirm your region before you promise a number [VERIFY]. A month is about 730 hours, so one endpoint runs roughly 7.30 US dollars a month whether it moves a byte or not.
Worked example
A private RAG stack needs three private endpoints: one for Azure OpenAI, one for Azure AI Search, one for Storage. That is 3 endpoints times 730 hours times 0.01, which is 21.90 US dollars a month in fixed charges before any traffic. Assume 200 GB in and 200 GB out through the endpoints in a month, 400 GB times 0.01, which is 4.00 US dollars. Total, about 25.90 US dollars a month for the private path, on top of model and search costs. The fixed part dominates, so consolidating endpoints matters more than shaving traffic.
Because the fixed charge is linear in the number of endpoints, the monthly floor climbs in a straight line as you add resources behind Private Link. Six endpoints is about 43.80 US dollars a month before a single request. That is the real argument for a shared endpoint strategy in a hub VNet rather than one endpoint per resource per spoke.
How I would phase in private networking
I do not flip everything private in one change window, because the failure modes hide until the last flag and then you are debugging DNS and trust at once. I phase it. First, add the private endpoint on the account and wire the DNS zones, but leave public access on behind an IP allowlist. Prove that a VM inside the VNet resolves the hostname to the private IP and gets a real completion back. Only then disable public access. If On Your Data is in play, fix the trust settings, the Storage bypass, the Search managed identity and the OpenAI trust, in the same window you go private, not after. Do that and the cutover is a non event.
The verdict for this part is short. Private networking on Azure OpenAI is three moving pieces, an endpoint, its DNS, and the public access flag, and the only hard rule is that the flag comes last. Everything else is checkable. Next up is the identity side of the same problem, Entra ID and managed identities, in Part 10, which is what actually decides who the private caller is allowed to be. Before you close public access anywhere, resolve the hostname from inside the VNet and confirm you get a private address. If that one check passes, the rest holds.
References
Configure a managed virtual network for Microsoft Foundry, Microsoft Learn
Network and access configuration for Azure OpenAI On Your Data, Microsoft Learn
Azure Private Link pricing, Microsoft Azure
What a private endpoint actually is
A private endpoint is a network interface with a private IP address, pulled from a subnet you own, that maps to one specific Azure resource over Private Link. When you create one against your Azure OpenAI account, Azure drops a NIC into your subnet, say 10.1.2.4, and every packet to that address rides the Microsoft backbone to the resource. Nothing crosses the public internet.
Here is the detail that trips up most first attempts. The private endpoint does not change the public FQDN of the resource. Your code still calls my-openai.openai.azure.com. What changes is name resolution inside the VNet. You need that hostname to resolve to 10.1.2.4 for callers in the VNet, while public DNS keeps handing out the public address to everyone else. That is the whole trick, and skipping it is the whole trap. A private endpoint with no DNS override is a NIC nobody talks to, because the app still resolves the public name and, once you disable public access, gets nothing back.
The three private DNS zones you cannot skip
To make the private name resolution work you create a private DNS zone, link it to your VNet, and let a DNS zone group on the endpoint write the A records for you. A modern Foundry or Cognitive Services resource answers on more than one hostname suffix, so you generally register three zones, not one. Miss a zone and one API surface resolves privately while another still points at the closed public address, which produces the maddening case where the chat call works and the embeddings call times out.
| Private DNS zone | Covers |
|---|---|
privatelink.openai.azure.com | The classic Azure OpenAI data plane calls |
privatelink.cognitiveservices.azure.com | Account and control surface for the Cognitive Services resource |
privatelink.services.ai.azure.com | The unified Foundry inference surface |
If you run your own DNS, a hub resolver or a custom forwarder, do not link the private zones straight to the spoke VNet. Point conditional forwarders at the resolver and let it own the private zones centrally. This is where split-horizon DNS matters. Inside the VNet the name must return the private IP, everywhere else the public one. When something resolves to the wrong side, this is almost always the cause.
Turn off public access, but not first
Closing the public door is a single flag, --public-network-access Disabled. The mistake is treating it as step one. Flip it before the private endpoint and the DNS zone group exist and you have locked yourself and your app out in the same instant, because the hostname still resolves to a public IP that no longer answers. The fix is boring and it works. Build the private path, prove it resolves, then and only then close the public one.
# 1. Create the private DNS zone for the OpenAI data plane az network private-dns zone create -g rg-ai -n privatelink.openai.azure.com # 2. Link the zone to the VNet that hosts your app az network private-dns link vnet create -g rg-ai -n dns-link --zone-name privatelink.openai.azure.com --virtual-network vnet-ai --registration-enabled false # 3. Create the private endpoint against the Azure OpenAI resource az network private-endpoint create -g rg-ai -n pe-openai --vnet-name vnet-ai --subnet snet-pe --private-connection-resource-id $(az cognitiveservices account show -g rg-ai -n my-openai --query id -o tsv) --group-id account --connection-name openai-conn # 4. Wire a DNS zone group so A records are written automatically az network private-endpoint dns-zone-group create -g rg-ai --endpoint-name pe-openai -n zg-openai --private-dns-zone privatelink.openai.azure.com --zone-name openai # 5. Only now, close the public door az cognitiveservices account update -g rg-ai -n my-openai --public-network-access Disabled
nslookup my-openai.openai.azure.com returns a 10.x address. Failure mode: run step 5 before steps 1 to 4 and every request from the app fails with a connection error, because the name still resolves to the public IP that is now shut.Managed VNet or your own VNet?
There are two ways to get private. In the first you own everything: you create the VNet, the subnet, the private endpoints and the DNS, exactly as the script above does. Full control, more moving parts, and it is the right choice when you call the bare Azure OpenAI resource from your own services. In the second, Azure AI Foundry provisions a managed virtual network around the project compute for you. You pick an isolation mode and Foundry handles the plumbing, including private endpoints to Storage, Cosmos DB and Azure AI Search that the agent uses. Foundry offers two outbound modes: AllowInternetOutbound, which lets the managed compute reach the internet, and AllowOnlyApprovedOutbound, which drops everything except the private endpoints and FQDN rules you approve. Projects created after 25 June 2026 also get a network secured container registry with public access off by default.
My rule is simple. For a plain chat or retrieval app that calls the resource directly, a private endpoint on the account is enough, and the managed VNet is overhead you do not need. Reach for the managed VNet when you run Foundry Agent Service, where the agent executes code and pulls from several backing stores and you want that whole blast radius fenced in one place. The same split shows up on AWS, where a VPC endpoint on Bedrock plays the role of the private endpoint here; I compared that path in the AWS series on Bedrock PrivateLink.
| Question | Your own VNet | Foundry managed VNet |
|---|---|---|
| Who builds the endpoints | You do, per resource | Foundry, for the project stores |
| Outbound control | Whatever your NSG and firewall say | Isolation mode, approved FQDN rules |
| Best fit | Direct calls to the resource | Foundry Agent Service, multi store agents |
| Effort | Higher, you own DNS and NSGs | Lower, less to tune |
When On Your Data goes private
This is the failure I see most often, and it only appears once everything is locked down, which is the worst time to find it. The On Your Data feature has Azure OpenAI call Azure AI Search, which in turn reads from a Storage account. Make all three private and turn public access off, and those service to service hops stop working, because a service calling another over a private boundary is not a client on your VNet. It is another Azure service, and it needs an explicit trust path.
Three settings fix it. On the Storage account, allow trusted Azure services to bypass the firewall so Search and OpenAI can reach it by managed identity. On Azure AI Search, switch the API access control to role based so it accepts identity rather than only keys, and give it a system assigned managed identity. On Azure OpenAI, allow Azure AI Search as a trusted service, which shows up as the Microsoft.CognitiveServices trust, so Search can call the embedding endpoint even though the model has no public access. Skip any one of these and the query returns an error that never names the real cause.
Gotcha
If you disabled public access on Azure OpenAI and On Your Data now fails, check trust before you touch DNS. Nine times out of ten the endpoints resolve fine and the real problem is that Azure AI Search has no managed identity, or the model was never told to trust Search. The error message points at neither.
What the private path costs each month
Private Link is not free, and the bill is easy to model because it has only two parts. Every private endpoint carries a fixed hourly charge, and every gigabyte that flows through one carries a data processing fee. At the public list rate that is 0.01 US dollars per endpoint hour and 0.01 US dollars per gigabyte, though the exact figure varies by region, so confirm your region before you promise a number [VERIFY]. A month is about 730 hours, so one endpoint runs roughly 7.30 US dollars a month whether it moves a byte or not.
Worked example
A private RAG stack needs three private endpoints: one for Azure OpenAI, one for Azure AI Search, one for Storage. That is 3 endpoints times 730 hours times 0.01, which is 21.90 US dollars a month in fixed charges before any traffic. Assume 200 GB in and 200 GB out through the endpoints in a month, 400 GB times 0.01, which is 4.00 US dollars. Total, about 25.90 US dollars a month for the private path, on top of model and search costs. The fixed part dominates, so consolidating endpoints matters more than shaving traffic.
Because the fixed charge is linear in the number of endpoints, the monthly floor climbs in a straight line as you add resources behind Private Link. Six endpoints is about 43.80 US dollars a month before a single request. That is the real argument for a shared endpoint strategy in a hub VNet rather than one endpoint per resource per spoke.
How I would phase in private networking
I do not flip everything private in one change window, because the failure modes hide until the last flag and then you are debugging DNS and trust at once. I phase it. First, add the private endpoint on the account and wire the DNS zones, but leave public access on behind an IP allowlist. Prove that a VM inside the VNet resolves the hostname to the private IP and gets a real completion back. Only then disable public access. If On Your Data is in play, fix the trust settings, the Storage bypass, the Search managed identity and the OpenAI trust, in the same window you go private, not after. Do that and the cutover is a non event.
The verdict for this part is short. Private networking on Azure OpenAI is three moving pieces, an endpoint, its DNS, and the public access flag, and the only hard rule is that the flag comes last. Everything else is checkable. Next up is the identity side of the same problem, Entra ID and managed identities, in Part 10, which is what actually decides who the private caller is allowed to be. Before you close public access anywhere, resolve the hostname from inside the VNet and confirm you get a private address. If that one check passes, the rest holds.
References
Configure a managed virtual network for Microsoft Foundry, Microsoft Learn
Network and access configuration for Azure OpenAI On Your Data, Microsoft Learn
Azure Private Link pricing, Microsoft Azure
A private endpoint does not hide your resource, it changes what the name resolves to inside your VNet. The DNS zone is the part that actually makes it work. Disable public access last, never first. On Your Data breaks the moment the model and the search index both go private unless you wire trusted-service bypass and managed identity. Budget for a fixed per hour charge on every private endpoint plus a per gigabyte data fee.
az cognitiveservices account update -g rg-ai -n my-openai --public-network-access Disabled. Run it at the wrong moment and the app you shipped last week starts returning connection errors, because the hostname it calls still points at a public address you just closed. Private networking on Azure OpenAI is not hard. The order is what bites people. This part walks the whole path, from what a private endpoint is to the exact sequence I use, and it shows where the On Your Data feature quietly falls over when the model and the index both move behind Private Link.Where private networking sits in the Azure OpenAI picture
Part 8 answered whether the model is reachable at all: the right region, enough quota, a healthy deployment. This part answers a different question. Who can reach it over the network, and from where. By default an Azure OpenAI resource has a public endpoint. The hostname my-openai.openai.azure.com resolves on the public internet, and anyone with a valid key or Entra token can call it. For plenty of workloads that is fine. Auth is doing the real work, and the traffic is TLS the whole way.
Regulated workloads want more than that. They want the request to never touch the public internet, so a stolen key cannot be replayed from a coffee shop and a network capture never sees the path. That is what Private Link buys you. There are two layers to keep straight. First, the resource has its own networking settings: a public access toggle and a list of private endpoints. Second, if you build on Azure AI Foundry projects rather than calling the bare resource, Foundry can wrap the agent and its compute in a managed virtual network. A virtual network, or VNet, is your private address space in Azure. A private endpoint is a network card inside that space that stands in for a specific Azure resource. Private Link is the Microsoft backbone path between the two. Get those three ideas straight and the rest is wiring.
What a private endpoint actually is
A private endpoint is a network interface with a private IP address, pulled from a subnet you own, that maps to one specific Azure resource over Private Link. When you create one against your Azure OpenAI account, Azure drops a NIC into your subnet, say 10.1.2.4, and every packet to that address rides the Microsoft backbone to the resource. Nothing crosses the public internet.
Here is the detail that trips up most first attempts. The private endpoint does not change the public FQDN of the resource. Your code still calls my-openai.openai.azure.com. What changes is name resolution inside the VNet. You need that hostname to resolve to 10.1.2.4 for callers in the VNet, while public DNS keeps handing out the public address to everyone else. That is the whole trick, and skipping it is the whole trap. A private endpoint with no DNS override is a NIC nobody talks to, because the app still resolves the public name and, once you disable public access, gets nothing back.
The three private DNS zones you cannot skip
To make the private name resolution work you create a private DNS zone, link it to your VNet, and let a DNS zone group on the endpoint write the A records for you. A modern Foundry or Cognitive Services resource answers on more than one hostname suffix, so you generally register three zones, not one. Miss a zone and one API surface resolves privately while another still points at the closed public address, which produces the maddening case where the chat call works and the embeddings call times out.
| Private DNS zone | Covers |
|---|---|
privatelink.openai.azure.com | The classic Azure OpenAI data plane calls |
privatelink.cognitiveservices.azure.com | Account and control surface for the Cognitive Services resource |
privatelink.services.ai.azure.com | The unified Foundry inference surface |
If you run your own DNS, a hub resolver or a custom forwarder, do not link the private zones straight to the spoke VNet. Point conditional forwarders at the resolver and let it own the private zones centrally. This is where split-horizon DNS matters. Inside the VNet the name must return the private IP, everywhere else the public one. When something resolves to the wrong side, this is almost always the cause.
Turn off public access, but not first
Closing the public door is a single flag, --public-network-access Disabled. The mistake is treating it as step one. Flip it before the private endpoint and the DNS zone group exist and you have locked yourself and your app out in the same instant, because the hostname still resolves to a public IP that no longer answers. The fix is boring and it works. Build the private path, prove it resolves, then and only then close the public one.
# 1. Create the private DNS zone for the OpenAI data plane az network private-dns zone create -g rg-ai -n privatelink.openai.azure.com # 2. Link the zone to the VNet that hosts your app az network private-dns link vnet create -g rg-ai -n dns-link --zone-name privatelink.openai.azure.com --virtual-network vnet-ai --registration-enabled false # 3. Create the private endpoint against the Azure OpenAI resource az network private-endpoint create -g rg-ai -n pe-openai --vnet-name vnet-ai --subnet snet-pe --private-connection-resource-id $(az cognitiveservices account show -g rg-ai -n my-openai --query id -o tsv) --group-id account --connection-name openai-conn # 4. Wire a DNS zone group so A records are written automatically az network private-endpoint dns-zone-group create -g rg-ai --endpoint-name pe-openai -n zg-openai --private-dns-zone privatelink.openai.azure.com --zone-name openai # 5. Only now, close the public door az cognitiveservices account update -g rg-ai -n my-openai --public-network-access Disabled
nslookup my-openai.openai.azure.com returns a 10.x address. Failure mode: run step 5 before steps 1 to 4 and every request from the app fails with a connection error, because the name still resolves to the public IP that is now shut.Managed VNet or your own VNet?
There are two ways to get private. In the first you own everything: you create the VNet, the subnet, the private endpoints and the DNS, exactly as the script above does. Full control, more moving parts, and it is the right choice when you call the bare Azure OpenAI resource from your own services. In the second, Azure AI Foundry provisions a managed virtual network around the project compute for you. You pick an isolation mode and Foundry handles the plumbing, including private endpoints to Storage, Cosmos DB and Azure AI Search that the agent uses. Foundry offers two outbound modes: AllowInternetOutbound, which lets the managed compute reach the internet, and AllowOnlyApprovedOutbound, which drops everything except the private endpoints and FQDN rules you approve. Projects created after 25 June 2026 also get a network secured container registry with public access off by default.
My rule is simple. For a plain chat or retrieval app that calls the resource directly, a private endpoint on the account is enough, and the managed VNet is overhead you do not need. Reach for the managed VNet when you run Foundry Agent Service, where the agent executes code and pulls from several backing stores and you want that whole blast radius fenced in one place. The same split shows up on AWS, where a VPC endpoint on Bedrock plays the role of the private endpoint here; I compared that path in the AWS series on Bedrock PrivateLink.
| Question | Your own VNet | Foundry managed VNet |
|---|---|---|
| Who builds the endpoints | You do, per resource | Foundry, for the project stores |
| Outbound control | Whatever your NSG and firewall say | Isolation mode, approved FQDN rules |
| Best fit | Direct calls to the resource | Foundry Agent Service, multi store agents |
| Effort | Higher, you own DNS and NSGs | Lower, less to tune |
When On Your Data goes private
This is the failure I see most often, and it only appears once everything is locked down, which is the worst time to find it. The On Your Data feature has Azure OpenAI call Azure AI Search, which in turn reads from a Storage account. Make all three private and turn public access off, and those service to service hops stop working, because a service calling another over a private boundary is not a client on your VNet. It is another Azure service, and it needs an explicit trust path.
Three settings fix it. On the Storage account, allow trusted Azure services to bypass the firewall so Search and OpenAI can reach it by managed identity. On Azure AI Search, switch the API access control to role based so it accepts identity rather than only keys, and give it a system assigned managed identity. On Azure OpenAI, allow Azure AI Search as a trusted service, which shows up as the Microsoft.CognitiveServices trust, so Search can call the embedding endpoint even though the model has no public access. Skip any one of these and the query returns an error that never names the real cause.
Gotcha
If you disabled public access on Azure OpenAI and On Your Data now fails, check trust before you touch DNS. Nine times out of ten the endpoints resolve fine and the real problem is that Azure AI Search has no managed identity, or the model was never told to trust Search. The error message points at neither.
What the private path costs each month
Private Link is not free, and the bill is easy to model because it has only two parts. Every private endpoint carries a fixed hourly charge, and every gigabyte that flows through one carries a data processing fee. At the public list rate that is 0.01 US dollars per endpoint hour and 0.01 US dollars per gigabyte, though the exact figure varies by region, so confirm your region before you promise a number [VERIFY]. A month is about 730 hours, so one endpoint runs roughly 7.30 US dollars a month whether it moves a byte or not.
Worked example
A private RAG stack needs three private endpoints: one for Azure OpenAI, one for Azure AI Search, one for Storage. That is 3 endpoints times 730 hours times 0.01, which is 21.90 US dollars a month in fixed charges before any traffic. Assume 200 GB in and 200 GB out through the endpoints in a month, 400 GB times 0.01, which is 4.00 US dollars. Total, about 25.90 US dollars a month for the private path, on top of model and search costs. The fixed part dominates, so consolidating endpoints matters more than shaving traffic.
Because the fixed charge is linear in the number of endpoints, the monthly floor climbs in a straight line as you add resources behind Private Link. Six endpoints is about 43.80 US dollars a month before a single request. That is the real argument for a shared endpoint strategy in a hub VNet rather than one endpoint per resource per spoke.
How I would phase in private networking
I do not flip everything private in one change window, because the failure modes hide until the last flag and then you are debugging DNS and trust at once. I phase it. First, add the private endpoint on the account and wire the DNS zones, but leave public access on behind an IP allowlist. Prove that a VM inside the VNet resolves the hostname to the private IP and gets a real completion back. Only then disable public access. If On Your Data is in play, fix the trust settings, the Storage bypass, the Search managed identity and the OpenAI trust, in the same window you go private, not after. Do that and the cutover is a non event.
The verdict for this part is short. Private networking on Azure OpenAI is three moving pieces, an endpoint, its DNS, and the public access flag, and the only hard rule is that the flag comes last. Everything else is checkable. Next up is the identity side of the same problem, Entra ID and managed identities, in Part 10, which is what actually decides who the private caller is allowed to be. Before you close public access anywhere, resolve the hostname from inside the VNet and confirm you get a private address. If that one check passes, the rest holds.
References
Configure a managed virtual network for Microsoft Foundry, Microsoft Learn
Network and access configuration for Azure OpenAI On Your Data, Microsoft Learn
Azure Private Link pricing, Microsoft Azure


DrJha