The given key does not identify an element in this collection value

Terraform version
Terraform v1.0.11
on windows_amd64
provider registry.terraform.io/hashicorp/azurerm v2.88.

Receiving the following during terraform plan.

│ Error: Invalid index
│
│   on main.tf line 80, in module "azurerm_firewall_policy_rule_collection_groups":
│   80:   firewall_policy_id  = ["${module.azurerm_firewall_policies[each.value.firewall_policy_key].firewall_policy_id}"]
│     ├────────────────
│     │ each.value.firewall_policy_key is "policy1"
│     │ module.azurerm_firewall_policies is object with no attributes
│
│ The given key does not identify an element in this collection value.

The line module.azurerm_firewall_policies indicates the ID attribute cannot be located.
I have added the ID attribute as an output in the azurerm_firewall_policies module.

Excerpt from root module main.tf

// Firewall policies to be created


module "azurerm_firewall_policies" {

    source = "../modules/firewall_policy"

    for_each = {

        for key, value in var.azurerm_firewall_policies : key => value

        if try(value.base_policy, null) == null

    }

    location            = lookup(each.value, "region", null) == null ? [each.value.resource_group_key].location : var.global_settings.regions[each.value.region]

    global_settings     = var.global_settings

    settings            = each.value

    resource_group_name = local.resource_groups[each.value.resource_group_key].name

    tags                = var.tags

    depends_on          = [module.resource_groups]

}

// Firewall policiy rule collection groups to be created

module "azurerm_firewall_policy_rule_collection_groups" {

  depends_on = [

    local.firewall_policies

  ]

  source   = "../modules/firewall_policy_rule_collection_groups"

  for_each = var.azurerm_firewall_policy_rule_collection_groups

  global_settings     = var.global_settings

  ip_groups           = local.ip_groups

  policy_settings     = each.value

  public_ip_addresses = local.public_ip_addresses

  firewall_policy_id  = ["${module.azurerm_firewall_policies[each.value.firewall_policy_key].firewall_policy_id}"]

}

Excerpt from firewall_policy_rule_collection_group module.tf

resource "azurerm_firewall_policy_rule_collection_group" "polgroup" {

  name               = var.policy_settings.name

  priority           = var.policy_settings.priority

  firewall_policy_id = var.firewall_policy_id

Excerpt from azurerm_firewall_policies outputs.tf

output "firewall_policy_id" {

  description = "The ID of the Azure Firewall Policy"

  value       = azurerm_firewall_policy.fwpol.id

}

output "name" {

  description = "Name of the firewall policy"

  value       = azurerm_firewall_policy.fwpol.name

}

output "resource_group_name" {

  value       = azurerm_firewall_policy.fwpol.resource_group_name

}

Hi @simonmacpherson,

The error message includes the context that module.azurerm_firewall_policies is an empty object, which suggests that the if clause in your for_each expression for that module is filtering out all of the elements of var.azurerm_firewall_policies. Because of that, there is no attribute named "policy1" and therefore the lookup fails.

It seems that the for_each expression for module.azurerm_firewall_policy_rule_collection_groups includes a value whose firewall_policy_key is "policy1", and so Terraform is reporting that those two collections don’t agree with one another and so there’s no way to resolve that expression.

I’m not sure exactly what to suggest without understanding better the underlying goal, but mechanically the requirement here would be for you to make sure that the for_each expressions for these two module calls agree about which “firewall policy keys” should exist. That could mean writing a similar if clause for module.azurerm_firewall_policy_rule_collection_groups to filter out the ones that aren’t declared, or it could mean changing the definition of var.azurerm_firewall_policy_rule_collection_groups so that it only refers to policies which meet the condition of not including a value for the attribute base_policy.

Hi @apparentlymart

The goal here is to create a firewall policy rule collection group and assign the group to the created policy based on the firewall policy id.

Below is an excerpt from the .tfvars file containing the data for the
azurerm_firewall_policy_rule_collection_groups variable.

azurerm_firewall_policy_rule_collection_groups = {

  group1 = {

    firewall_policy_key = "policy1"

    name                = "default-firewall-policy-rule-collection"

    priority            = 100

    # Configure rules that contain source addresses, protocols, destination ports, and destination addresses.

    network_rule_collections = {

      group1 = {

        name     = "default_network_rule_collection"

        priority = 400

        action   = "Allow"

        rules = {

          rule1 = {

            name                  = "network_rule_collection1_rule1"

            protocols             = ["Any"]

            source_addresses      = ["10.0.0.0/8"]

            destination_addresses = ["10.0.0.0/8"]

            destination_ports     = ["80", "1000-2000", "22"]

          }

Hi @simonmacpherson,

I think what’s not clear to me is the reason for the extra filtering condition you placed on the for_each statement, which seems to be filtering out all of your firewall policy entries:

        if try(value.base_policy, null) == null

If you were to remove this and just set for_each = var.azurerm_firewall_policies directly then I assume it would have some undesirable effect that you were trying to avoid with that condition, but that condition is then in turn conflicting with the other rule you wrote elsewhere by making policy1 not be declared at all.

So it seems like one of these two requirements needs to change in order for the result to make sense together, but I’m not sure which one.

Hi @apparentlymart

I’ve removed the if try statement from the azurerm_firewall_policies module as there is not a requirement for it.

If i just set for_each = var.azurerm_firewall_policies I still get the same error.

I’m not sure if this still applies in the latest Terraform version, but I read today a limitation of for_each is that you cannot reference any resource outputs, which is what am I doing with the statement local.firewall_policies[each.value.firewall_policy_key].id. Terraform requires that it can compute for_each during the plan phase, before any resources are created or modified. It can an reference hard-coded values, variables, data sources and lists of resources, but not computed resources.

I have a local.tf which has an entry firewall_policies = module.azurerm_firewall_policies.

locals {

resource_groups = var.resource_groups

firewall_policies = module.azurerm_firewall_policies

public_ip_addresses = module.public_ip_addresses

ip_groups = module.ip_groups

}

So I’m not sure how I can assign the collection group the the policy using the firewall policy id.

Hi @simonmacpherson,

There is a specific error message for using an unknown value as the for_each collection, so if you were encountering that rule then Terraform would be explicit about it. I don’t think that’s the cause in your case.

I think the main thing to understand here is why that mapping of firewall policies is empty. Since you now have it set directly with the variable, the proximal cause must be that the variable itself is empty. So I think the next step would be to find the value of that variable and correct it so that it contains at least elements for all of the keys you will refer to from the other data structure.