Homeβ€Ί Blogβ€Ί Azure Architecture Series #88 β€” Azure DNS Public Zones…
Azure Architecture Azure Architecture Series

Azure Architecture Series #88 β€” Azure DNS Public Zones

Verified against current vendor documentation on 9 November 2026. Pricing, limits and API behaviour were checked against the official docs on that date. Cloud services change fast — if you are reading this much later, treat the specifics as a starting point and re-check the linked sources.

Business Challenge

#87 finished the perimeter: four posts on firewalls, WAF and volumetric protection, all of which assume traffic has already arrived at an address. DNS is the step before that, and it is the one layer where a mistake redirects users rather than exposing them.

Azure DNS is also narrower than its name suggests, and the scoping sentence is worth having first:

Authoritative only — and not a registrar

“Azure DNS provides an authoritative DNS service. It doesn't provide a public recursive DNS service.”

And: “the zone must be created in Azure and delegated to Azure's authoritative DNS servers with a domain registrar. Azure DNS isn't the domain registrar.” It also “currently doesn't support purchasing of domain names.”

So hosting a domain here is a three-party arrangement: you own the name at a registrar, Azure answers queries for it, and a recursive resolver somewhere else does the asking. Azure owns exactly one of those three roles, and the consequences of that division run through everything below.

The sharpest consequence is stated as a note rather than a warning:

Ownership is not checked

“You do not have to own a domain name to create a DNS zone with that domain name in Azure DNS. However, you do need to own the domain to configure the Azure DNS name servers as the correct name servers for the domain name with the domain name registrar.”

Creating a zone is a resource-creation operation in your subscription. It validates nothing about the outside world. A zone named after a domain you do not control is a perfectly healthy Azure resource that answers no real queries, and nothing in the portal will tell you which kind you have.

Architecture

Diagram: Azure DNS public zones across five bands. The first band establishes the scope. Azure DNS is an authoritative service only and does not provide a public recursive DNS service; it is not a domain registrar and cannot purchase domain names. Hosting a domain is therefore a three-party arrangement in which you own the name at a registrar, Azure answers queries for it, and some other recursive resolver does the asking. Critically, you do not have to own a domain name to create a zone with that name in Azure DNS; ownership only matters when configuring Azure's name servers at the registrar. A zone for a domain you do not control is a healthy Azure resource that answers no real queries. The second band covers duplicate zones and delegation. The same zone name can be reused in a different resource group or subscription, and where multiple zones share a name each instance is assigned different name server addresses, but only one set of addresses can be configured with the registrar. So two teams can each hold a valid-looking zone for the same domain while only one is live. Delegation works by NS records: a parent zone points to a child zone's name servers, and each delegation actually has two copies of the NS records, one in the parent pointing to the child and one at the apex of the child zone itself. The third band covers what occupies the zone apex and why it constrains design. Both the NS and SOA record sets are created automatically at the apex when a zone is created and deleted automatically with the zone; neither can be deleted separately. The apex NS set is partly yours: you may add further name servers to cohost with another DNS provider and may change the TTL and metadata, but removing or modifying the prepopulated Azure name servers is not allowed. That restriction applies only at the apex; NS record sets used to delegate child zones can be created, modified and deleted freely. For SOA you may modify every property except host, which is preconfigured to Azure's primary name server, and the zone serial number is not updated automatically when records change, so it must be edited by hand if it matters. Because NS and SOA already occupy the apex, a CNAME cannot be created there, and more generally a CNAME record set cannot coexist with any other record set of the same name. These are DNS standards rather than Azure limitations. The fourth band covers alias records, which exist to answer the apex problem and a lifecycle problem. Alias is a qualification on an A, AAAA or CNAME record set that can target a Standard SKU public IP, a Traffic Manager profile, an Azure CDN endpoint, an Azure Front Door endpoint, or another record set of the same type in the same zone, with a limit of 50 alias record sets per resource. Unlike CNAME, alias records can be created at the zone apex. They also couple the record's lifecycle to the Azure resource: delete the target and the alias becomes an empty record set rather than a dangling record, which avoids directing users to whoever is assigned the old public IP address next. Creating one requires the Microsoft.Network resource provider registered in both subscriptions when zone and target differ. For new Traffic Manager configurations Microsoft now recommends Traffic Manager Linked Records instead, as they return endpoint addresses without an intermediate CNAME hop, and pointing a zone apex at Azure CDN from Akamai is unsupported. The fifth band covers limits and concurrency. Default limits are 250 public zones per subscription, 10,000 record sets per zone and 20 records per record set, which multiply out to 200,000 records in one zone and 2,500,000 record sets in one subscription. TXT is the exception at 400 records per record set, twenty times the general limit, and it is the one figure in the table carrying no footnote offering an increase through support. A TXT record set is also capped at 4,096 total characters across all records combined, which at the 255-character maximum string length is just over sixteen full-length strings. TTL is set on the record set rather than per record and may be any value from 1 to 2,147,483,647 seconds. Concurrency is handled by etags with four REST behaviours, and Azure DNS PowerShell uses them by default unless suppressed with the Overwrite switch. Finally, Resource Manager tags work on zones but not on record sets, where metadata is the alternative but cannot drive billing views or Resource Manager policy.
Three parties, an occupied apex, and a limits table with one row shaped unlike the others.

