Problem
When creating an Azure PostgreSQL Flexible Server, Terraform fails with an error indicating that the target subnet is missing the required service delegation.
│ Error:
│ waiting for
│ creation of the Postgresql Flexible Server "example"
│ (Resource Group "vexample-resources-test"):
│ Code="OperationFailed"
│ Message="The subnet name as example-app-dev is missing required
│ delegations Microsoft.DBforPostgreSQL/flexibleServers"
│
│ with azurerm_postgresql_flexible_server.postgreSQL,
│ on postgres.tf line 38,
│ in resource "azurerm_postgresql_flexible_server"
│ "postgreSQL":
│ 38:
│ resource "azurerm_postgresql_flexible_server"
│ "postgreSQL" { ... }This issue often occurs when you create multiple subnets using a for_each loop, but only one of those subnets needs the specific delegation for the PostgreSQL service.
Cause
A subnet delegation in Azure dedicates a specific subnet to an Azure service, allowing that service to establish basic network configuration rules. The azurerm_postgresql_flexible_server resource requires its associated subnet to have a service_delegation block for Microsoft.DBforPostgreSQL/flexibleServers.
When creating multiple subnets dynamically with for_each, you must conditionally apply this delegation block only to the specific subnet intended for the PostgreSQL server.
Solution
To resolve this, you can use a dynamic block within your azurerm_subnet resource. This approach allows you to conditionally generate the delegation block based on a boolean flag in your input variables.
Step 1: Define an Input Variable
First, define a variable of type map(object) to manage the properties of each subnet, including a boolean flag to control service delegation.
variable "subnetPrefix" {
type = map(object({
name = string
address = list(string)
service_delegation = bool
}))
}Step 2: Provide Subnet Values
Next, in your .tfvars file or another variable definition file, define the subnets. Set the service_delegation attribute to true only for the subnet that will host the PostgreSQL server.
subnetPrefix = {
"s1" = { name = "example-web-dev", address = ["172.31.6.0/28"], service_delegation = false },
"s2" = { name = "example-db-dev", address = ["172.31.6.16/28"], service_delegation = true },
"s3" = { name = "example-app-dev", address = ["172.31.6.32/27"], service_delegation = false }
}Step 3: Conditionally Create the Delegation
Finally, configure the azurerm_subnet resource to use for_each to iterate over the var.subnetPrefix map. Inside the resource, a dynamic block checks the service_delegation boolean for each subnet and creates the delegation block only when the value is true.
resource "azurerm_subnet" "example" {
for_each = var.subnetPrefix
name = each.value.name
address_prefixes = each.value.address
resource_group_name = azurerm_resource_group.example.name
virtual_network_name = azurerm_virtual_network.example.name
enforce_private_link_endpoint_network_policies = true
dynamic "delegation" {
for_each = each.value.service_delegation == true ? [1] : []
content {
name = "delegation"
service_delegation {
name = "Microsoft.DBforPostgreSQL/flexibleServers"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}
}Outcome
After applying this configuration, Terraform will generate a plan that creates three subnets. Only the subnet where service_delegation was set to true (example-db-dev) will include the required delegation block, resolving the error.
Terraform will perform the following actions:
# azurerm_subnet.example["s1"] will be created
+ resource "azurerm_subnet" "example" {
# ... (no delegation block)
}
# azurerm_subnet.example["s2"] will be created
+ resource "azurerm_subnet" "example" {
# ...
+ delegation {
+ name = "delegation"
+ service_delegation {
+ actions = [
+ "Microsoft.Network/virtualNetworks/subnets/join/action",
]
+ name = "Microsoft.DBforPostgreSQL/flexibleServers"
}
}
}
# azurerm_subnet.example["s3"] will be created
+ resource "azurerm_subnet" "example" {
# ... (no delegation block)
}
Plan: 3 to add, 0 to change, 0 to destroy.