Search code examples
amazon-web-servicesterraformamazon-waf

If duplicates are expected, use the ellipsis (...) after the value expression


I'm using Terraform to create association between AWS WAF Web_ACL and ALBs. We have two web_acl called "internal" and "external". We have three ALBs called "1", "2" and "3". Now I want to associate web_acl "internal" with ALB "1", "external" with ALB "2" and "3".

Here's my code for the association.

resource "aws_wafv2_web_acl_association" "example" {

  for_each = { for web_acl in var.web_acl : web_acl.name => web_acl }

  resource_arn = aws_alb.example[each.value.alb].arn
  web_acl_arn  = aws_wafv2_web_acl.example[each.value.name].arn
}

Here's the definition of var.web_acl in example.tfvars.

web_acl = [
  {
    name   = "internal"
    ip_set = "internal"
    alb    = "1"
    action = "BLOCK"
  },
  {
    name   = "external"
    ip_set = "external"
    alb    = "2"
    action = "ALLOW"
  },
  {
    name   = "external"
    ip_set = "external"
    alb    = "3"
    action = "ALLOW"
  }
]

The error is "Two different items produced the key "external" in this 'for' expression. If duplicates are expected, use the ellipsis (...) after the value expression to enable grouping by key.

Basically, I wanted to associate two ALB with one web_acl. I've tried to add "..." to the end of the for loop like "for_each = { for web_acl in var.web_acl : web_acl.name => web_acl... }". But it didn't work.

Could you please advise how to solve this? Any help will be appreciated. Thanks.


Solution

  • The rule for for_each is that you must have one element in the map for each resource instance you intend to declare. The rule for maps is that keys must be unique. Therefore for this to work you need to build a map whose keys are unique for all instances that you want to declare.

    From what you've described it seems like you would need to combine name and alb together to make the final keys unique, since you've said that you want to be able to have two ALBs associated with the same name.

    To achieve that you can change the key-building part of your for expression to produce a key that includes both values needed to make it unique:

    for_each = {
      for web_acl in var.web_acl :
      "${web_acl.name}:${web_acl.alb}" => web_acl
    }
    

    The above will generate keys like this, which should therefore all be unique:

    • internal:1
    • external:2
    • external:3

    My choice to separate the two parts with a colon was arbitrary. You can use whatever string format you find intuitive as long as it includes both of the values needed to make each key unique.