What the zone apex already contains, and what that forbids

At the apex (@)NS record setSOA record set
Created Automatically with the zone Automatically with the zone
Deleted Automatically with the zone — cannot be deleted separately Automatically with the zone — cannot be created or deleted separately
What you may change Add further name servers; change TTL and metadata Every property except host
What you may not Remove or modify the prepopulated Azure name servers host — preconfigured to Azure's primary name server
Consequence The apex is occupied, so no CNAME can be created there. “These constraints arise from the DNS standards and aren't limitations of Azure DNS.”

Default limits for public zones

ResourceLimitRaisable via support?
Public DNS zones per subscription250Yes
Record sets per public DNS zone10,000Yes
Records per record set20Yes
TXT records per record set400No footnote — the only row without one
Alias records for a single Azure resource50Yes

Those multiply out usefully: 200,000 records in a single zone, and 2,500,000 record sets across a subscription, before anyone has to ask Azure Support for anything.

Why This Architecture Holds Up

Because two teams can hold the same zone and only one of them is real

Zone names are unique only within a resource group: “The name of the zone must be unique within the resource group… The same zone name can be reused in a different resource group or a different Azure subscription.” Which is reasonable — and then:

Each duplicate gets its own name servers, and only one set can be delegated

“Where multiple zones share the same name, each instance is assigned different name server addresses. Only one set of addresses can be configured with the domain name registrar.”

So the failure looks like this: two teams each create a contoso.com zone in their own resource group. Both are valid resources. Both accept records. Both show green. One is delegated and answers the internet; the other is an elaborate notepad. Azure has no way to tell you which, because the thing that decides it is a setting at a registrar Azure does not talk to.

The practical defence is not technical. It is that the registrar's name server list is the authoritative record of which zone is live, and it belongs in the same document as the zone's resource ID. A zone whose name servers are not in that list should be treated as a draft, whatever its contents.

Because the apex is already occupied, and that is why alias records exist

Two record sets appear at the apex the moment a zone is created, and both are partly outside your control. The consequence is the constraint everyone meets eventually: “Since the zone apex (name = '@') contains the NS and SOA record sets… you can't create a CNAME record set at the zone apex.”

That matters because the things you most want at the apex are CNAME-shaped. “Since using a Traffic Manager profile requires creation of a CNAME record, it's not possible to point to Traffic Manager profile from the zone apex” — and the same applies to a CDN endpoint or a Front Door endpoint. A naked domain cannot be a CNAME, so contoso.com cannot point at a load-balanced front end the ordinary way.

Alias records are the answer, and they are “qualifications on a DNS record set” rather than a record type of their own. They apply to A, AAAA and CNAME sets, and “unlike CNAME records, alias records are created at the zone apex”. Targets are specific Azure things: a Standard SKU public IP, a Traffic Manager profile, an Azure CDN endpoint, an Azure Front Door endpoint, or another record set of the same type in the same zone.

Note the SKU qualifier on the first of those — “a Standard SKU public IP resource”. #87 found that DDoS IP Protection also cannot protect a Basic-tier public IP. Basic public IPs are now excluded from both, which makes the SKU of an address a decision with consequences two layers away from where it is made.

Because an alias record is a lifecycle coupling, not a DNS feature

The apex problem is the headline, but the more interesting property is what alias records do when things are deleted:

Delete the target and the record empties rather than dangles

“Alias records prevent dangling references by tightly coupling the life cycle of a DNS record with an Azure resource… If you delete those underlying resources, the DNS alias record becomes an empty record set. It no longer references the deleted resource.”

And the reason that matters is stated plainly, which is unusual: an alias updating itself “can potentially avoid the security risks of directing the users to another application that has been assigned the old public IP address.”

That is the whole subdomain-takeover problem described from the defender's side. A plain A record pointing at a released public IP keeps pointing there, and Azure will eventually hand that address to someone else. The documentation is also candid about why this happens organisationally rather than technically: “a role might have the authority to delete a CNAME or IP address that belongs to an application. But they don't have sufficient authority to update the DNS record that points to those targets.” Alias records do not fix the permissions split; they make it harmless.

