A standalone module that provisions a hardened Azure Traffic Manager profile β a global, DNS-based traffic load balancer with encrypted endpoint health monitoring β targeting
hashicorp/azurerm ~> 4.0.
- π Provisions one
azurerm_traffic_manager_profileβ a global DNS traffic director that answers queries at<relative_name>.trafficmanager.net. - π§ Supports every routing method the provider exposes: Priority (failover), Weighted, Performance, Geographic, MultiValue, and Subnet.
- π©Ί Configures endpoint health monitoring (
monitor_config) that decides which endpoints receive traffic β the profile's core resilience and failover control. - π Defaults health checks to HTTPS on port 443 so probes are encrypted out of the box.
- π§± Leaves endpoints to their own catalog modules; this profile is attached to Azure / external / nested
endpoints by exporting its
idandfqdn.
π‘ Why it matters: Traffic Manager is DNS-level global load balancing. It never proxies your traffic β it hands clients the DNS answer for a healthy endpoint. The profile's health monitor is therefore the whole ballgame for failover: if the monitor is weak or unencrypted, so is your resilience story. This module makes the encrypted, sensible-default monitor the path of least resistance.
If this module saves you time, here are three no-cost ways to help it reach other engineers:
- β Star the repository β it is the signal that tells other engineers the work is worth their time.
- π€ Connect on LinkedIn β linkedin.com/in/microsoftexpert.
- β Buy me a coffee β buymeacoffee.com/microsoftexpert.
flowchart LR
rg["terraform-azurerm-resource-group"]
tmp["terraform-azurerm-traffic-manager-profile"]
azep["terraform-azurerm-traffic-manager-azure-endpoint"]
exep["terraform-azurerm-traffic-manager-external-endpoint"]
nsep["terraform-azurerm-traffic-manager-nested-endpoint"]
pip["terraform-azurerm-public-ip"]
web["terraform-azurerm-linux-web-app"]
rg -->|"resource_group_name"| tmp
tmp -->|"profile id + fqdn"| azep
tmp -->|"profile id + fqdn"| exep
tmp -->|"profile id + fqdn"| nsep
pip -->|"target public IP"| azep
web -->|"target resource id"| azep
classDef self fill:#0078D4,stroke:#004578,color:#ffffff;
classDef keystone fill:#004578,stroke:#001d33,color:#ffffff;
classDef sibling fill:#eef3f8,stroke:#b7c7d8,color:#1b2733;
class tmp self;
class azep,exep,nsep keystone;
class rg,pip,web sibling;
The profile is the anchor: it consumes a resource group by name and emits an id + fqdn that the endpoint
modules attach to. The endpoints, in turn, point at concrete backends (public IPs, web apps, external FQDNs).
flowchart TD
client["DNS client query"]
subgraph module["module: azurerm_traffic_manager_profile.this"]
profile["azurerm_traffic_manager_profile (this)"]
routing["traffic_routing_method: Priority / Weighted / Performance / Geographic / MultiValue / Subnet"]
monitor["monitor_config: HTTPS probe on 443"]
end
ep1["endpoint A (sibling module)"]
ep2["endpoint B (sibling module)"]
b1["backend: public IP / web app"]
b2["backend: external FQDN"]
client -->|"resolves the trafficmanager.net FQDN"| profile
profile -->|"applies routing method"| routing
monitor -->|"health probe result"| profile
routing -->|"returns healthy endpoint"| ep1
routing -->|"failover / distribution"| ep2
ep1 -->|"points at"| b1
ep2 -->|"points at"| b2
monitor -.->|"probes"| ep1
monitor -.->|"probes"| ep2
classDef self fill:#0078D4,stroke:#004578,color:#ffffff;
classDef keystone fill:#004578,stroke:#001d33,color:#ffffff;
classDef sibling fill:#eef3f8,stroke:#b7c7d8,color:#1b2733;
class profile,routing,monitor self;
class ep1,ep2 keystone;
class client,b1,b2 sibling;
Resource inventory
| Resource | Count | Role |
|---|---|---|
azurerm_traffic_manager_profile.this |
1 | The keystone profile: DNS config, routing method, and health monitor. |
dns_config block |
1 | Publishes the *.trafficmanager.net name and its TTL. |
monitor_config block |
1 | The health probe applied to every endpoint. |
custom_header block(s) |
0..N | Optional probe request headers, rendered from a keyed map. |
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
| azurerm provider | ~> 4.0 |
| Provider block | None in this module β the caller configures provider "azurerm" { features {} }, auth, and subscription. |
Schema notes that bite (verified against the live provider schema):
- π
nameandresource_group_nameare immutable β changing either forces a new profile. - π
dns_config.relative_nameis immutable β changing it forces replacement, because the published*.trafficmanager.netname changes. β οΈ max_returnis only valid whentraffic_routing_method = "MultiValue", where it is required (1β8). Setting it under any other method is rejected.β οΈ Amonitor_config.pathis only valid for HTTP/HTTPS probes. This module nulls it automatically whenprotocol = "TCP".β οΈ monitor_config.interval_in_secondsaccepts only10or30; a10-second (fast) probe interval restricts the legaltimeout_in_seconds/tolerated_number_of_failurescombinations.- βΉοΈ
fqdnis computed and only known after apply.
Network Contributoron the target resource group, or a custom role grantingMicrosoft.Network/trafficManagerProfiles/*at the smallest scope that works (the resource group).- No data-plane permissions are needed β Traffic Manager is a control-plane, DNS-only service.
- An existing resource group (Traffic Manager is global, but the profile is still managed inside a resource group).
- The
Microsoft.Networkresource provider registered on the target subscription. - A
dns_config.relative_namethat is globally unique across*.trafficmanager.net. - The caller configures the
provider "azurerm" { features {} }block, authentication, and subscription.
terraform-azurerm-traffic-manager-profile/
βββ providers.tf # required_version >= 1.12.0; azurerm ~> 4.0; no provider block
βββ variables.tf # deeply-typed object() schemas + tags/timeouts tail
βββ main.tf # the single keystone azurerm_traffic_manager_profile.this
βββ outputs.tf # id first, then name, then fqdn and other computed attributes
βββ README.md # this document
βββ SCOPE.md # the cross-module contract
βββ LICENSE # MIT, Copyright (c) 2026 Casey Wood
βββ .gitignore # canonical library ignore set
The smallest real call. Health monitoring defaults to encrypted HTTPS on port 443; you only supply identity, routing method, and the DNS label.
module "traffic_manager" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-app-prod"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
dns_config = {
relative_name = "contoso-app-prod" # -> contoso-app-prod.trafficmanager.net
}
tags = {
environment = "prod"
workload = "web"
}
}βΉοΈ The caller configures the provider, authentication, subscription, and the mandatory
provider "azurerm" { features {} }block. This module intentionally declares none of them.
Consumes
| Input | Type | Source module |
|---|---|---|
resource_group_name |
string |
terraform-azurerm-resource-group (name) |
Emits
| Output | Description | Consumed by |
|---|---|---|
id |
Traffic Manager profile Resource ID (first) | terraform-azurerm-traffic-manager-azure-endpoint, -external-endpoint, -nested-endpoint (as parent or child), diagnostics, RBAC |
name |
Profile name | diagnostics / tagging |
fqdn |
Public DNS name (<relative_name>.trafficmanager.net) |
CNAME records, endpoint modules |
resource_group_name |
The resource group holding the profile | downstream compositions |
traffic_routing_method |
The active routing method | documentation / downstream logic |
Values these examples reference but do not create are declared inputs:
variable "service_plan_id" {
description = "service plan id of an existing resource these examples reference."
type = string
}1 Β· Minimal priority (failover) profile
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-failover"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
dns_config = {
relative_name = "contoso-failover"
}
}π‘ Priority routing sends all traffic to the highest-priority healthy endpoint and fails over only when it goes unhealthy. The HTTPS-on-443 default monitor decides "healthy."
2 Β· Weighted routing
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-weighted"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Weighted"
dns_config = {
relative_name = "contoso-weighted"
ttl = 30
}
}π‘ Weight is set per endpoint (in the endpoint modules), not on the profile. A lower
ttllets clients pick up weight changes sooner.
3 Β· Performance routing
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-performance"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Performance"
dns_config = {
relative_name = "contoso-perf"
}
}π‘ Performance routing returns the endpoint with the lowest network latency for the querying resolver's region β ideal for multi-region active/active apps.
4 Β· Geographic routing
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-geo"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Geographic"
dns_config = {
relative_name = "contoso-geo"
}
}βΉοΈ Geographic routing maps the query's origin region to an endpoint. Assign the geographic regions on the endpoints themselves (in the endpoint modules); each region maps to exactly one endpoint.
5 Β· Subnet routing
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-subnet"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Subnet"
dns_config = {
relative_name = "contoso-subnet"
}
}βΉοΈ Subnet routing maps client source-IP ranges to specific endpoints (for example, sending corporate egress ranges to an internal endpoint). The IP-range-to-endpoint mapping is set on the endpoints.
6 Β· MultiValue routing with max_return
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-multivalue"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "MultiValue"
max_return = 4
dns_config = {
relative_name = "contoso-mv"
}
}
β οΈ max_return(1β8) is required for MultiValue and rejected for every other method. MultiValue returns several healthy endpoints in one DNS answer so the client can retry across them.
7 Β· HTTPS monitor with expected status ranges
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-health"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
dns_config = {
relative_name = "contoso-health"
}
monitor_config = {
protocol = "HTTPS"
port = 443
path = "/healthz"
expected_status_code_ranges = ["200-202", "301-301"]
}
}π Encrypted probe on a dedicated health path, treating
200-202and a301redirect as healthy. Endpoints failing the range are pulled from DNS rotation.
8 Β· HTTPS monitor with custom headers (keyed map)
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-headers"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Performance"
dns_config = {
relative_name = "contoso-headers"
}
monitor_config = {
protocol = "HTTPS"
port = 443
path = "/healthz"
custom_header = {
host = { name = "Host", value = "app.contoso.com" }
probe = { name = "X-Health-Probe", value = "traffic-manager" }
}
}
}π‘
custom_headeris a keyed map so each header is addressable and stable across plans. TheHostheader is the common case for probing multi-tenant front ends.
9 Β· Fast-failover monitor (10-second interval)
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-fast"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
dns_config = {
relative_name = "contoso-fast"
ttl = 10
}
monitor_config = {
protocol = "HTTPS"
port = 443
path = "/healthz"
interval_in_seconds = 10
timeout_in_seconds = 9
tolerated_number_of_failures = 3
}
}
β οΈ Fast probing (interval_in_seconds = 10) shortens failover time but constrains the legaltimeout_in_secondsandtolerated_number_of_failurescombinations. Pair it with a low DNSttl.
10 Β· TCP monitor (path is nulled automatically)
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-tcp"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
dns_config = {
relative_name = "contoso-tcp"
}
monitor_config = {
protocol = "TCP"
port = 443
}
}βΉοΈ For a raw TCP handshake probe, leave
pathunset β the module nulls it automatically whenprotocol = "TCP", so no invalid TCP path is ever sent. Prefer HTTPS where the endpoint speaks HTTP.
11 Β· Disabled profile (staged, not yet live)
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-staged"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
profile_status = "Disabled"
dns_config = {
relative_name = "contoso-staged"
}
}
β οΈ ADisabledprofile answers no DNS queries β every endpoint is out of rotation. Use it to stage a profile before cut-over, then flip toEnabled.
12 Β· Traffic View enabled (latency telemetry)
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-insights"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Performance"
traffic_view_enabled = true
dns_config = {
relative_name = "contoso-insights"
}
}βΉοΈ Traffic View aggregates client-network telemetry into latency insights and incurs additional cost. It is off by default; enable it only where you will use the data.
13 Β· Fully-specified, hardened profile with tags and timeouts
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-web-prod"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"
profile_status = "Enabled"
dns_config = {
relative_name = "contoso-web-prod"
ttl = 30
}
monitor_config = {
protocol = "HTTPS"
port = 443
path = "/healthz"
interval_in_seconds = 30
timeout_in_seconds = 10
tolerated_number_of_failures = 3
expected_status_code_ranges = ["200-299"]
custom_header = {
host = { name = "Host", value = "app.contoso.com" }
}
}
tags = {
environment = "prod"
workload = "web"
owner = "platform-team"
}
timeouts = {
create = "30m"
delete = "30m"
}
}π Everything explicit: encrypted probe, dedicated health path, status-range gating, and a
Hostheader β a production-grade baseline.
14 Β· for_each at scale β one profile per workload
locals {
profiles = {
web = { relative_name = "contoso-web", routing = "Performance" }
api = { relative_name = "contoso-api", routing = "Priority" }
edge = { relative_name = "contoso-edge", routing = "Weighted" }
}
}
module "tmp" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
for_each = local.profiles
name = "tmp-${each.key}"
resource_group_name = "rg-networking-prod"
traffic_routing_method = each.value.routing
dns_config = {
relative_name = each.value.relative_name
}
tags = { workload = each.key }
}π‘ One module block, many profiles. Each keeps its own routing method and DNS label; the shared HTTPS monitor default applies to all.
15 Β· ποΈ End-to-end composition (resource group + profile + Azure endpoints)
Wires real sibling module outputs into inputs: a resource group holds the profile, and two
traffic-manager-azure-endpoint sibling modules attach to the profile by id and point at a public IP and a
Linux web app.
module "rg" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-resource-group.git?ref=v1.0.0"
name = "rg-networking-prod"
location = "eastus"
}
module "pip_primary" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-public-ip.git?ref=v1.0.0"
name = "pip-web-primary"
resource_group_name = module.rg.name
location = "eastus"
}
module "web_secondary" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-linux-web-app.git?ref=v1.0.0"
service_plan_id = var.service_plan_id
name = "app-web-secondary"
resource_group_name = module.rg.name
location = "westus2"
}
module "traffic_manager" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-profile.git?ref=v1.0.0"
name = "tmp-web-prod"
resource_group_name = module.rg.name
traffic_routing_method = "Priority"
dns_config = {
relative_name = "contoso-web-prod"
ttl = 30
}
monitor_config = {
protocol = "HTTPS"
port = 443
path = "/healthz"
expected_status_code_ranges = ["200-299"]
custom_header = { host = { name = "Host", value = "app.contoso.com" } }
}
tags = { environment = "prod", workload = "web" }
}
# Primary endpoint β highest priority, targets the public IP.
module "endpoint_primary" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-azure-endpoint.git?ref=v1.0.0"
name = "primary"
profile_id = module.traffic_manager.id
target_resource_id = module.pip_primary.id
priority = 1
}
# Secondary endpoint β failover target, the web app.
module "endpoint_secondary" {
source = "git::https://github.com/microsoftexpert/terraform-azurerm-traffic-manager-azure-endpoint.git?ref=v1.0.0"
name = "secondary"
profile_id = module.traffic_manager.id
target_resource_id = module.web_secondary.id
priority = 2
}
output "traffic_manager_fqdn" {
value = module.traffic_manager.fqdn
}π‘ The profile owns routing and health monitoring; the endpoint modules own the backends and their per-endpoint priority/weight. Clients resolve
contoso-web-prod.trafficmanager.netand receive the primary endpoint until its HTTPS probe fails, then the secondary.
Identity (required) β name, resource_group_name.
Routing (required) β traffic_routing_method, dns_config (with relative_name).
Health & behavior (optional, secure defaults) β monitor_config, profile_status, max_return,
traffic_view_enabled.
Universal tail β tags, timeouts.
Full object() schemas
| Name | Type | Default | Description |
|---|---|---|---|
name |
string |
β (required) | Profile resource name. Immutable / force-new. |
resource_group_name |
string |
β (required) | Existing resource group name. Immutable / force-new. |
traffic_routing_method |
string |
β (required) | Priority | Weighted | Performance | Geographic | MultiValue | Subnet. Updatable in place. |
dns_config |
object({ relative_name = string, ttl = optional(number, 60) }) |
β (required) | Publishes <relative_name>.trafficmanager.net. relative_name is force-new. |
monitor_config |
object({ protocol = optional(string,"HTTPS"), port = optional(number,443), path = optional(string,"/"), interval_in_seconds = optional(number,30), timeout_in_seconds = optional(number,10), tolerated_number_of_failures = optional(number,3), expected_status_code_ranges = optional(list(string)), custom_header = optional(map(object({ name = string, value = string })), {}) }) |
HTTPS/443 probe | Endpoint health monitor. path is auto-nulled for TCP. |
profile_status |
string |
"Enabled" |
Enabled | Disabled. |
max_return |
number |
null |
1β8; required for MultiValue, rejected otherwise. |
traffic_view_enabled |
bool |
false |
Latency telemetry (extra cost). |
tags |
map(string) |
{} |
Tags applied to the profile. |
timeouts |
object({ create, read, update, delete = optional(string) }) |
null |
Optional operation timeouts. |
| Output | Description | Kind |
|---|---|---|
id |
The Azure Resource ID of the Traffic Manager profile | Passthrough |
name |
The name of the Traffic Manager profile | Passthrough |
fqdn |
The fully-qualified DNS name of the profile (e.g | Passthrough |
resource_group_name |
The resource group that holds the profile | Passthrough |
traffic_routing_method |
The routing method the profile applies to DNS queries | Passthrough |
dns_relative_name |
The DNS label the profile answers on, the leftmost part of fqdn |
Derived |
dns_ttl_seconds |
The DNS time-to-live in seconds returned to resolvers | Derived |
failover_detection_seconds |
How long Traffic Manager takes to decide an endpoint is unhealthy, in seconds: interval_in_seconds x (tolerated_number_of_failures + 1) |
Derived |
worst_case_failover_seconds |
The upper bound on how long clients may keep reaching a failed endpoint, in seconds: detection time plus the DNS TTL | Passthrough |
dns_ttl_dominates_failover_time |
True when the DNS TTL is longer than the health monitor's detection time, meaning DNS caching - not probing - is what limits failover speed | Derived |
monitor_protocol |
The protocol used for health probes | Derived |
monitor_port |
The port health probes connect to | Derived |
probe_is_encrypted |
True when health probes run over HTTPS | Derived |
probe_path_is_ignored |
True when the probe protocol is TCP, where the path has no effect | Derived |
fast_probing_enabled |
True when interval_in_seconds is 10 rather than 30 |
Derived |
single_probe_failure_removes_endpoint |
True when tolerated_number_of_failures is 0, so one missed probe takes an endpoint out of rotation |
Derived |
endpoint_weight_is_ignored_by_this_routing_method |
True unless the routing method is Weighted | Derived |
endpoint_priority_is_ignored_by_this_routing_method |
True unless the routing method is Priority | Derived |
endpoint_geo_mappings_are_required_by_this_routing_method |
True when the routing method is Geographic, where an endpoint with no geo_mappings receives no traffic at all rather than acting as a default |
Derived |
endpoint_subnets_are_required_by_this_routing_method |
True when the routing method is Subnet, where a client address matching no endpoint's ranges gets no answer | Derived |
endpoint_location_is_required_by_this_routing_method |
True when the routing method is Performance, which needs an endpoint_location on each external and nested endpoint |
Derived |
traffic_view_is_billed_separately |
True when Traffic View is enabled | Derived |
profile_answers_no_queries |
True when profile_status is Disabled |
Derived |
profile_status |
Whether the profile is Enabled or Disabled | Passthrough |
max_return |
The maximum number of endpoints returned in one answer, or null | Passthrough |
- The health monitor is the resilience control. Traffic Manager routes only to endpoints its
monitor_configreports healthy. Because the module defaults to HTTPS on 443, the empty call already performs encrypted health checks; loosening to TCP or HTTP is an explicit caller choice. - Force-new fields bite hard.
name,resource_group_name, anddns_config.relative_nameare all immutable. Changingrelative_namein particular republishes the profile under a new DNS name and forces replacement β treat it as permanent once endpoints and CNAMEs depend on it. max_returnis method-coupled. It is required forMultiValueand rejected everywhere else; the module keeps itnullby default and validates the 1β8 range so a stray value fails at plan time rather than deep in an apply.pathis protocol-coupled. The provider rejects apathon TCP probes;main.tfnullspathwheneverprotocol = "TCP", so a caller cannot construct that invalid combination through this module.custom_headerkey stability. Probe headers are a keyed map rendered through adynamicblock, so adding or removing one header never re-indexes the others.features {}dependence. The profile relies on the caller'sprovider "azurerm" { features {} }block; the module declares no provider block by design.
Secure by default β the empty call already produces the hardened resource; each relaxation is an explicit opt-out the caller must type.
| Concern | Secure default (empty call) | Opt-out (caller types it) |
|---|---|---|
| Health-probe encryption | monitor_config.protocol = "HTTPS" on port = 443 |
set protocol = "TCP" / "HTTP" or a different port |
| Profile availability | profile_status = "Enabled" (predictable, live behavior) |
set profile_status = "Disabled" |
| Probe path validity | path auto-nulled when protocol = "TCP" |
supply HTTP/HTTPS with an explicit path |
| Telemetry cost/exposure | traffic_view_enabled = false |
set traffic_view_enabled = true |
| Method-coupled inputs | max_return = null unless MultiValue |
set max_return (1β8) with MultiValue |
| DNS TTL | ttl = 60 (balanced failover vs. query volume) |
raise or lower dns_config.ttl |
# From the module folder β plan-only; a human applies from CI.
terraform init -backend=false
terraform validate
terraform fmt -check- Pin the source to a tag β
?ref=v1.0.0β never a branch. - No
applyhappens during authoring; a human runsterraform applyfrom CI against real credentials.
The offline proof gate is what this repository guarantees:
terraform validateproves the configuration is internally consistent and type-correct against the pinned provider schema β everyobject()shape, enumvalidation {}, and reference is checked without calling Azure.terraform fmt -checkenforces canonical formatting.- Only
terraform plan(run by a human, against credentials, from CI) exercises the ARM API and confirms live behavior such as DNS-name uniqueness and method-coupled field acceptance. This repository never runsplanorapplyduring authoring.
$ terraform output
id = "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-networking-prod/providers/Microsoft.Network/trafficManagerProfiles/tmp-web-prod"
name = "tmp-web-prod"
fqdn = "contoso-web-prod.trafficmanager.net"
resource_group_name = "rg-networking-prod"
traffic_routing_method = "Priority"| Symptom | Cause | Fix |
|---|---|---|
max_return error at plan/apply |
max_return set with a non-MultiValue method, or missing for MultiValue |
Set max_return (1β8) only when traffic_routing_method = "MultiValue"; leave it null otherwise. |
| Profile answers no DNS queries | profile_status = "Disabled" |
Set profile_status = "Enabled". |
| All endpoints show unhealthy | HTTPS probe on 443 fails (no TLS listener, wrong path, or status outside the expected range) | Match monitor_config.protocol/port/path to the endpoint, or widen expected_status_code_ranges. |
| "path is not valid for TCP" style rejection | A path reached a TCP probe |
Use this module's default handling (leave path unset for TCP) or switch to HTTPS. |
| Plan wants to replace the profile | Changed name, resource_group_name, or dns_config.relative_name (all force-new) |
Keep them stable; treat relative_name as permanent once endpoints/CNAMEs depend on it. |
provider not initialized / features error |
Caller root module missing provider "azurerm" { features {} } |
Add the features {} block in the root module; this module intentionally omits it. |
| DNS name already taken | relative_name collides in the global *.trafficmanager.net namespace |
Choose a globally-unique relative_name. |
- Terraform Registry β
azurerm_traffic_manager_profile - Microsoft Learn β Azure Traffic Manager documentation
- Sibling modules β
terraform-azurerm-traffic-manager-azure-endpoint,terraform-azurerm-traffic-manager-external-endpoint,terraform-azurerm-traffic-manager-nested-endpoint,terraform-azurerm-resource-group,terraform-azurerm-public-ip. - This module's
SCOPE.mdβ the cross-module contract.
π "Infrastructure as Code should be standardized, consistent, and secure."