Chain to resources created with count in Terraform

Viewed 485

How do I chain to resource(s) created with count? Or should I not created them with count if I want to chain additional resources to them? Doing it the way below, with count used in the initial resource and for_each used in the chained resource gives me the following error:

The given "for_each" argument value is unsuitable: the "for_each" argument must be a map, or set of strings, and you have provided a value of type number.

I understand why this error occurs, but I also am confused on the best practice here.

resource "aws_wafv2_web_acl" "waf_acl_regional" {
  count       = var.env == "prod" ? 1 : 0
  name        = "${var.project}-${var.env}"
  description = "A simple WAF ACL for ${var.env} environment."
  scope       = "REGIONAL"

  default_action {
    allow {}
  }

  rule {
    ...
  }

  visibility_config {
    ...
  }
}

resource "aws_wafv2_web_acl_association" "example" {
  for_each     = aws_wafv2_web_acl.waf_acl_regional
  resource_arn = aws_lb.hasura.arn
  web_acl_arn  = each.value.arn
}

Thanks for any help!

2 Answers

You have instructed the aws_wafv2_web_acl resource to use the count meta-argument [1], which as the name suggests uses numbers. It creates an array where you can access elements by referencing the element of the array. In your case that would be aws_wafv2_web_acl.waf_acl_regional[0]. On the other hand, the for_each meta-argument [2] uses key/value pairs. That means that in order to fetch a value, you have to have a key which will be used as a reference to a value. For example, that would be something like aws_wafv2_web_acl.waf_acl_regional["prod"]. That further means that the var.env would have to be of type map or set [3]. Those types are complex types in Terraform.


[1] https://www.terraform.io/language/meta-arguments/count

[2] https://www.terraform.io/language/meta-arguments/for_each

[3] https://www.terraform.io/language/expressions/type-constraints#complex-types

In order to project from what count produces into what for_each needs you will need to write a slightly more elaborate expression to explain to Terraform which keys it should use to identify the instances.

For example, if the name argument of aws_wafv2_web_acl is suitably unique to identify all instances of that particular resource, you could write a for expression to project the list of objects into a map where the keys are the name values:

  for_each = {
    for acl in aws_wafv2_web_acl.waf_acl_regional : acl.name => acl
  }

This relies on the fact that a count resource produces a list, which is a suitable value to project using a for expression. When doing this, it's important to select an attribute whose value is defined statically in the configuration, rather than chosen dynamically by a remote system during the apply step. For example, the id attribute of many resource types is a unique ID chosen dynamically by the remote system, and so that would not be a suitable value to use as a for_each key.

That's important because Terraform will need to know the value during the plan phase in order to explain which resource instances the plan would create when applied.

Related