Tag-based VM registration
Tag an Azure VM with a name, and DTM keeps that name’s addresses in step with your fleet. Tag-based VM registration discovers virtual machines and VM Scale Set instances carrying a registration tag and maintains the A (IPv4) and AAAA (IPv6) values of a record you created, adding addresses when VMs appear, updating them when IPs change, and removing them when VMs go away.
The division of ownership is strict, and it is the heart of the feature:
- You own the record. You pre-create it with
auto_populate: true, and everything you set on it stays yours: TTL,lb_policy,health_check_template,enabled,protected. Registration never touches them. - DTM owns the value list. On an
auto_populaterecord, the reconciler adds and removes addresses as the fleet changes. Do not edit the values yourself; the next cycle would put them back the way Azure says they should be.
The integration is opt-in and read-only toward Azure: it is disabled by default, and when enabled it discovers everything through Azure Resource Graph queries. DTM never modifies your Azure resources.
Step 1: pre-create the record
Section titled “Step 1: pre-create the record”Create the record for the service name with auto_populate: true and no
values (requires a bearer token; see the
API overview):
curl -sk -X POST https://<dtm>:8443/api/v1/zones/<zone-id>/records \ -H "Authorization: Bearer $DTM_TOKEN" \ -H "X-DTM-CSRF: 1" \ -H "Content-Type: application/json" \ -d '{ "name": "api", "type": "A", "ttl": 30, "auto_populate": true, "lb_policy": {"method": "round-robin"}, "health_check_template": {"protocol": "https", "port": 443, "path": "/healthz"} }'This is the only record shape that may be created with an empty value list: an auto-populated record with no values is a service that currently has no instances, and it answers NODATA rather than NXDOMAIN, so resolvers do not cache a negative for a name that is about to come back.
Constraints on auto_populate records (all rejected with 400):
valuesmust be omitted on create, andPUTmay not carryvalueseither. To take the addresses back into your own hands, send{"auto_populate": false, "values": [...]}in one request.- Only
AandAAAAtypes. lb_policy.value_weightsis rejected: weights key on the address itself, and DTM changes those addresses as the fleet does. Every other method (round-robin,region,geo-failover,failover,latency, client affinity) copes with a changing value set.
In Terraform, use the dedicated
dtm_auto_record resource, which
has no values attribute at all, so a plan can never diff on a list DTM
owns.
Step 2: tag the VM
Section titled “Step 2: tag the VM”Add the registration tag to a VM or a VM Scale Set:
az vm update -g rg-app-prod -n vm-api-01 \ --set "tags.dtm-register=api.example.internal"On the next cycle, DTM adds the VM’s primary NIC private IPs to your record’s values:
dig @<dtm> api.example.internal +short10.30.1.12Multiple VMs, one name. If several VMs, or the instances of a VMSS, carry the same FQDN in their tag, their addresses collapse into that one record, which DTM then load balances with the policy you configured:
dig @<dtm> api.example.internal +short10.30.1.1210.30.1.1310.30.1.14The tag key defaults to dtm-register and is configurable (see below). Tag
names are matched the way Azure treats them, case-insensitively, so a tag
typed as DTM-Register still registers.
Both VM Scale Set orchestration modes are supported: Uniform, and Flexible (the Azure default for new scale sets), whose instances are standalone VM resources that reference the scale set.
When a service goes away
Section titled “When a service goes away”A departed service, whether scaled to zero, untagged, or deleted, empties its record rather than deleting it. The record survives with all of its configuration (TTL, LB policy, health template) and answers NODATA until the service returns. Registration never deletes a record.
Removal of individual addresses is still cycle-gated: values are only removed after a complete discovery cycle. A partial cycle (a failed Resource Graph page, an unreadable subscription) can add addresses but never removes them, so a transient Azure error cannot take live backends out of DNS.
Health checks
Section titled “Health checks”Set the health configuration on the record itself via
health_check_template, as in step 1. Per-address checks are instantiated
automatically for each value and follow their address: adding or removing one
VM leaves every other backend’s accumulated health state untouched.
The legacy dtm-healthcheck VM tag no longer configures anything. Health
configuration belongs to the record; if a VM carries a dtm-healthcheck tag
that disagrees with the record’s template, the tag is reported in the server
log and otherwise ignored.
The zone allowlist
Section titled “The zone allowlist”Registration remains gated by a mandatory zone allowlist. A tagged FQDN only registers if it is covered by an allowlisted DTM zone that is Active, using the most specific match when zones nest.
Prerequisites
Section titled “Prerequisites”The node’s managed identity needs the Reader role over the compute and network resources in scope, so the Resource Graph queries can see the VMs, VMSS instances, and their NICs.
Configuration
Section titled “Configuration”Unlike Private Endpoint automation, tag-based registration is server boot configuration (YAML or environment variables), not a runtime API:
azure: tag_registration_enabled: true tag_registration_interval_seconds: 300 # default 300 tag_registration_tag_key: dtm-register # default tag_registration_zone_allowlist: - example.internal - db.example.internal tag_registration_client_id: '' # optional user-assigned MIEach setting has an environment equivalent under the
DTM_AZURE_TAG_REGISTRATION_* prefix, for example
DTM_AZURE_TAG_REGISTRATION_ENABLED=true.
Set tag_registration_client_id only if the node should authenticate with a
specific user-assigned managed identity instead of the default.
One admin API endpoint exists, to run a discovery cycle immediately instead of waiting for the interval (requires the admin role):
curl -sk -X POST https://<dtm>:8443/api/v1/tag-registration/run \ -H "Authorization: Bearer $DTM_TOKEN" \ -H "X-DTM-CSRF: 1"The response reports what the cycle actually did:
{ "updated": 2, "drained": 0, "skipped": 0, "unclaimed": 1 }updated: records whose value list changed.drained: records emptied because their service departed.skipped: tagged resources refused by the zone allowlist or with invalid tag values.unclaimed: tags naming a record nobody has pre-created.
Troubleshooting
Section titled “Troubleshooting”If a tagged VM does not publish, check in this order:
- Pre-created record: does a record with
auto_populate: trueexist at the tagged name? If not, the tag counts asunclaimedand nothing is published. - Allowlist: is the FQDN covered by an allowlisted zone, and is that zone Active? An empty allowlist registers nothing.
- Permissions: does the managed identity have Reader over the VM and its NIC? A subscription DTM cannot read degrades the cycle to incomplete, which pauses value removal until access is restored.
- Logs and counters:
skippedandunclaimedcounts in the run response, plus ignoreddtm-healthchecktags and unresolvable NICs, are logged on each cycle.