Map VPC endpoint IPs from multiple aws_vpc_endpoint objects


I have a map of distinct VPC endpoints I am creating, and I’m trying to include the IPs of those endpoints in my TF outputs. I am trying to iterate over the and resolve them using aws_network_interface objects, but I can’t seem to find the correct syntax to iterate over a map of lists (and yield a map of lists).

If I do this:

resource "aws_vpc_endpoint" "my_endpoints" {
    for_each = var.map_of_endpoint_services
    vpc_id             = var.my_vpc
    service_name       = each.value.service_name
    auto_accept        = true
    vpc_endpoint_type  = "Interface"
    security_group_ids = [aws_security_group.my_endpoint[each.key].id]
    subnet_ids         = var.my_subnet_ids

 data "aws_network_interface" "my_enis" {
   for_each = { for eni in flatten([
     for svc, s in aws_vpc_endpoint.my_endpoints : [
       for eni in s.network_interface_ids : {
         svc = svc
         eni = eni
   ]) : "${eni.svc}_${eni.eni}" => eni }
  id = each.value.eni

I get the following:

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 understand what that means, but I don’t know how to flatten it in such a way that:

  • I can tell it how many per endpoint there will be (the length of the subnet list)
  • I can convert it back to a map of lists, e.g. “service_name” => [ip1, ip2, …]

The only way I’ve seen this work is by creating a separate resource for each endpoint type, like:

resource "aws_vpc_endpoint" "my_endpoint_1" {

data "aws_network_interface" "my_eni_1" {

But I really don’t want to have to enumerate every endpoint type in the code. The point is to have a single map of all the endpoints I need and build from that.

Is this doable?


As noted in other places (Stack Overflow and some Terraform bug reports on this issue), we were able to make this work by moving the data source and output definitions outside the module where the VPC endpoints are created. Once the module has finished, the for_each constraint is no longer an issue.

That said, I still think this is something we should be able to do inside the module.