Hi,
I have noticed that its not possible to pass a list of cidr when create an aws_route.
Without this I am not sure how can we achieve my use case.
I have a list of route tables on which I want to loop and on every route table I need to add multiple rules(for every private subnet cidr)
resource "aws_route" "monitoring_to_mediamon" {
count = "${length(data.aws_route_tables.monitoring_rts.ids)}"
route_table_id = "${element(data.aws_route_tables.monitoring_rts.ids, count.index)}"
destination_cidr_block = "${data.terraform_remote_state.vpc.private_subnet_cidrs}"
vpc_peering_connection_id = "${aws_vpc_peering_connection.peer.id}"
}
Executing the above code gives following error:
Error: aws_route.mediamon_to_monitoring: destination_cidr_block must be a single value, not a list
An AWS route should only have one element in the destination_cidr_block argument, so there should be no need to change the aws_route resource.
Assuming that private_subnet_cidrs is a list, I suggest basing the count on the number of private_subnet_cidrs and referencing the destination_cidr_block via something like
"${data.terraform_remote_state.vpc.private_subnet_cidrs[count.index]}"
@heycasey why do we need to restrict that destination_cidr_block should only have one value.
In our architecture we create three types of subnets in each VPC. App subnet, Data subnet and public subnet and each subnet type is in all availability zone. So if I deploy in Oregon my code would create 9 subnets.
Now there is another stack that does vpc peering between two VPCs and I need to modify the route tables in a way that only App subnets of both VPCs are able to communicate with each other. Each subnet has its own route table.
In the VPC peering stack I get following values as array vpc1_app_subnet_route_table_ids, vpc2_app_subnet_route_table_ids, vpc1_app_subnet_cidrs, vpc2_app_subnet_cidrs
So now if I need to achieve this from terraform I need to do something like this:
resource "aws_route" "vpc1" {
count = "${length(var.vpc1_app_subnet_route_table_ids)}"
route_table_id = "${element(var.vpc1_app_subnet_route_table_ids, count.index)}"
destination_cidr_block = "${var.vpc2_app_subnet_cidrs}"
vpc_peering_connection_id = "${aws_vpc_peering_connection.peer.id}"
}
resource "aws_route" "vpc2" {
count = "${length(var.vpc2_app_subnet_route_table_ids)}"
route_table_id = "${element(var.vpc2_app_subnet_route_table_ids, count.index)}"
destination_cidr_block = "${var.vpc1_app_subnet_cidrs}"
vpc_peering_connection_id = "${aws_vpc_peering_connection.peer.id}"
}
In the above code I need to pass an array of cidr to destination_cidr_block while itterating over (using count) route table ids.
I cannot use count for cidrs as I am already using it for route tables. I don't think there is any way to achieve this in terraform right now.
@heycasey I think it's a good feature to have if we can pass a list of cidr when creating aws_route.
+1 for @ankurkgupta
i have the same problem as @ankurkgupta: 2 VPCs over VPC peering connection but in different modules. It becomes really repetitive to create a module variable per CIDR block. I could instead pass a list to the module and then decode from within the module with array indices: routes[0], routes[1], .. but that's implying the module should know how many routes there are.
@ankurkgupta I have the same issue where I'm using count to populate a list for the route_table_ids and I need to pass a list of cidrs to the destination_cidr_block
did you find any work arounds?
Hi Guys, jumping in late here:
I am retrieving a list of Cidr Blocks from a data block and then I iterate through it using a FOR, it should work:
resource "aws_route" "route" {
provider = aws.shared
route_table_id = data.aws_route_table.shared_rtable.id
for_each = {for s in data.aws_subnet.shared_cidrblocks: s.cidr_block => s}
destination_cidr_block = each.value.cidr_block
transit_gateway_id = aws_ec2_transit_gateway.tgw.id
depends_on = [aws_ram_principal_association.ramprincipalassoci,aws_ram_resource_association.ramassociation,aws_ec2_transit_gateway.tgw, aws_ec2_transit_gateway_vpc_attachment.fromshared]
}
But for now it throws
Error: Error creating route: InvalidParameterValue: Route target is not supported. This route only supports interface and instance targets.
status code: 400
They way I found to make this work is to use count with multiple indexes:
locals {
routes_with_destination_cidrblocks = setproduct(data.terraform_remote_state.vpc_vpc1.outputs.private_subnet_route_table_ids, var.destination_cidr_block)
}
resource "aws_route" "add-routes-to-TransitGatway" {
count = length(local.routes_with_destination_cidrblocks)
route_table_id = local.routes_with_destination_cidrblocks[count.index][0]
destination_cidr_block = local.routes_with_destination_cidrblocks[count.index][1]
transit_gateway_id = var.transit_gateway_id
}
var.destination_cidr_block is a list of cidr blocks:
variable "destination_cidr_block" {
description = "list of cidr blocks to add to route table with destination transitgateway"
type = list(string)
default = []
}
example of variable cidr blocks:
destination_cidr_block = [
"10.10.192.0/20",
"10.10.208.0/20",
"10.10.224.0/20",
]
i would like for this feature to happen.
Simple scenario is if i want multiple routetables depending on the count to be populate dwith multiple routes.
Cannot use count and for_each in the same resource so making the destination_cidr a list would be perfect
You should be able to use the setproduct function to produce a single list that can be iterated over with for_each.
Most helpful comment
They way I found to make this work is to use count with multiple indexes:
var.destination_cidr_block is a list of cidr blocks:
example of variable cidr blocks: