Terraform 40: Service Bus wiring with for_each
easy⏱ 5 mincourseterraform
One map, three linked resources
Describe each queue/topic binding once in a locals map. The same for_each map then powers: (1) a data lookup of the Service Bus topic authorization rule, and (2) the Key Vault secret that stores its connection string. Adding a subscriber is one map entry.
locals {
environment_name = "dev"
service_bus = {
"orders-events-receiver" = {
system = "shop"
topic = "orders-events-topic"
rg = "myorg-shop-bus-dev-rg"
}
"billing-events-publisher" = {
system = "shop"
topic = "billing-events-topic"
rg = "myorg-shop-bus-dev-rg"
}
}
}
Data-source the auth rule, then keyvault-secret it
Terraform doesn't create the namespace here — it reads each topic's authorization rule with a data source, then writes primary_connection_string into Key Vault. Note the strcontains(...) naming convention: a receiver uses a -sub-rule, a publisher a -publisher-rule.
data "azurerm_servicebus_topic_authorization_rule" "bus" {
for_each = local.service_bus
name = strcontains(each.key, "receiver") ? "${each.key}-sub-rule" : "${each.key}-publisher-rule"
resource_group_name = each.value.rg
namespace_name = "${local.environment_name}-${each.value.system}-namespace"
topic_name = each.value.topic
}
resource "azurerm_key_vault_secret" "bus_conn" {
for_each = local.service_bus
name = "${each.key}-connectionstring"
value = data.azurerm_servicebus_topic_authorization_rule.bus[each.key].primary_connection_string
key_vault_id = data.azurerm_key_vault.app.id
expiration_date = "2099-12-30T00:00:00Z"
}
Index instances by their map key
With a for_each map, every instance is addressed by key: data.<...>.bus[each.key] or ["orders-events-receiver"]. Keys are stable, so removing one entry destroys only that instance — unlike list count indexes, which shift and cause cascading replacements.
The connection string still lands in state
Even done right, primary_connection_string is stored in state — which is exactly why the backend must be a locked, encrypted remote store with least-privilege access. The win is that no secret sits in your source code; consumers read it from Key Vault at runtime.
Resolve each entry's auth-rule name
Write authRuleName(key) replicating the HCL ternary: if key contains "receiver" return `${key}-sub-rule`, else `${key}-publisher-rule`. Then map it over the serviceBus keys and log each key -> ruleName line. orders-events-receiver must map to orders-events-receiver-sub-rule.