amazon-web-servicesterraformterraform-provider-azureaws-vpn

How to use nested count in terraform for creating VPN endpoint routes?


I want to create VPN client endpoint in AWS using terraform.

My current block of code is:

resource "aws_ec2_client_vpn_route" "vpn_route" {
  depends_on = [
    aws_ec2_client_vpn_network_association.vpn_subnets
  ]
  count                  = length(var.rule)
  client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id
  destination_cidr_block = element(var.rule, count.index)
  target_vpc_subnet_id   = element(var.subnets_id, count.index)
}

Here rule & subnet_id variables are as below:

rule        = ["172.16.0.0/16", "172.18.0.0/16", "172.19.0.0/16"]
subnets_id  = ["subnet-123", "subnet-456"]

I want to associate each rule CIDR with both subnets. But my current code is only associating 1 subnet with 1 CIDR. I am not able to figure out how to solve it.

Update:

I modified code according to @Ervin's answer but getting following error.

Error: error creating client VPN route "cvpn-endpoint-0e72bbde5,subnet-0fefd,172.19.0.0/16": ConcurrentMutationLimitExceeded: Cannot initiate another change for this endpoint at this time. Please try again later.
│       status code: 400, request id: 2663f630-54a1-4a22-a093-d04425204cf5
│
│   with module.VPN-Endpoint.aws_ec2_client_vpn_route.vpn_route["5"],
│   on modules\VPN-Endpoint\rule_route.tf line 14, in resource "aws_ec2_client_vpn_route" "vpn_route":
│   14: resource "aws_ec2_client_vpn_route" "vpn_route" {

I guess it is because each route should be created one by one. So I modified my code as below by adding time sleep:

resource "time_sleep" "wait_30_seconds" {

  create_duration = "30s"
}

resource "aws_ec2_client_vpn_route" "vpn_route" {
  depends_on = [
    aws_ec2_client_vpn_network_association.vpn_subnets,
    time_sleep.wait_30_seconds
  ]
  for_each               = { for index, pair in setproduct(var.rule, var.subnets_id) : index => pair }
  client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id
  destination_cidr_block = each.value[0]
  target_vpc_subnet_id   = each.value[1]
}

But it is still not working. Is there any workaround for this?


Solution

  • You can accomplish this by using setproduct. This function computes the Cartesian-product for the elements of the two lists.

    resource "aws_ec2_client_vpn_route" "vpn_route" {
      depends_on = [
        aws_ec2_client_vpn_network_association.vpn_subnets
      ]
      for_each               = { for index, pair in setproduct(var.rule, var.subnets_id) : index => pair }
      client_vpn_endpoint_id = aws_ec2_client_vpn_endpoint.vpn.id
      destination_cidr_block = each.value[0]
      target_vpc_subnet_id   = each.value[1]
    }