Skip to main content
Migration PlaybookMicrosoft FoundryPrivate EndpointPrivate DNSTerraform / Bicep

Azure OpenAI to Microsoft Foundry: Fixing Private Endpoint & DNS Failures Before the Auto-Upgrade

Microsoft is automatically flipping eligible Azure OpenAI resources to Foundry — the same resource, mutated from kind: OpenAI to kind: AIServices. A Foundry resource answers on three FQDNs where Azure OpenAI answered on one. If the two new private DNS zones do not exist, every new Foundry capability resolves to a public IP or fails outright. This is how to get ahead of it.

The failure signature this guide resolves
# 1. Auto-upgrade status on a private-networked resource (JSON view, API 2026-01-15-preview):
"foundryAutoUpgrade": {
  "mode": "Enabled",
  "scheduledAt": null,
  "status": "Failed: PrivateNetworking"
}

# 2. After a MANUAL kind-flip, the new Foundry FQDN does not resolve privately.
#    It falls through to the PUBLIC IP — silently bypassing your private endpoint:
$ nslookup my-aoai-prod.services.ai.azure.com
Non-authoritative answer:
Name:    my-aoai-prod.services.ai.azure.com
Address: 20.42.65.92          <-- PUBLIC IP. Private Link is being bypassed.

$ nslookup my-aoai-prod.openai.azure.com
Name:    my-aoai-prod.privatelink.openai.azure.com
Address: 10.0.2.4             <-- correct. The OLD zone still works.

# 3. Or, with public access disabled, the call simply dies:
curl: (28) Failed to connect to my-aoai-prod.services.ai.azure.com port 443:
      Connection timed out

Symptom: Existing openai.azure.com calls keep working, but every new Foundry capability (Agent Service, model catalog, Foundry API) fails to resolve or times out.  Failure point: Client → Private DNS zone lookup → no zone exists for the new FQDN → public resolution or timeout.  Default platform behaviour: The kind-flip is non-destructive and preserves your endpoint, keys, and existing zone. It does not create the two additional private DNS zones that Foundry's other two FQDNs require.

3 FQDNs
A Foundry resource answers on openai, cognitiveservices, and services.ai — where Azure OpenAI needed only the first
2 zones
The number of private DNS zones you must add alongside your existing one. Microsoft's own status message names this as the blocker
> 4.57.0
The minimum AzureRM provider version for a non-destructive Terraform kind-flip. Below it, Terraform may plan a destroy/recreate
Deferred
The foundryAutoUpgrade.mode value that buys you time — settable in the portal, Bicep, or Terraform

There is a particular kind of dread that comes from reading "Microsoft is automatically upgrading your resources" in a service notice, especially when those resources sit behind a private endpoint in a locked-down landing zone. The good news is that the auto-upgrade is more careful than the panic suggests — private-networked resources are explicitly held back from the first waves. The bad news is that this is a stay of execution, not a pardon: the same resources become eligible in a later wave, and the manual upgrade path that many teams are already taking has exactly the failure mode everyone fears. Either way, the fix is the same, it is cheap, and you can do it today, entirely ahead of time.

Figure 1 — Anatomy of the kind-flip: what mutates, what survives, and what silently goes missing
BEFORE — Azure OpenAIMicrosoft.CognitiveServices/accountskind: OpenAIResolves on ONE FQDN:openai.azure.com1 private DNS zone needed ✓FLIPauto ormanualAFTER — Microsoft FoundryMicrosoft.CognitiveServices/accountskind: AIServicesResolves on THREE FQDNs:openai.azure.com ✓ (existing)cognitiveservices.azure.com ✗services.ai.azure.com ✗THE GAPThe flip does NOT createthe 2 new private DNS zones.New FQDNs resolve PUBLIC— or not at all.You must pre-create them.✓ PRESERVED BY THE FLIP — this part genuinely is non-destructiveresource name · endpoint · API keys · managed identity · RBAC · fine-tunes · batches · PTU · tags · existing network configYour existing GPT calls keep working after the flip. What breaks is every NEW Foundry capability —Agent Service, the model catalog, the Foundry API — because their FQDNs have no private DNS zone to resolve against.
The kind-flip mutates one property on the same Azure resource. It preserves your endpoint, keys, identity, and existing DNS zone — which is exactly why it feels safe and why the gap goes unnoticed. The resource now answers on two additional FQDNs that have nowhere private to resolve.
01What the "Kind-Flip" Actually Is (and What It Preserves)Concept

Azure OpenAI and Microsoft Foundry are not two different Azure resource types. They are the same resource typeMicrosoft.CognitiveServices/accounts — distinguished by a single kind property. The "upgrade" is therefore not a migration in the traditional sense. Nothing is copied, moved, or recreated. One property mutates in place:

  • kind changes from OpenAI to AIServices
  • properties.allowProjectManagement is set to true
  • A managed identity is configured on the resource