Two operational details attach. The limit is “50 alias record sets per resource”, which binds in exactly the fan-out case where one Front Door endpoint fronts many customer domains. And creation requires “the Microsoft.Network resource provider” registered — “if the DNS zone and the alias target resource are in different subscriptions, both subscriptions must be registered”, which is the sort of prerequisite that surfaces as an opaque failure in a pipeline rather than a clear message.

One recommendation has moved, and it was news a few days ago: “For new Traffic Manager-backed DNS configurations, consider using Traffic Manager Linked Records instead of alias records… without an intermediate CNAME hop”. Alias-to-Traffic-Manager “remain supported for backward compatibility” — so this is a new-build default change, not a migration.

Because the SOA serial number does not move on its own

This is the detail most likely to break something downstream, and it is one sentence:

The zone serial is static unless you edit it

“The zone serial number in the SOA record isn't updated automatically when changes are made to the records in the zone. It can be updated manually by editing the SOA record, if necessary.”

In conventional DNS the serial is how the outside world detects that a zone changed — secondaries compare it to decide whether to transfer, and monitoring systems watch it as a change signal. In Azure DNS it is an editable field that nothing increments. Any tooling that treats a static serial as “nothing has changed” will be wrong about an Azure-hosted zone, permanently and silently.

This is a reasonable design for a service where there is no zone transfer to coordinate — the records are the API, and the API is always current. It is only a problem if something upstream assumed otherwise, which is why it is worth knowing before a monitoring integration is built rather than after it reports nothing for a month.

Because the apex NS set is half yours, and that is deliberate

The apex NS record set is the one place where Azure's control and yours overlap in the same object. You may “add more name servers to this NS record set, to support cohosting domains with more than one DNS provider”, and change its TTL and metadata. You may not remove or modify what Azure put there: “removing or modifying the prepopulated Azure DNS name servers isn't allowed.”

So multi-provider DNS is supported by addition only. You can run Azure DNS alongside another provider for the same domain; you cannot use Azure DNS to express a migration away from Azure by removing its own name servers from the apex. That has to happen at the registrar, which is consistent with everything else here — the registrar is where authority lives.

The restriction is also precisely scoped, and the scoping is the useful part: “This restriction only applies to the NS record set at the zone apex. Other NS record sets in your zone (as used to delegate child zones) can be created, modified, and deleted without constraint.” Child delegation is entirely yours. Which is how the two-copy structure works: “Each delegation actually has two copies of the NS records; one in the parent zone pointing to the child, and another in the child zone itself.” You write the parent copy; Azure writes the child's apex copy.

Because TXT limits are a different shape from every other type

The limits table has one row that does not match its neighbours in either value or footnote. Records per record set is 20. TXT records per record set is 400 — twenty times as many. And where 250, 10,000, 20 and 50 all carry the footnote “If you need to increase these limits, contact Azure Support”, the 400 does not.

So TXT gets far more headroom and, uniquely, no documented path to more. That is a sensible shape once you remember what TXT record sets hold: SPF, DKIM selectors, domain-verification tokens from every SaaS product the organisation has ever trialled. The apex TXT set is where unrelated systems accumulate, and 400 is generous precisely because nobody curates it.

There is a second TXT ceiling that bites sooner and is easier to miss. A single string may be “up to 255 characters in length”, and “Azure DNS supports a total string length of up to 4,096 characters in each TXT record set (across all records combined)”. That budget is just over sixteen maximum-length strings for the whole record set — not per record. A long DKIM key is a substantial fraction of it.

Two related traps in the same area. SPF must be a TXT record: “The obsolete SPF record type isn't supported”, and importing a zone file silently converts any SPF-typed records to TXT. And the API and the portal disagree about strings: “When calling the Azure DNS REST API, you need to specify each TXT string separately. When you use the Azure portal, PowerShell, or CLI interfaces, you should specify a single string per record”, which is then auto-split. So the same TXT value expressed through two interfaces is two different payloads, and a tool that round-trips between them can reshape a record without changing its meaning — or change its meaning if the splitting is wrong.

Because etags are the only thing standing between two pipelines

Azure DNS has optimistic concurrency, and it is on by default in exactly one place. “By default, Azure DNS PowerShell uses Etags to block concurrent changes to zones and record sets. The optional -Overwrite switch can be used to suppress Etag checks, in which case any concurrent changes that occurred are overwritten.”

At the REST layer it is opt-in, and the default is the unsafe one:

HeaderBehaviour
NonePUT always succeeds (no Etag checks)
If-match <etag>PUT only succeeds if resource exists and Etag matches
If-match *PUT only succeeds if resource exists
If-none-match *PUT only succeeds if resource doesn't exist

A REST call or ARM template that sends no etag wins unconditionally, including over a change made two seconds earlier by someone else. With DNS that is not an abstract concern: the losing change is often the one that was correct, and the symptom is a record that reverts for no visible reason. If two pipelines can write the same zone, the protection has to be asked for — If-match on updates, If-none-match * on creates — and the reason to ask is that the consequence of not asking is invisible until someone notices the record is wrong.

