Dynamic block gives unsupported attribute error on local variable and each.key

I’m running into an issue when I attempt to reference a local variable as the for_each argument of a dynamic block inside of a parent for_each. The statement also attempts to reference the key from the parent for_each, which Terraform also errors on. When I comment out the dynamic block in question, Terraform is able to validate the code and generate a plan without issue.

The simplified resource creation code is below.

resource "azurerm_linux_web_app" "linux_webapps" {
  for_each = var.linux_java_app_services
  ...
  site_config {
    ...
    dynamic "ip_restriction" {
      iterator = "subnet_rule"
      for_each = (local.app_service_network_restrictions[(each.key)].subnets)
      content {
        action = subnet_rule.value.action
        name = subnet_rule.value.name
        priority = subnet_rule.value.priority
        virtual_network_subnet_id = subnet_rule.value.virtual_network_subnet_id
      }
    }
  }
}

With the dynamic block included, Terraform errors with two “Unsupported attribute” errors. I have multiple dynamic blocks due to the required naming conventions; however, each block produces the same errors. I’ve commented out all the blocks and tested each one individually as well as modified the references to include or not include parenthesis around different portions of the argument.

Error on “local.app_service_network_restrictions”
for_each = (local.app_service_network_restrictions[(each.key)].subnets)
This object does not have an attribute named “app_service_network_restrictions”.

Error on “each.key”
for_each = (local.app_service_network_restrictions[(each.key)].subnets)
This object does not have an attribute named “key”.

The variables and locals referenced are formatted as follows. Truncated to remove irrelevant items.

linux_java_app_services = {
  "app1" = {
    ...
    network_restrictions_azure_services = [{
      action = "Allow"
      is_frontend_rule = false
      is_scm_rule = true
      priority = 100
      service = "AzureCloud"
    }]
   network_restrictions_vnet_subnets = [{
      action = "Allow"
      is_frontend_rule = true
      is_scm_rule = false
      priority = 100
      subnet_key = "AzureAppGatewayFirewall"
      vnet_key = "vn-001"
    }]
  }
}

locals {
  app_service_network_restrictions = {for key, value in var.linux_java_app_services : key => {
    scm_services = [for restriction in value.network_restrictions_azure_services : {
      action = restriction.action
      name = "${restriction.action} ${restriction.service}"
      priority = restriction.priority
      service_tag = restriction.service
    } if restriction.is_scm_rule]
    subnets = [for restriction in value.network_restrictions_vnet_subnets : {
      action = restriction.action
      name = "${restriction.action} ${restriction.subnet_key} on ${restriction.vnet_key}"
      priority = restriction.priority
      virtual_network_subnet_id = module.vnet.network[(restriction.vnet_key)].subnets[(restriction.subnet_key)].id
    } if restriction.is_frontend_rule]
}

When I output my local.app_service_network_restrictions variable, it is formatted as I expect.

  + app_restrictions = {
      + app1 = {
          + ips          = []
          + scm_ips      = []
          + scm_services = [
              + {
                  + action      = "Allow"
                  + name        = "Allow AzureCloud"
                  + priority    = 100
                  + service_tag = "AzureCloud"
                },
            ]
          + scm_subnets  = []
          + services     = []
          + subnets      = [
              + {
                  + action                    = "Allow"
                  + name                      = "Allow AzureAppGatewayFirewall on vn-001"
                  + priority                  = 100
                  + virtual_network_subnet_id = "/subscriptions/-removed ID-/resourceGroups/example001/providers/Microsoft.Network/virtualNetworks/vn-001/subnets/AzureAppGatewayFirewall"
                },
            ]
        }
    }

I’m unsure of how to proceed, as my output statement

output "app_restrictions" {
  value = local.app_service_network_restrictions
}

indicates that the attribute does exist, and “each.key” is used elsewhere without issue.
If anyone can shed some light on what I’m overlooking, I’d appreciate it.

1 Like

For anyone who comes here with a similar issue, the problem was the iterator declaration. It’s the same as defining a variable name, so the value should not be enclosed in quotation marks.

# Wrong syntax
iterator = "custom_iterator"

# Correct syntax
iterator = custom_iterator

Hopefully Hashicorp will make a change to provide an error message on the iterator declaration instead of the for_each line.

1 Like