Conditional for_each based on content of each.value

I have the following map of object:

external-dns = {
   internal = {
      create_iam_policy = true
      ...
   }
   external = {
     create_iam_policy = false
   }
}

I would like to be able to iterate over a ressource aws_iam_policy with for_each based on the condition inside the map.

For example:

resource "aws_iam_policy" "external-dns" {                                                                  
   for_each = local.external-dns if each.values["create_iam"]                                                                           
   count    = local.external-dns["enabled"] && local.external-dns["create_iam_resources_irsa"] ? 1 : 0                                                      
   name     = "tf-${var.cluster-name}-${local.external-dns["name"]}"                                                                                        
   policy   = local.external-dns["iam_policy_override"]                                                =  = "" ? data.aws_iam_policy_document.external-dns.json : local.external-dns["iam_policy_override"]    
}                                                                                                 

But only if each.value[“create_iam”] is true. I don’t know if it is at all possible and if it is I don’t know the correct syntax or function to use to create a sub map wth only the map that satisfy the condition.

Thanks

You can do this by creating a new map with a for expression using an if clause. Here’s a full example using null_resource:

locals {
  external_dns = {
    internal = {
      name = "int"
      create_iam_policy = true
      iam_policy_override = "int-policy"
    }
    external = {
      name = "ext"
      create_iam_policy = false
      iam_policy_override = null
    }
  }
}

resource "null_resource" "none" {
  for_each = { for k, v in local.external_dns : k => v if v.create_iam_policy }
  triggers = {
    key = each.key
    name = each.value.name
    iam_policy_override = each.value.iam_policy_override
  }
}

The result of a plan:

$ tf plan

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # null_resource.none["internal"] will be created
  + resource "null_resource" "none" {
      + id       = (known after apply)
      + triggers = {
          + "iam_policy_override" = "int-policy"
          + "key"                 = "internal"
          + "name"                = "int"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Translating that to your example AWS resource configuration, it should look something like this:

resource "aws_iam_policy" "external-dns" {                                                                  
   for_each = { for k, v in local.external-dns : k => v  if v.create_iam_policy }
   name     = "tf-${var.cluster-name}-${each.value.name}"
   policy   = each.value.iam_policy_override == "" ? data.aws_iam_policy_document.external-dns.json : each.value.iam_policy_override
}                                                                                                 

Note that you can’t use for_each and count together in a single resource like in the original example, and you must refer to the individual object used by for_each using each.value. I hope this makes sense!

Thanks a lot I managed to do what I wanted here https://github.com/particuleio/terraform-kubernetes-addons/blob/main/modules/aws/external-dns.tf with your solution :slight_smile:

1 Like