Invalid for_each argument during the aws_lb_target_group_attachment

Hi there,
I have two target_groups - one for port 80 and another for 443. Also have two instances as the members and I need to attach both of the target groups to each instance. So this is the code I’m using, to attach:

// Creates the target-group
resource "aws_lb_target_group" "nlb_target_groups" {
  for_each = {
    for lx in var.nlb_listeners : "${lx.protocol}:${lx.target_port}" => lx
  }
  name                 = "${var.vpc_names[var.idx]}-tgr-${each.value.target_port}"
  deregistration_delay = var.deregistration_delay
  port                 = each.value.target_port
  protocol             = each.value.protocol
  vpc_id               = var.vpc_ids[var.idx]
  proxy_protocol_v2    = true

  health_check {
    port                = each.value.health_port
    protocol            = each.value.protocol
    interval            = var.health_check_interval
    healthy_threshold   = var.healthy_threshold
    unhealthy_threshold = var.unhealthy_threshold
  }
}

// Attach the target groups to the instance(s)
resource "aws_lb_target_group_attachment" "tgr_attachment" {
  for_each = {
    for pair in setproduct(keys(aws_lb_target_group.nlb_target_groups), var.elb_members.ids) : "${pair[0]}:${pair[1]}" => {
      target_group = aws_lb_target_group.nlb_target_groups[pair[0]]
      instance_id  = pair[1]
    }
  }
  target_group_arn = each.value.target_group.arn
  target_id        = each.value.instance_id
  port             = each.value.target_group.port
  #target_id       = [for tid in range(var.inst_count) : data.aws_instances.nlb_insts.ids[tid]]
}

where var.nlb_listeners is like this:

nlb_listeners = [
  {
    protocol    = "TCP"
    target_port = "80"
    health_port = "1936"
  },
  {
    protocol    = "TCP"
    target_port = "443"
    health_port = "1936"
  }
]

and var.elb_members.ids is like this:

"ids" = [
    "i-015604f88xxxxxx42",
    "i-0e4defceexxxxxxe5",
  ]

but I’m getting Invalid for_each argument error:

Error: Invalid for_each argument

  on ../../modules/elb/balencer.tf line 46, in resource "aws_lb_target_group_attachment" "tgr_attachment":
  46:   for_each = {
  47:     for pair in setproduct(keys(aws_lb_target_group.nlb_target_groups), var.elb_members.ids) : "${pair[0]}:${pair[1]}" => {
  48:       target_group = aws_lb_target_group.nlb_target_groups[pair[0]]
  49:       instance_id  = pair[1]
  50:     }
  51:   }

The "for_each" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the for_each depends on.

I cannot figure out why it’s either invalid or how this for_each cannot determine the values. Any idea what’s am I doing wrong here? Seriously got stuck in the middle and would really appreciate any help to put me to the right direction.

-S

Am I the first one experiencing that? Any suggestions from any one at all?

-S

Okay, I have figure out in my way, which is working fine for now. In my ec2 child-module, I have a data-source like this:

ec2/data.tf

// List of instance attributes by role
data "aws_instance" "by_role" {
  for_each = {
    for ic in range(var.inst_count): "${var.inst_role}0${ic+1}" => ic
  }
  instance_tags  = {
    Name = "${var.vpc_names[var.idx]}${each.key}"
  }
  instance_id    = aws_instance.inst[substr(each.key,4,2)-1].id
}
// 
output "inst_by_role" {
  value = data.aws_instance.by_role
}

That returns a map like this:

inst_info = {
  "asa01" = {
    "ami" = "ami-06a5087891b6d8eb8"
    "arn" = "arn:aws:ec2:us-east-1:619xx:instance/i-0939b2db7xx"
    "associate_public_ip_address" = false
    ..........
  }
  "asa02" = {
    "ami" = "ami-06a5087891b6d8eb8"
    "arn" = "arn:aws:ec2:us-east-1:619xx:instance/i-0ab3f8dae7xx"
    "associate_public_ip_address" = false
    .........
  }
}

and in the nlb child-module:

nlb/listener.tf

variable "inst_info" {
  #type       = map
  description = "List of attributes of the NLB members"
}
// Attach the target groups to the instance(s)
resource "aws_lb_target_group_attachment" "tgr_attachment" {
  for_each = {
    for pair in setproduct(keys(aws_lb_target_group.nlb_target_groups), keys(var.inst_info)):
    "${pair[0]}:${pair[1]}" => {
      target_group = aws_lb_target_group.nlb_target_groups[pair[0]]
      inst_name    = var.inst_info[pair[1]]
    }
  }
  target_group_arn = each.value.target_group.arn
  target_id        = each.value.inst_name.id
  port             = each.value.target_group.port
}

then feed the data in the root-module:

module "asa-nlb" {
  source    = "../../modules/nlb"
  inst_role = "asa"
  inst_info = module.dfw.inst_by_role
  .......
}

this reply from @apparentlymart helped me a lot to look for a alternative way to get it working.

-San