Using dynamic inside blocks in a resource

This does not work

resource "azurerm_container_registry" "acr" {
  name                = "ml${var.TERRAFORM_WORKSPACE}acr00"
  ....
  network_rule_set {
    default_action = "Deny"
    dynamic "ip_rule" {
      for_each = module.global.whitelisted_ip_addresses
      content {
         action   = "Allow"
         ip_range = ip_rule.value
     }
   }

Error is unknown variable at the for_each line. “There is no variable named ‘module’”

Are dynamic blocks restricted to be at the “top-level”, for want of a better word, inside a resource, provider, data or provisioner. You cannot use them inside a block as illustrated ?

2 Likes

Here’s an alternative. I had the same 3 hours of pain to sort this

    locals {
  allowed_virtual_networks = [for s in var.whitelisted_subnet_ids : {
    action    = "Allow",
    subnet_id = s
  }]
}

resource "azurerm_container_registry" "acr" {
  name                     = module.azure_naming.acr_name
  location                 = var.location
  resource_group_name      = azurerm_resource_group.acr_rg.name
  sku                      = "Premium"
  admin_enabled            = false
  georeplication_locations = var.georeplicated_region_list

  network_rule_set {
    default_action  = "Deny"
    virtual_network = local.allowed_virtual_networks
  }
}

This ip_rule argument seems to be set to use the attributes as blocks backward compatibility hack, even though that for some reason isn’t mentioned in its documentation, so ip_rule isn’t really a block type and so isn’t compatible with the dynamic construct.

Instead, you’d need to use the patterns described under Arbitrary Expressions with Argument Syntax to dynamically generate values for this argument. For example:

  ip_rule = [
    for ip_range in module.global.whitelisted_ip_addresses : {
      action   = "Allow"
      ip_range = ip_range
    }
  ]

Normally when a provider is relying on that backward compatibility hack it is mentioned in the documentation with a link to the “Attributes as Blocks” page I linked above; it looks like this was missed when writing the documentation for the ip_rule argument in the Azure provider documentation, so it might be worth raising a pull request or issue in the provider’s repository to see if it can be updated to acknowledge this argument’s strange behavior.

In the Azure provider source code I see that this also applies to the virtual_network argument too, so perhaps the docs for both of these could be updated together. It seems that this also applies to the network_rule_set argument that both of these are embedded inside.


For those who want to look in provider code to check whether this is true for other arguments elsewhere, the thing to look for is the schema of the argument having the following additional setting:

  ConfigMode: schema.SchemaConfigModeAttr,

Providers use this annotation to activate the compatibility hack, so if someone in future finds this thread after encountering a similar problem and is comfortable browsing the provider codebases they can confirm whether this solution applies by looking for this special ConfigMode. One way to find these is, for example, to search for the identifier in the codebase and look in the results for the file corresponding to the resource type you’re interested in.

2 Likes