That is the whole operation. Because both variants share the same resource type and management APIs, your existing Azure RBAC assignments and Azure Policy controls continue to apply, and the upgrade preserves the resource name, endpoint, API keys, managed identity, security configurations, fine-tuning jobs, batches, stored completions, and files. Costs do not increase.

This is genuinely non-destructive — and that is the problem

Because so much is preserved, teams reasonably conclude that nothing needs to change on their side. And for the existing Azure OpenAI endpoint, nothing does — it keeps resolving through your existing privatelink.openai.azure.com zone. The gap is invisible until someone tries to use a Foundry feature, at which point they hit an FQDN that your private DNS has never heard of.

Do not over-read the danger

An honest framing matters here, because there is a lot of alarmist commentary about this rollout. The kind-flip will not take your production GPT inference offline. Your existing endpoint, keys, and private DNS zone survive intact. What it will do is quietly leave every new Foundry capability unreachable over private networking — and, worse, resolve those FQDNs to public IPs, which means a client that can reach the internet will silently bypass your private endpoint entirely. That is a compliance problem before it is an availability problem.

02Reality Check: Who Actually Gets Auto-FlippedCorrection

Here is the detail that most coverage of this rollout gets wrong, and it changes your risk posture materially: resources using private networking are not selected for auto-upgrade in the current waves. Microsoft's auto-upgrade documentation defines an explicit status code for precisely this case.

Auto-upgrade status codes — Microsoft.CognitiveServices/accounts
Eligible                      Scheduled for auto-upgrade on the date in scheduledAt.
Completed                     Upgrade done. Resource is now Foundry. scheduledAt is null.
DeferredByCustomer            You deferred it. scheduledAt is null.
RolledBack                    Upgraded, then rolled back to Azure OpenAI.
Failed: CustomerManagedKeys   Not eligible — uses CMK, not in an allow-listed subscription.
Failed: PrivateNetworking     Not yet eligible — uses private networking.
                              "Manually upgrade to configure two additionally
                               required DNS zones."
Failed: WeightsAndBiases      Not eligible — W&B integration is unsupported on Foundry.

So if your Azure OpenAI resource sits behind a private endpoint today, the platform is currently refusing to auto-flip it, and telling you why. That is a safety net — but read the wording carefully. The status is "not yet eligible." The documentation is explicit that the rollout is staged, that resources using security configurations such as private networking or CMK are simply not selected at first, and that once zero-touch support for those configurations becomes available, those resources can be selected later and return to Eligible with a new scheduled date.

Your actual exposure is therefore threefold:

  • The manual upgrade, today. Plenty of teams are clicking the portal's upgrade banner right now to get Agent Service or the wider model catalog. That path has no private-networking guard rail — it is exactly where the DNS gap bites.
  • A future auto-upgrade wave. When zero-touch support for private networking ships, your resource flips from Failed: PrivateNetworking back to Eligible with a scheduled date. You do get advance notice — but if your DNS zones are not already in place, you are now doing network changes against a clock.
  • Drift between environments. Your dev resource has no private endpoint, so it is eligible and gets flipped automatically. Your production resource does not. You now have two resources of different kinds and a template that no longer matches reality.
The right response is preparation, not panic

Nothing is going to break your private-networked resource tonight. But the two DNS zones cost nothing to create, are harmless to have in place before you upgrade, and turn the eventual flip — whenever and however it happens — into a non-event. Create them now, on your own schedule, and the entire problem disappears. That is the rest of this guide.

03Why Private Endpoints Break: The Three-Zone DNS ProblemRoot Cause

Private Link works by overriding public DNS. When a client in your VNet resolves your resource's public hostname, a linked private DNS zone intercepts the lookup and returns the private endpoint's IP instead of the public one. No private zone, no interception — the client resolves the public IP and your private endpoint is bypassed.

The critical fact is that the private endpoint for Microsoft.CognitiveServices/accounts (subresource account) covers three public FQDNs, each with its own corresponding private DNS zone:

Public FQDNRequired private DNS zoneAzure OpenAIFoundry
openai.azure.comprivatelink.openai.azure.comRequired — you have thisStill used (existing endpoint)
cognitiveservices.azure.comprivatelink.cognitiveservices.azure.comOften absentRequired
services.ai.azure.comprivatelink.services.ai.azure.comNot usedRequired

An Azure OpenAI resource behind Private Link typically only ever needed the first zone, so that is the only one most landing zones created. After the flip, the resource answers on all three — but two of them have no private zone to resolve against. Those are the "two additionally required DNS zones" that Microsoft's own Failed: PrivateNetworking status message tells you to configure.

Never call the privatelink FQDN directly

A recurring mistake when people try to "fix" this by hand: requests from clients must use the resource's public custom subdomain as the base URL (for example my-aoai-prod.services.ai.azure.com). Do not point clients at *.privatelink.services.ai.azure.com — that hostname is part of Azure's internal CNAME resolution chain, not a client-facing endpoint. Clients on the VNet use exactly the same connection string as public clients; the private DNS zone does the redirection invisibly.

