Skip to content

Private Endpoint DNS automation

Azure Private Endpoints only work if clients can resolve a service’s privatelink.* name to the endpoint’s private IP. DTM can maintain those records for you: it enumerates the Private Endpoints your nodes can see, reads each endpoint’s DNS configuration (the fully qualified name and its private IPs), and keeps matching A records in the corresponding privatelink.* zone on DTM.

The integration is opt-in and read-only. It is disabled by default, and while disabled DTM makes no ARM calls at all. When enabled it only ever reads from Azure; it never creates, modifies, or deletes Azure resources.

Two panels. The control loop: DTM reads each Private Endpoint's DNS configuration over ARM (Reader role, hourly by default), the allowlist gate admits only official Microsoft privatelink zones, and DTM creates or updates an owner-tagged A record in the privatelink.blob.core.windows.net zone: storacct01 maps to 10.20.4.6. A note marks the integration opt-in and read-only toward Azure. The query path: a client asks for storacct01.blob.core.windows.net, public DNS answers a CNAME to the privatelink name (the hop people miss), the privatelink query reaches DTM either because the VNet's DNS points at DTM or through a conditional forwarder from the existing resolver, and DTM answers the private IP, A 10.20.4.6. Two panels. The control loop: DTM reads each Private Endpoint's DNS configuration over ARM (Reader role, hourly by default), the allowlist gate admits only official Microsoft privatelink zones, and DTM creates or updates an owner-tagged A record in the privatelink.blob.core.windows.net zone: storacct01 maps to 10.20.4.6. A note marks the integration opt-in and read-only toward Azure. The query path: a client asks for storacct01.blob.core.windows.net, public DNS answers a CNAME to the privatelink name (the hop people miss), the privatelink query reaches DTM either because the VNet's DNS points at DTM or through a conditional forwarder from the existing resolver, and DTM answers the private IP, A 10.20.4.6.

When enabled, DTM periodically walks the same discovery scopes you configured for Azure region discovery, so there is no separate scope list to maintain. For each Private Endpoint it finds, DTM:

  1. Reads the endpoint’s custom DNS configuration: each fully qualified name and the private IPs behind it.
  2. Matches the name against its allowlist of official Microsoft privatelink.* zones (see below).
  3. Creates the privatelink.* zone on DTM if it does not exist yet (created Active, with a default TTL of 300).
  4. Creates or updates an owner-tagged A record for the name.

Clients then resolve the service’s public name as usual, follow the CNAME to the privatelink.* name, and DTM answers with the private IP. For that to happen, queries for the privatelink.* zones must reach DTM: either point your VNet’s DNS servers at your DTM nodes, or add conditional forwarders for the privatelink.* zones from your existing resolver to DTM (see forwarders and stub zones for the equivalent concepts on the DTM side).

DTM will only manage records inside the closed set of official Microsoft privatelink zones: 47 exact zones, for example privatelink.blob.core.windows.net, plus three region-qualified families such as privatelink.<region>.azmk8s.io. Any discovered name that does not fall under one of these zones is skipped and logged, and is never served.

DTM is deliberately conservative about what it will touch:

  • DTM only manages records it created. Every automated record carries an owner tag. If an operator has created a record at the same name, DTM skips that name entirely and never overwrites it.
  • Stale records are pruned only after a fully complete discovery cycle. If a cycle is partial or truncated (for example an ARM call failed partway through), nothing is pruned, so a transient Azure API problem cannot cause DTM to withdraw records that are still valid. An incomplete cycle also never shrinks a live record: observed addresses are unioned with what is already published, and only a complete cycle removes a decommissioned IP.
  • Found but unpublishable is not deleted. A Private Endpoint whose DNS configuration DTM cannot represent (for example one that yields no usable IPv4 address) still counts as observed: it is reported, and it never authorizes removing a record that is currently being served.

By default, discovered records are served whenever they exist. You can optionally enable health gating, which attaches a coarse TCP port 443 check to discovered names:

  • Health gating only applies to names backed by two or more IPs, where dropping an unhealthy IP still leaves an answer.
  • A name with a single IP is never health-withdrawn; a wrong answer is worse than a slow one, but no answer at all is worst.
  • Each node’s managed identity needs the Reader role over the scopes that contain your Private Endpoints. These are the same discovery scopes used for region discovery.
  • The feature persists its configuration, so the node needs its standard persistent storage (the same disk that holds zones and records).

Private Endpoint automation is configured through the admin API only (all endpoints require the admin role; capture the $DTM_TOKEN bearer token per the API overview). The configuration is persisted, so it survives restarts.

Read the current configuration:

Terminal window
curl -sk https://<dtm>:8443/api/v1/config/private-endpoints \
-H "Authorization: Bearer $DTM_TOKEN"

Enable it:

Terminal window
curl -sk -X PUT https://<dtm>:8443/api/v1/config/private-endpoints \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"interval_seconds": 3600,
"health_gate": false
}'

interval_seconds controls how often a discovery cycle runs and defaults to 3600 when unset or zero. health_gate enables the optional TCP 443 gating described above.

Run a discovery cycle immediately (useful right after enabling, or after creating a new Private Endpoint):

Terminal window
curl -sk -X POST https://<dtm>:8443/api/v1/discovery/private-endpoints/run \
-H "Authorization: Bearer $DTM_TOKEN" \
-H "X-DTM-CSRF: 1"

The response reports created, updated, reaped, and unsupported counts. unsupported is the number of endpoints found but not publishable (unrepresentable DNS configuration), so “50 endpoints found and none publishable” reads differently from “nothing to do”.

After a cycle, query a discovered name against DTM directly:

Terminal window
dig @<dtm> storacct01.privatelink.blob.core.windows.net +short
10.20.4.6

If a name you expected is missing, check the node’s logs for skip messages: the two common causes are a name outside the privatelink allowlist and an operator-created record already present at that name.