Because the things you tag are not the things you bill on

A small governance asymmetry with a real effect: “Azure DNS supports using Azure Resource Manager tags on DNS zone resources. It doesn't support tags on DNS record sets”, where metadata is the alternative — but “unlike tags, metadata can't be used to provide a filtered view of your Azure bill and can't be specified in an Azure Resource Manager policy.”

So cost attribution and policy enforcement stop at the zone boundary. If one zone serves several teams or applications — which is the normal case, since a zone is a domain and a domain usually spans an organisation — there is no supported way to attribute its cost or govern its contents per application. The alternative is more zones, and the limit on those is 250 per subscription. That is the governance trade to make deliberately: one zone is simpler to delegate and impossible to attribute.

Key Architecture Decisions

DecisionChooseBecause
Confirming a zone is actually live Check the registrar's name server list, not the portal Ownership is never validated at zone creation, duplicates are allowed across resource groups, each gets different name servers, and only one set can be delegated. Azure cannot tell you which zone is real.
Pointing a naked domain at Traffic Manager, CDN or Front Door An alias record set NS and SOA occupy the apex so no CNAME can exist there — a DNS standard, not an Azure limit. Alias records can be created at the apex; CNAMEs cannot.
Any A/AAAA record pointing at an Azure public IP Make it an alias record It empties rather than dangles when the target is deleted, which is the documented defence against users being sent to whoever is assigned that address next.
Public IP SKU for anything DNS points at Standard Alias targets must be Standard SKU, and per #87 DDoS IP Protection also excludes Basic-tier public IPs. Basic is now excluded from both.
New Traffic Manager-backed DNS Traffic Manager Linked Records, not alias Microsoft's current recommendation — endpoint IPs returned directly with no intermediate CNAME hop. Alias remains supported for existing configurations.
Monitoring an Azure-hosted zone for change Do not watch the SOA serial It is not updated automatically when records change. Tooling that reads a static serial as “unchanged” will be silently wrong forever.
Running Azure DNS alongside another provider Add name servers to the apex NS set Supported by addition only — the prepopulated Azure name servers cannot be removed or modified. Leaving Azure is a registrar action, not a zone edit.
Delegating child zones Freely — the apex restriction does not apply Non-apex NS record sets can be created, modified and deleted without constraint. Remember both copies exist: parent and child apex.
Planning the apex TXT record set Budget against 4,096 characters, not 400 records The character ceiling is across all records combined — about sixteen maximum-length strings for the whole set. A long DKIM key consumes a real share of it.
Expecting the TXT limit to be raised Do not count on it 400 TXT records per record set is the only row in the limits table without the “contact Azure Support” footnote.
Writing TXT records from automation Pick one interface and stay on it REST wants each string separately; portal, PowerShell and CLI want one string per record and split it automatically. Round-tripping between them reshapes the payload.
Two pipelines that can write the same zone Send etags explicitly A REST PUT with no etag header always succeeds and overwrites concurrent changes. PowerShell checks by default; everything else does not.
Per-application cost attribution inside a zone Not available — decide whether to split zones Tags work on zones, not record sets; record set metadata cannot drive billing views or ARM policy. More zones means attribution, against a 250-per-subscription limit.
SPF configuration TXT records only The SPF record type is deprecated and unsupported, and importing a zone file converts SPF-typed records to TXT.

Closing Thought

Almost everything surprising about Azure DNS public zones follows from one division of responsibility: Azure is authoritative for a zone, and a registrar decides whether anyone asks Azure. That is why ownership is never validated, why duplicate zones are allowed and only one can be live, why you can add name servers to the apex but not remove Azure's, and why leaving Azure DNS is not an operation Azure DNS offers. The service is deliberately one third of the arrangement, and it behaves consistently with that everywhere.

The thing to change today, if it is not already true, is that every A or AAAA record pointing at an Azure public IP should be an alias record. Not for the apex — for the deletion behaviour. A plain record keeps pointing at a released address, Azure reassigns that address, and the documentation says what happens next in unusually direct language: users get “directed… to another application that has been assigned the old public IP address”. The permissions split that causes it — whoever can delete the IP often cannot fix the record — is organisational and will not be solved. Alias records make it not matter, and they cost nothing.

The quieter one to write down somewhere is the SOA serial. It does not increment. Nothing in Azure is wrong because of that, and any monitoring built on the assumption that it does will report a calm, unchanging zone no matter what happens inside it. That is the kind of error that holds for a year and then matters once.

Next in this series

#89 takes the same service inward: private DNS zones and virtual network links — how a zone that resolves only inside Azure is attached to networks, and what auto-registration does and does not cover.

Official Azure Reference

Comments

How was your experience?
Your feedback helps improve this site.
PoorExcellent