The silent-failure mode is the dangerous one

If your VNet still has outbound internet access, a missing private zone does not produce a clean error. The client resolves services.ai.azure.com to a public IP and connects over the public internet — traffic that you believe is on the Azure backbone is not. Your security review says "Private Link"; your packets say otherwise. If public network access is disabled on the resource, you instead get an honest timeout. Perversely, the timeout is the better outcome.

Figure 2 — DNS resolution after the flip: two of three FQDNs have nowhere private to land
✗ BROKEN — only one private DNS zone existsCLIENTin your VNetopenai.azure.comzone EXISTS → 10.0.2.4✓ PRIVATEcognitiveservices.azure.comNO ZONE → 20.42.x.x✗ PUBLIC IPservices.ai.azure.comNO ZONE → timeout✗ BYPASSEDAgent Service, model catalog, and the Foundry API all live behind the two FQDNs that resolve publicly — or not at all.✓ FIXED — all three private DNS zones created and VNet-linkedCLIENTin your VNetopenai.azure.comprivatelink zone → 10.0.2.4✓ PRIVATEcognitiveservices.azure.comNEW zone → 10.0.2.4✓ PRIVATEservices.ai.azure.comNEW zone → 10.0.2.4✓ PRIVATE
All three FQDNs point at the same private endpoint IP. The only difference between the broken and fixed states is whether a private DNS zone exists — and is linked to the VNet — to intercept the lookup. Creating the two missing zones is the entire fix.

Architectural Topology: Failing vs Remediated

ComponentFailing configuration (current)Remediated configuration (fix)
Private DNS zonesOnly privatelink.openai.azure.comAll three zones, each VNet-linked
DNS zone groupSingle zone config on the private endpointThree FQDN configs in the endpoint's zone group
New Foundry FQDNsResolve to a public IP — Private Link silently bypassedResolve to the private endpoint IP
Upgrade triggerPortal banner, clicked ad hoc by whoever saw itDeliberate, template-driven, on your schedule
Auto-upgrade postureUnmanaged — mode: Enabled by defaultfoundryAutoUpgrade.mode: Deferred until ready
Terraform providerAzureRM ≤ 4.57.0 — plans a destroy/recreateAzureRM > 4.57.0 — in-place, non-destructive update
IaC stateTemplate says kind: OpenAI; Azure says AIServicesTemplate is the source of truth for the flip
05Pre-Flight: Audit Your Current DNS ZonesAssessment

Before changing anything, establish exactly where you stand: what kind is the resource, is it scheduled for auto-upgrade, and which of the three private DNS zones already exist and are linked to your VNet.

Azure CLI — audit the resource kind and auto-upgrade statusRG="rg-ai-prod"; ACCT="my-aoai-prod" # 1. What kind is it today? az cognitiveservices account show -g $RG -n $ACCT \ --query "{name:name, kind:kind, customDomain:properties.customSubDomainName}" -o jsonc # 2. Is it scheduled for auto-upgrade? The foundryAutoUpgrade block only # appears on SELECTED resources. Requires API 2026-01-15-preview. az rest --method get \ --url "https://management.azure.com/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RG/providers/Microsoft.CognitiveServices/accounts/$ACCT?api-version=2026-01-15-preview" \ --query "properties.foundryAutoUpgrade" -o jsonc # Expect one of: # null → not selected yet # {"status":"Eligible", ...} → SCHEDULED. Act now. # {"status":"Failed: PrivateNetworking"} → held back — but only for now
Azure CLI — which of the three private DNS zones do you actually have?# List the zones present in the subscription az network private-dns zone list \ --query "[?contains(name,'openai') || contains(name,'cognitiveservices') || contains(name,'services.ai')].{zone:name, rg:resourceGroup, links:numberOfVirtualNetworkLinks}" \ -o table # You are looking for ALL THREE: # privatelink.openai.azure.com (you almost certainly have this) # privatelink.cognitiveservices.azure.com (often missing) # privatelink.services.ai.azure.com (almost certainly missing) # Inspect what the private endpoint's DNS zone group is actually wired to az network private-endpoint dns-zone-group list \ -g $RG --endpoint-name "pe-${ACCT}" -o jsonc
  • Record the resource kind. OpenAI means not yet flipped; AIServices means it already happened — check your DNS immediately.
  • Record the auto-upgrade status. Eligible with a scheduledAt date means you have a deadline. Defer it if you are not ready.
  • Confirm the private endpoint IP so you can verify resolution against it later.
  • List existing private DNS zones and their VNet links. A zone that exists but is not linked to the client's VNet is functionally the same as no zone at all.
  • Check hub-and-spoke. In a hub-spoke topology the zones usually live in the hub — every spoke VNet that hosts clients must be linked, or use DNS forwarding.
06Fix 1 — Pre-Create the Two Missing DNS Zones (Bicep)Remediation

