Skip to content

Regions, discovery and subnets with Terraform

Region-aware load balancing needs to know which region a client and each backend belong to. These resources provide that data. See regions and subnet mapping for the concepts.

dtm_subnet_mapping (role: editor or admin) ties a CIDR to a region. There is no update path; every attribute forces replacement.

resource "dtm_subnet_mapping" "ne" {
subnet = "10.100.0.0/16"
region_id = "northeurope"
}
resource "dtm_subnet_mapping" "we" {
subnet = "10.20.0.0/16"
region_id = "westeurope"
}
Attribute Required Description
subnet Yes CIDR block, e.g. 10.100.0.0/16.
region_id Yes Region tag, e.g. northeurope.
priority No Higher priority wins when CIDRs overlap. Default 0 (most-specific prefix wins).
source No Must be manual (the default). Discovered mappings get azure-api from the server itself; declaring it here fails at apply with a clear diagnostic, since a mapping that merely claims to be discovered would be pruned by the next discovery cycle.

dtm_discovery_scope (role: admin) tells DTM which Azure subscription (and optionally which resource group) to walk to auto-generate subnet mappings, using its managed identity’s read access.

resource "dtm_discovery_scope" "prod" {
subscription_id = "00000000-0000-0000-0000-000000000000"
resource_group = "rg-network" # optional; omit to scope the whole subscription
display_name = "Production networking"
enabled = true
}
Attribute Required Description
kind No subscription (default) or management-group. Changing it replaces the resource.
subscription_id For subscription scopes Azure subscription ID (UUID form). Must be empty on a management-group scope. Changing it replaces the resource.
resource_group No Narrow a subscription scope to one resource group. Changing it replaces the resource.
management_group_id For management-group scopes The management-group name segment. Changing it replaces the resource.
expanded_subscription_ids For management-group scopes The subscriptions the scope covers. Required: DTM never expands a group on its own.
display_name No Label shown in the UI.
enabled No Defaults to true.

A management-group scope authorises whole subscriptions, listed explicitly:

resource "dtm_discovery_scope" "corp" {
kind = "management-group"
management_group_id = "contoso-root"
expanded_subscription_ids = [
"11111111-1111-1111-1111-111111111111",
"33333333-3333-3333-3333-333333333333",
]
}

expanded_subscription_ids is the authorisation: the reviewed Terraform plan is the confirmation step, and git is the audit trail. Because the list is declared here, DTM reports membership drift on this scope but never applies it, even under region_discovery_auto_apply; otherwise DTM’s apply and your next terraform apply would silently revert each other forever. When the group’s membership changes, GET /api/v1/discovery/status says so; you update the list and apply.

To decide what to authorise, use the dtm_management_group_expansion data source (role: admin):

data "dtm_management_group_expansion" "corp" {
management_group_id = "contoso-root"
verify = true # issue the read discovery actually makes
}
output "cannot_scan" {
value = data.dtm_management_group_expansion.corp.unreadable_subscription_ids
}

verify = true costs one Azure call per subscription and is worth it: without it, “readable” only means the identity holds some role there, and Reader on a single resource group is enough to look readable while the subscription-wide read discovery needs still fails.

Discovered mappings appear with source = "azure-api"; you can add manual mappings alongside them.

dtm_region_discovery_config (role: admin) selects how DTM enumerates your Azure networks: arm-list (the default, walking the scopes directly) or resource-graph (an Azure Resource Graph query, better suited to large estates).

resource "dtm_region_discovery_config" "this" {
mode = "resource-graph"
}
  • The change applies live, with no restart, and the applied value is loaded over the server-config seed at boot, so a switch survives restarts.
  • resource-graph requires the nodes’ managed identity to be able to read Azure Resource Graph. Switching to a backend the identity cannot use fails closed: the discovery cycle logs the error and prunes nothing, and you recover by switching back, with no redeploy.
  • Singleton: import with ID region-discovery; removing the resource resets the backend to arm-list.

The dtm_regions data source returns the deduplicated set of region IDs in use:

data "dtm_regions" "all" {}
output "regions" {
value = data.dtm_regions.all.ids
}