0
votes

I am facing a problem in Terraform. I am trying to provision VPC's and Subnets using pre-defined CIDR ranges in my variables file. Below is the code snippet from the variables file i.e variables.tf

variable "vpc-fullcidr" {
  description = "VPC CIDR range"
  type = "list"
  default = ["10.0.0.0/16", "192.168.0.0/16"]
}
variable "subnet-cidr" {
  description = "Subnet CIDR range"
  type = "list"
  default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24", "192.168.0.0/24", 
  "192.168.1.0/24", "192.168.2.0/24"]
}

variable "vpc-count" {
  description = "Number of VPC to create"
  type    = "string"
  default = "2"
}

variable "subnet-count"
{
  description = "Number of Subnets to create"
  default = "6"
}

Below is my VPC Template. VPC's are getting provisioned without any issues:-

resource "aws_vpc" "VPCPrimary" {
   count = "${var.vpc-count}"
   cidr_block = "${element(var.vpc-fullcidr, count.index)}"
   #### Below DNS values are for the internal vpc dns resolution
   enable_dns_support = true
   enable_dns_hostnames = true
   tags {
     Name = "${element(var.VPCNameTag, count.index)}"
   }
}

When I am trying to create Subnets it is failing. Below is my Subnets template :-

resource "aws_subnet" "PrivateSubnets" {
  count = "${var.subnet-count}"
  vpc_id = "${element(aws_vpc.VPCPrimary.*.id, count.index)}"
  availability_zone = "${var.primaryaz}"
  cidr_block        = "${element(var.subnet-cidr, count.index)}"
  tags {
  Name = "Private Subnet ${count.index + 1}"
  }
}

Terraform Error log :-

Error: Error applying plan:

2 error(s) occurred:

* aws_subnet.PrivateSubnets[4]: 1 error(s) occurred:

* aws_subnet.PrivateSubnets.4: Error creating subnet: InvalidSubnet.Range: 
The CIDR '192.168.1.0/24' is invalid.
status code: 400, request id: 1a9136e6-8631-43cb-99a6-ccd2522854d4
* aws_subnet.PrivateSubnets[1]: 1 error(s) occurred:

* aws_subnet.PrivateSubnets.1: Error creating subnet: InvalidSubnet.Range: 
The CIDR '10.0.2.0/24' is invalid.
status code: 400, request id: 1b0e4cf5-2e1d-402e-a89d-f08d8ac694e1

I am trying to provision the infrastructure in an automated way where the variables.tf file is getting populated dynamically using user inputs in the .NET front end using stored procedures. This issue is when I am trying to create multiple VPC's along with multiple subnets. Is there any way in which I can map the Subnet CIDR block with VPC CIDR block in the terraform resource "aws_subnet".

1
Do all the others get created ok?James Thorpe
Oh hang on, do you have any logic to separate out the 192.168.x.x subnets from the 10.x.x.x ones so they only attempt to get created in the right VPC? Or are you just looping through all subnets on both VPCs (which is what appears to be the case from the TF snippets posted), although I'd expect there to be 6 errors reported in that case...James Thorpe
I searched a lot on how to implement a logic for separating the two but couldn't find the logic. Four of the six subnets created successfully hence error is for the remaining two. I am looking for a solution in which I will have n number of VPC's and x number of subnets to be created and user will dynamically provide these details.RahulM

1 Answers

1
votes

You have two VPCs defined, which I'll call A and B:

default = ["10.0.0.0/16", "192.168.0.0/16"]
#             A               B

You then have 6 subnets defined:

  default = [
    "10.0.1.0/24", 
    "10.0.2.0/24",
    "10.0.3.0/24",
    "192.168.0.0/24", 
    "192.168.1.0/24",
    "192.168.2.0/24"]

When creating the subnets, you loop over the subnet resource 6 times, once for each of the subnets:

resource "aws_subnet" "PrivateSubnets" {
  count = "${var.subnet-count}"
  vpc_id = "${element(aws_vpc.VPCPrimary.*.id, count.index)}"

In the above, you're also using the count to index into the created VPCs. This indexing goes from 1-6, while you only have 2 VPCs, so it wraps. This means that as it goes through subnets 1-6, it's repeating the VPCs as ABABAB. If you apply that pattern to the 6 you defined, you can see why 2 fail:

  default = [
    "10.0.1.0/24",      #A
    "10.0.2.0/24",      #B <- this fails
    "10.0.3.0/24",      #A
    "192.168.0.0/24",   #B
    "192.168.1.0/24",   #A <- this fails
    "192.168.2.0/24"]   #B

You can now see why two of them fail, as they're being created in the wrong VPC. A simple fix is to just order the subnets so they index into the VPCs correctly:

  default = [
    "10.0.1.0/24",     #A
    "192.168.0.0/24",  #B
    "10.0.2.0/24",     #A
    "192.168.1.0/24",  #B
    "10.0.3.0/24",     #A
    "192.168.2.0/24"]  #B

For a more general solution, you might want to look into using modules where you can give a single VPC CIDR and relevant subnets into the module multiple times.