This is the core fix, and the reassuring part is that it is safe to apply before you upgrade anything. Creating the two additional private DNS zones on a resource that is still kind: OpenAI is harmless — nothing resolves against them until the resource starts answering on those FQDNs. Deploy this today, and the flip becomes a non-event whenever it arrives.

Bicep — all three private DNS zones, VNet links, and the endpoint zone groupparam location string = resourceGroup().location param vnetId string param accountName string param privateEndpointName string = 'pe-${accountName}' // The three zones a Foundry (AIServices) account resolves against. // The first you already have; the last two are the "two additionally // required DNS zones" from the Failed: PrivateNetworking status message. var dnsZones = [ 'privatelink.openai.azure.com' 'privatelink.cognitiveservices.azure.com' 'privatelink.services.ai.azure.com' ] resource zones 'Microsoft.Network/privateDnsZones@2024-06-01' = [for z in dnsZones: { name: z location: 'global' }] // A zone is useless unless it is LINKED to the VNet the clients live in. resource zoneLinks 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = [for (z, i) in dnsZones: { parent: zones[i] name: 'link-to-vnet' location: 'global' properties: { virtualNetwork: { id: vnetId } registrationEnabled: false } }] // Wire ALL THREE zones into the private endpoint's DNS zone group so Azure // maintains the A records for you automatically. resource pe 'Microsoft.Network/privateEndpoints@2024-05-01' existing = { name: privateEndpointName } resource zoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2024-05-01' = { parent: pe name: 'default' properties: { privateDnsZoneConfigs: [for (z, i) in dnsZones: { name: replace(z, '.', '-') properties: { privateDnsZoneId: zones[i].id } }] } }
Azure CLI — the same fix, if you are not using BicepRG="rg-ai-prod"; ACCT="my-aoai-prod"; VNET="vnet-hub"; PE="pe-my-aoai-prod" for ZONE in privatelink.cognitiveservices.azure.com privatelink.services.ai.azure.com; do # 1. Create the zone az network private-dns zone create -g $RG -n $ZONE # 2. Link it to the VNet — without this, the zone does nothing az network private-dns link vnet create -g $RG -n "link-${ZONE}" \ --zone-name $ZONE --virtual-network $VNET --registration-enabled false done # 3. Add both zones to the private endpoint's DNS zone group. # Azure then creates and maintains the A records automatically. az network private-endpoint dns-zone-group add \ -g $RG --endpoint-name $PE --name default \ --private-dns-zone privatelink.cognitiveservices.azure.com \ --zone-name cognitiveservices az network private-endpoint dns-zone-group add \ -g $RG --endpoint-name $PE --name default \ --private-dns-zone privatelink.services.ai.azure.com \ --zone-name servicesai
Prefer the DNS zone group over hand-written A records

You can create the A records manually, and in a heavily customized DNS estate you may have to. But wherever possible, attach the zones to the private endpoint's DNS zone group and let Azure create and maintain the records. Hand-written A records go stale the moment a private endpoint IP changes, and that failure is far harder to spot than a missing zone.

07Fix 2 — The Terraform Path and the 4.57.0 Destroy TrapCritical

If you manage the resource with Terraform, there is a trap here that is far more dangerous than the DNS gap, and it deserves to be the loudest warning in this guide.

⚠ Read this before you run terraform apply

Microsoft's documentation is explicit: when using the AzureRM provider, you must use a version greater than 4.57.0 for a non-destructive resource update. On older provider versions, changing kind is treated as a ForceNew attribute — Terraform will plan to destroy and recreate the Cognitive Services account.

Destroying that account means destroying your model deployments, fine-tuned models, PTU reservations, stored completions, batches, and files. A "kind flip" turns into a data-loss incident. Always read the plan. If you see -/+ destroy and then create replacement, stop and upgrade the provider.

