Terraform Resource - How to interpolate the string in resource reference

I would need to iterate the following resource and reference the resource name in the property “route_table_id” dynamically as below

resource "aws_route_table" "gin" {
  vpc_id = aws_vpc.main.id
  route = [
    {
      carrier_gateway_id = "",
      cidr_block = "192.0.2.0/24", 
      transit_gateway_id = "tgw-123456789",   
    }
  ]
  tags = {
    Name = "INSIDE-RT"
  }
}

resource "aws_route_table_association" "main" {
  for_each = { for x in aws_subnet.main : x.id => element(split("-", x.tags.Name), length(split("-", x.tags.Name))-2) if  x.tags.Name == "asg-net-cnw-gin-01" || x.tags.Name == "asg-net-cnw-gin-02" }
  subnet_id      = each.key
  route_table_id = aws_route_table."${each.value}".id # this
}

I tried with format, replace but this was converted as string. Please assist

Hi @nageebuddy,

There is no syntax to dynamically choose a resource based on templating, because Terraform needs to see all of the dependencies between resources before evaluating any expressions in order to determine the correct evaluation order.

One way you can get a similar effect to what you described is to construct a mapping from subnet keys to route tables and then use that mapping for your dynamic selection. For example:

locals {
  subnet_route_tables = {
    gin   = aws_route_table.gin
    other = aws_route_table.other
  }
}

resource "aws_route_table_association" "main" {
  for_each = # ...

  subnet_id      = each.key
  route_table_id = local.subnet_route_tables[each.value].id
}

Another approach is to declare the route tables themselves with a single resource using for_each, and then that resource will appear in expressions as a map that you can access with dynamic keys.

In both approaches Terraform can see exactly which other resources the route table association resource depends on, which satisfies the requirement of being able to construct a dependency graph before evaluation.


I notice another problem with your configuration here which is not related to what you asked, but I expect you’d encounter it immediately after implementing one of the solutions I described above:

The keys in a for_each map must always be values you’ve determined statically inside the configuration, because otherwise the individual instances would not have known ids during the initial planning step. Your for_each expression seems to be using aws_subnet id values as keys, which won’t work because those are opaque ids assigned by the remote system only during the apply step, and so these instances will not have known keys during the planning step when you’ve not yet created the subnets.

You didn’t show the configuration of aws_subnet.main in your question and so I can’t show a concrete example, but the situation here is a typical use-case for Chaining for_each between resources, like this:

resource "aws_subnet" "main" {
  for_each = # whatever expression defines the set of subnets to declare

  # (subnet configuration)
}

resource "aws_route_table_association" "main" {
  for_each = {
    for key, x in aws_subnet.main : key => {
      subnet_id       = x.id
      route_table_key = element(split("-", x.tags.Name), length(split("-", x.tags.Name))-2)
    }
    if x.tags.Name == "asg-net-cnw-gin-01" || x.tags.Name == "asg-net-cnw-gin-02"
  }

  subnet_id      = each.value.subnet_id
  route_table_id = local.subnet_route_tables[each.value.route_table_key].id
}

Notice that in this variant the aws_route_table_association.main for_each expression uses exactly the same keys as the aws_subnet.main resource, which are presumably values chosen directly in your configuration, and the dynamically-chosen subnet ID is only used as part of the object we’re using as the value, in each.value.subnet_id. This then allows you to still use the dynamically-chosen subnet ID as part of the resource configuration, but to use a statically-known key as the identifier for each of the instances within Terraform’s own addresses.

1 Like

Thanks a lot. I will pick the option2 as you suggested