Terraform — pin the provider FIRST, before touching kindterraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "> 4.57.0" # REQUIRED for a non-destructive kind flip } } } provider "azurerm" { features {} }
Terraform — the kind-flip, done in placeresource "azurerm_cognitive_account" "foundry" { name = "my-aoai-prod" location = azurerm_resource_group.ai.location resource_group_name = azurerm_resource_group.ai.name custom_subdomain_name = "my-aoai-prod" sku_name = "S0" # THE FLIP: OpenAI -> AIServices kind = "AIServices" # Required alongside the flip identity { type = "SystemAssigned" } # Keep your existing network posture — do not relax it during the upgrade public_network_access_enabled = false network_acls { default_action = "Deny" } }
Terraform — the two missing private DNS zones, links, and zone grouplocals { # All three zones a Foundry account resolves against. foundry_dns_zones = [ "privatelink.openai.azure.com", "privatelink.cognitiveservices.azure.com", "privatelink.services.ai.azure.com", ] } resource "azurerm_private_dns_zone" "foundry" { for_each = toset(local.foundry_dns_zones) name = each.value resource_group_name = azurerm_resource_group.ai.name } # A zone with no VNet link resolves nothing. This is the step people skip. resource "azurerm_private_dns_zone_virtual_network_link" "foundry" { for_each = azurerm_private_dns_zone.foundry name = "link-${replace(each.key, ".", "-")}" resource_group_name = azurerm_resource_group.ai.name private_dns_zone_name = each.value.name virtual_network_id = azurerm_virtual_network.spoke.id registration_enabled = false } resource "azurerm_private_endpoint" "foundry" { name = "pe-my-aoai-prod" location = azurerm_resource_group.ai.location resource_group_name = azurerm_resource_group.ai.name subnet_id = azurerm_subnet.pe.id private_service_connection { name = "psc-foundry" private_connection_resource_id = azurerm_cognitive_account.foundry.id subresource_names = ["account"] is_manual_connection = false } # Register ALL THREE zones so Azure maintains the A records itself. private_dns_zone_group { name = "default" private_dns_zone_ids = [for z in azurerm_private_dns_zone.foundry : z.id] } }
Sequence matters

Apply the DNS zones first, confirm they exist and are linked, and only then flip the kind. Doing it in one apply usually works, but splitting it into two applies means that if the flip has a problem, your DNS is already correct and the rollback is trivial. There is no upside to coupling them.

08Fix 3 — Defer the Auto-Upgrade Until You Are ReadyBuy Time

If your resource shows "status": "Eligible" with a scheduledAt date and you are not ready — security review outstanding, DNS zones not deployed, change freeze in effect — you can defer. This is a supported, first-class operation, not a hack.

Bicep — defer the auto-upgrade (keep every other property unchanged)resource account 'Microsoft.CognitiveServices/accounts@2026-01-15-preview' = { name: accountName location: location kind: 'OpenAI' // stay on OpenAI for now sku: { name: 'S0' } properties: { // ... keep ALL your existing properties exactly as they are foundryAutoUpgrade: { mode: 'Deferred' // opt out of the scheduled auto-upgrade } } }
Terraform — defer via AzAPI (and remember the provider floor)# Update your existing AzureRM or AzAPI definition to set the deferral, # then run terraform apply. AzureRM must still be > 4.57.0. resource "azapi_update_resource" "defer_foundry_upgrade" { type = "Microsoft.CognitiveServices/accounts@2026-01-15-preview" resource_id = azurerm_cognitive_account.aoai.id body = { properties = { foundryAutoUpgrade = { mode = "Deferred" } } } }

You can also defer in the portal: open the resource, select Resource upgrade in the left navigation, and choose Defer upgrade. After deferring, the status becomes DeferredByCustomer and scheduledAt becomes null.

Deferral is a pause, not an exit

Be honest with yourself about what deferring buys you: time, not permanence. The direction of travel is clear — Foundry is the consolidated resource, and the Assistants API has a hard retirement date. Use the deferral window to create the DNS zones, run your security review, and upgrade deliberately. Do not use it to do nothing for six months and then get surprised again.

09Rollback: What Blocks It and How to UnblockEscape Hatch

The flip is reversible. If a resource was upgraded — automatically or by someone clicking the banner — and you need to return to Azure OpenAI, you can roll it back. But rollback is blocked by any Foundry-specific sub-resource that cannot exist on an Azure OpenAI account, and the error messages are not always obvious.

Blocker / errorWhy it blocksFix
Foundry projects existProjects are a Foundry-only constructDelete all projects on the resource before rolling back
Connections existFoundry-only sub-resourceDelete connections before rolling back
Non-OpenAI model deploymentsAzure OpenAI kind cannot host non-OpenAI modelsDelete any non-OpenAI deployments (Llama, DeepSeek, etc.)
Azure OpenAI instance quota exceededLimit of 30 Azure OpenAI instances per subscription per regionDelete an unused Azure OpenAI resource, then retry the rollback
AIServices instance quota exceededLimit of 100 AIServices instances per subscription per regionDelete an unused Foundry resource, then retry the upgrade
Leave the DNS zones in place when you roll back

If you roll back to kind: OpenAI, do not tear down the two extra private DNS zones. They are inert on an Azure OpenAI resource — nothing resolves against them — and leaving them means the next upgrade attempt, whenever it comes, needs no network change at all. Deleting them just recreates the problem for your future self.

Validation & Verification: Confirm the Fix

The whole failure mode here is silent — a missing zone resolves to a public IP and everything appears to work. So validation cannot be "the app still runs." It has to be: does each of the three FQDNs resolve to the private endpoint IP, from inside the VNet? Run these from a VM or container in the client subnet, not from your laptop.

Step 1 — Resolve all three FQDNs from inside the VNet# Run from a VM/jumpbox IN the VNet that hosts your clients. ACCT="my-aoai-prod" for FQDN in \ "${ACCT}.openai.azure.com" \ "${ACCT}.cognitiveservices.azure.com" \ "${ACCT}.services.ai.azure.com" do echo "--- $FQDN" nslookup "$FQDN" | grep -A2 "Name:" done # PASS: every one resolves to your PRIVATE endpoint IP (e.g. 10.0.2.4), # via a CNAME through the corresponding privatelink.* zone. # FAIL: any of them returns a public IP (20.x / 40.x / 52.x) — that zone # is missing or not linked to THIS VNet.
Step 2 — Confirm the zone group actually wired all three configsaz network private-endpoint dns-zone-group show \ -g rg-ai-prod --endpoint-name pe-my-aoai-prod --name default \ --query "privateDnsZoneConfigs[].{zone:privateDnsZoneId, records:recordSets[].fqdn}" -o jsonc # PASS: three configs, each with a recordSet resolving to the PE's private IP. # FAIL: only one config → you created the zones but never attached them. # Also confirm each zone is linked to the CLIENT's VNet (not just the hub) az network private-dns link vnet list \ -g rg-ai-prod --zone-name privatelink.services.ai.azure.com -o table
Step 3 — Send a real request over the private path# From inside the VNet. Use the PUBLIC custom subdomain as the base URL — # never the privatelink.* hostname, which is an internal CNAME only. curl -i "https://${ACCT}.openai.azure.com/openai/v1/models" \ -H "api-key: $AZURE_OPENAI_KEY" # PASS: HTTP/1.1 200 OK, and the request traversed the private endpoint. # Now prove the negative — this same call from OUTSIDE the VNet should FAIL # if public network access is disabled. If it SUCCEEDS from your laptop, # your traffic is not private and the whole exercise was cosmetic.
The test that actually matters

Resolving to a private IP proves the zone works. It does not prove your traffic is private, because a client with internet access will happily use a public route if DNS ever hands it one. The decisive test is the negative one: with public network access disabled on the resource, the same call from outside the VNet must fail. If it succeeds, you have a private endpoint that nothing is actually forced to use — which is the exact compliance gap the missing zones create in the first place.

Key Takeaways

Private-networked resources are not being auto-flipped — yet. Microsoft holds them back with a Failed: PrivateNetworking status. But the wording is "not yet eligible": they can return to Eligible in a later wave. This is a stay of execution, not a pardon.
The flip does not break your existing inference. Your openai.azure.com endpoint, keys, and existing DNS zone all survive. What breaks is every new Foundry capability, because two of the three FQDNs have no private DNS zone.
Create the two missing zones now. privatelink.cognitiveservices.azure.com and privatelink.services.ai.azure.com are inert on an Azure OpenAI resource and harmless to add early. Deploy them today and the eventual flip is a non-event.
A zone that is not VNet-linked does nothing. Creating the zone is half the job; linking it to the VNet where the clients actually live is the other half — and in hub-and-spoke, that means every relevant spoke.
Terraform below AzureRM 4.57.0 will destroy your account. Changing kind on an older provider plans a destroy/recreate, taking your model deployments, fine-tunes, and PTU with it. Pin the provider and read the plan.
The dangerous failure is silent, not loud. A missing zone resolves to a public IP, so your app keeps working while quietly bypassing Private Link. Validate with the negative test: from outside the VNet, the call must fail.

Frequently Asked Questions

Will the auto-upgrade break my private endpoint overnight?
Not currently. Resources that use private networking are not selected in the present auto-upgrade waves — they carry a Failed: PrivateNetworking status, and Microsoft's own message directs you to upgrade manually so you can configure the two additional DNS zones. However, the documentation states the rollout is staged and that resources using security configurations can be selected in a later wave once zero-touch support becomes available, at which point you would receive advance notice and a scheduled date. The practical risk today is not the auto-upgrade — it is someone on your team clicking the portal's upgrade banner without realizing the DNS implications. Pre-creating the zones removes the risk from both paths.
Which private DNS zones does a Foundry resource actually need?
Three, because the private endpoint for Microsoft.CognitiveServices/accounts (subresource account) covers three public FQDNs. You need privatelink.openai.azure.com for openai.azure.com, privatelink.cognitiveservices.azure.com for cognitiveservices.azure.com, and privatelink.services.ai.azure.com for services.ai.azure.com. An Azure OpenAI deployment typically only ever needed the first, which is why the other two are usually missing — and those are the "two additionally required DNS zones" Microsoft refers to. Each zone must also be linked to the virtual network where your clients run, and ideally attached to the private endpoint's DNS zone group so Azure maintains the A records for you.
Is the upgrade reversible, and what stops a rollback?
Yes, the upgrade is reversible — you can roll a Foundry resource back to Azure OpenAI. What blocks a rollback is any Foundry-specific sub-resource that cannot exist on an Azure OpenAI account: Foundry projects, connections, and non-OpenAI model deployments all have to be deleted first. You can also be blocked by quota, since there are per-subscription-per-region limits on both resource kinds (30 Azure OpenAI instances, 100 AIServices instances), so a rollback can fail simply because you have no Azure OpenAI headroom left in that region. One piece of advice: if you do roll back, leave the two extra private DNS zones in place. They are inert on an Azure OpenAI resource and having them already there makes the next upgrade attempt a network non-event.
Why did my Terraform plan want to destroy my Cognitive Services account?
Because you are on an AzureRM provider version at or below 4.57.0, where kind is treated as a ForceNew attribute — so changing it from OpenAI to AIServices is planned as a destroy-and-recreate rather than an in-place update. This is genuinely dangerous: destroying the account takes your model deployments, fine-tuned models, PTU reservations, batches, and stored files with it. Microsoft's guidance is explicit that you need a provider version greater than 4.57.0 for a non-destructive resource update. Pin the provider, re-run terraform plan, and confirm the plan shows an in-place update (~) rather than a replacement (-/+) before you apply.

Popular posts from this blog

The Cloud Incumbent: AWS Bedrock Hosts Every Frontier Model and Amazon Is Betting on Neutrality AWS at $37.6 billion quarterly revenue, growing 28%. $13 billion invested in Anthropic. A $100 billion Anthropic-to-AWS commitment. Trainium with $225 billion in customer revenue commitments. The most quietly powerful AI strategy in the race. By Francis Avorgbedor | Azure Engineer  ·  July 4, 2026  ·  14 min read  ·  Amazon · AWS · Cloud AI 74 SEVENAI Momentum Score — Rank #5 $37.6B AWS Q1 2026 revenue — 28% YoY growth ▲ Fastest in 15 quarters $13B Total Amazon investment in Anthropic to date ▲ Strategic anchor 100K+ Customers running Claude on AWS Bedrock ▲ Distribution moat Amazon's AI strategy is built on a thesis that every other Magnificent Seven company is testing against — and that Amazon is uniquely positioned to win regardless of the outcome. The thesis is neutrality. In a race where Microsoft has bet on OpenAI, Google has bet on Gemini, and Meta has bet...
Performance Fix Foundry Local 1.2 Linux ARM64 Embeddings Offline ASR The Edge Latency Drop: Fixing Latency Spikes by Offloading Embeddings to Foundry Local 1.2 You are paying a full cloud round trip — network, TLS, queue, throttle risk — to turn a twelve-word search query into a vector. That is the most expensive way possible to do one of the cheapest computations in your stack. Foundry Local 1.2 now runs on Linux ARM64, which means embeddings and speech recognition can happen on a Raspberry Pi, a Jetson, or a Graviton instance — offline, unmetered, and in single-digit milliseconds. The failure signature this guide resolves # Application Insights — the embedding call, not the LLM, is your tail latency: name p50 p95 p99 calls/day POST /embeddings (cloud) 89 ms 412 ms 3,847 ms 1,240,000 POST /chat/completions (cloud) 940 ms 1,720 ms 2,910 ms 38,000 ^^^^^^^^ ...
  The 500GB System File That Eats Your Hard Drive Something on your Windows 10 drive is consuming hundreds of gigabytes and the normal tools cannot find it. This guide identifies every known culprit — from hibernation files and shadow copies to runaway backups and the Windows component store — and tells you exactly what is safe to delete, what to leave alone, and what the commands actually do.
How to Reset an Azure Virtual Machine to Factory Settings Using a Managed Disk Azure does not have a single "factory reset" button. What it does have is something better: the OS Disk Swap — a method that swaps out the corrupted or misconfigured OS disk for a clean Windows Server managed disk without deleting the VM, its NICs, its IP addresses, or any attached data disks. Here is how it works, when to use it, and the exact steps to execute it safely. FA Francis Avorgbedor Azure Engineer July 16, 2026 15 min read Azure VMs · Windows Server · Real-World Fix 3 Methods to achieve a clean Windows Server installation on an existing Azure VM ~15min Typical OS Disk Swap duration — VM retains its NICs, IPs, and data disks throughout 0 Data disks affected by an OS Disk Swap — data disks remain attached and untouched 1 Snapshot of the original OS disk you must take before starting — no exceptions Introduction Why Azure Does Not Have a Simple Factory Reset — and What to Do Instead On a ph...

AKS CrashLoopBackOff, Pending Pods, and NotReady Nodes — The Real Fixes Engineers Use

Incident Playbook AKS Kubernetes kubectl 2026 AKS CrashLoopBackOff, Pending Pods, and NotReady Nodes — The Real Fixes Engineers Use Every AKS engineer eventually faces the same nightmare: CrashLoopBackOff at 2am, pods stuck Pending for no clear reason, or nodes flipping to NotReady mid-deployment. The difference between panic and control is knowing the exact diagnostic sequence — and the real fixes that work in production. This guide gives you both. 3 commands get pods, describe pod, and logs diagnose roughly 90% of AKS incidents before you touch anything else Exit 137 The code that means OOMKilled — the container hit its memory limit and was killed by the kernel (128 + SIGKILL 9) Events The bottom of kubectl describe is where the real cause lives — Pending, FailedScheduling, and image errors all surface there CoreDNS The single component behind most "intermittent" production failures — service discovery breaks quietly and looks like an app bug Table of Contents 01 The 3 Comm...
Can I Update My Old Computer to Windows 11 — and How Much Will It Cost? Your i7, 16GB RAM, 512GB SSD machine is powerful enough to run Windows 11 comfortably. The TPM 2.0 and Secure Boot wall is a security checkbox, not a performance ceiling. Here are two proven ways to get past it, what each one costs, and what you are trading away by doing so. $0 Cost of the Windows 11 licence if your existing Windows 10 is genuine — the upgrade remains free in 2026 2 Proven methods to bypass TPM 2.0 and Secure Boot — Rufus (easy) and Registry edit (manual) 25H2 Current Windows 11 version — all known bypass methods tested and confirmed working as of July 2026 Oct 2025 Windows 10 end of life — no more security updates. Staying on Windows 10 now carries real risk. First — Check Your BIOS Before Anything Else You Might Not Actually Need a Bypass Before running any bypass, open your BIOS and look at two settings. Many computers that fail the Windows 11 compatibility check have TPM 2.0 present in the hard...
2026 Edition 100 Tools Software Engineering DevOps AIOps Top 100 Best AI Tools for Azure  Engineers and DevOps Professionals in 2026 85% of developers now regularly use AI tools. Fully AI-generated code accounts for nearly 28% of all pull requests. The question is no longer whether to use AI tools — it is which ones, in which combination, for which part of the lifecycle. This guide cuts through the noise: 100 tools, 10 categories, honest pricing, real use cases, and a selection framework for building your stack without redundancy. 85% Percentage of developers who now regularly use AI tools, per JetBrains' 2025 State of Developer Ecosystem report — up from near zero three years ago 28% Share of all pull requests containing primarily AI-generated code in 2026 — the metric that signals AI coding assistants have moved from experiment to workflow $50B Cursor's reported valuation in April 2026 Series D talks — the number that signals investor confidence in the AI developer tools mark...

Azure Files vs Azure NetApp Files: Which One Should You Choose?

Azure Files vs Azure NetApp Files: Which One Should You Choose? Performance tiers, protocol support, dual-protocol capability, pricing models, SAP/Oracle/HPC suitability, data management features, and the decision framework that maps each workload type to the right service — with step-by-step setup procedures for both. FA Francis Avorgbedor Azure Engineer July 15, 2026 20 min read Azure Storage · Architecture 4 Azure Files tiers: Premium SSD, Standard Hot, Cool, Tx Optimized 3 ANF performance tiers: Standard, Premium, Ultra — all SSD-backed 4TiB ANF minimum provisioning — significant cost floor for small workloads Dual ANF serves the same data via SMB and NFS simultaneously — AF cannot Introduction Two Services, One Surface Area — Completely Different Purposes Microsoft offers two fully managed, enterprise-grade file storage services in Azure. They share a surface area — both serve file shares over standard protocols, both run on managed infrastructure, and both integrate with Microsof...
Troubleshooting Guide AKS Kubernetes Real Solutions kubectl Azure Kubernetes Service (AKS) Troubleshooting Guide: Real Solutions to Common Problems CrashLoopBackOff at 2am. Pods stuck Pending with no obvious cause. Nodes going NotReady mid-deployment. DNS resolution silently failing in production. Every AKS engineer encounters these — the difference between engineers who panic and engineers who stay calm is knowing the exact sequence of diagnostic commands to run. This guide gives you that sequence, the root cause analysis for each failure mode, and the fix. 3 commands 90% of AKS problems are diagnosed with the same three kubectl commands: describe pod, logs --previous, and get events — in that order, every time Exit 137 The exit code that tells you everything: container killed by SIGKILL — either the Linux OOM killer (memory limit exceeded) or kubelet after grace period expired 5 min The CrashLoopBackOff ceiling: Kubernetes applies exponential backoff (10s → 20s → 40s → 80s → 160s → 3...

How to Deploy an AI Chatbot on Azure Using Azure OpenAI and App Service

Step-by-Step Guide Azure OpenAI App Service Production Python How to Deploy an AI Chatbot on Azure Using Azure OpenAI and App Service From zero to a production-grade AI chatbot: provision Azure OpenAI, write a streaming Flask API backend, deploy it on Azure App Service with Managed Identity, wire in conversation history and content safety, and instrument it with Application Insights — all with complete code and Terraform IaC. No API keys in environment variables. No hardcoded secrets. No half-finished PoC patterns. 7 phases This guide covers the full deployment lifecycle: architecture design → resource provisioning → backend code → App Service deployment → streaming → security → monitoring Zero keys The chatbot authenticates to Azure OpenAI using Managed Identity and DefaultAzureCredential — no API keys stored in environment variables, Key Vault, or code SSE Server-Sent Events stream GPT tokens to the browser as they generate — the same token-by-token typing effect users expect from pr...