DEV Community

Simranjeet Singh
Simranjeet Singh

Posted on • Originally published at awsmag.com on

How to create a VPC using Terraform?

VPC

Running your applications comes up with other challenges too and one of those challenges is having a robust network set up to host all parts in one place. We have to set up VPC (Virtual Private Cloud), internet gateway, subnet, etc. to make sure our application is working properly. The other aspect of this is to manage the infrastructure once it is ready and deployed. This is where Terraform comes in handy. Terraform is an Infrastructure-as-a-code that helps you to define infrastructure in code and you can easily maintain it for future updates.

If you are not aware of the networking fundamentals on AWS, read the article AWS Networking Fundamentals before going deep with Terraform in this article.

You need to have some information about how Terraform works. If you don’t know about Terraform, I suggest going through its documentation to have a basic idea about it before diving into the article.

I will post the snippets and add some description in steps here. You can also find the complete module at a GitHub repo aws-vpc-terraform .

Directory Structure

The above directory structure of the module has the following key files:

  • main : Contains the entire module and all the resources we will discuss in some time.
  • output : Defines the output provided by the module. This provider returns the vpcId of the VPC created by the module.
  • provider: Defines the provider required for the module to work properly. You can also think of it as dependencies required for the module. This module needs the AWS module from Hashicorp (creators of Terraform). The AWS module will allow us to use the resources available in the AWS to create our desired infrastructure.
  • variables: It contains the input variables required by the module to complete its task. For the sale of this article, I have set default values to the variables but they can be easily made required by removing the default value.

As mentioned above the most important file is main.tf which contains all the code for the resources we are about to create. Let’s go through each resource statement in file and understand them a bit.

data "aws_availability_zones" "availableAZ" {}

# VPC 
resource "aws_vpc" "vpc" { 
  cidr_block = var.cidr 
  instance_tenancy = "default" 
  enable_dns_support = true 
  enable_dns_hostnames = true 
  assign_generated_ipv6_cidr_block = true 
  tags = { 
    Name = var.namespace 
    Namespace = var.namespace 
  } 
}

# Public Subnet 
resource "aws_subnet" "publicsubnet" { 
  count = 3 
  cidr_block = tolist(var.publicSubnetCIDR)[count.index] 
  vpc_id = aws_vpc.vpc.id 
  map_public_ip_on_launch = true 
  availability_zone = data.aws_availability_zones.availableAZ.names[count.index] 
  tags = { 
    Name = "${var.namespace}-publicsubnet-${count.index + 1}" 
   AZ = data.aws_availability_zones.availableAZ.names[count.index]
   Namespace = var.namespace 
  } 
  depends_on = [aws_vpc.vpc] 
}

# Private Subnet 
resource "aws_subnet" "privatesubnet" { 
  count = 3 
  cidr_block = tolist(var.privateSubnetCIDR)[count.index] 
  vpc_id = aws_vpc.vpc.id 
  availability_zone = data.aws_availability_zones.availableAZ.names[count.index]
  tags = { 
    Name = "${var.namespace}-privatesubnet-${count.index + 1}"
    AZ = data.aws_availability_zones.availableAZ.names[count.index]
    Namespace = var.namespace 
  }
  depends_on = [aws_vpc.vpc] 
}

# Internet Gateway 
resource "aws_internet_gateway" "internetgateway" { 
  vpc_id = aws_vpc.vpc.id 
  tags = { 
    Name = "${var.namespace}-InternetGateway" 
    Namespace = var.namespace 
  }
  depends_on = [aws_vpc.vpc]
}

# Elastic IP 
resource "aws_eip" "elasticIPs" { 
  count = 3 
  vpc = true 
  tags = { 
    Name = "elasticIP-${count.index + 1}"
    Namespace = var.namespace 
  } 
  depends_on = [aws_internet_gateway.internetgateway] 
} 

# NAT Gateway 
resource "aws_nat_gateway" "natgateway" { 
  count = 3 
  allocation_id = aws_eip.elasticIPs[count.index].id 
  subnet_id = aws_subnet.publicsubnet[count.index].id 
  tags = { 
    Name = "${var.namespace}-NATGateway-${count.index + 1}"
    AZ = data.aws_availability_zones.availableAZ.names[count.index]
    Namespace = var.namespace 
  } 
  depends_on = [aws_internet_gateway.internetgateway] 
}
Enter fullscreen mode Exit fullscreen mode
  • We have all the major parts of the network and now it is time to create route tables. Route Tables define which traffic can flow to which resource. We will create a Route Table for public and private subnets.
  • Public Route Table will have the traffic flowing from Internet Gateway directly. We will also create an association record to associate the newly created route table with the public subnets.
# Route Table for Public Routes 
resource "aws_route_table" "publicroutetable" { 
  vpc_id = aws_vpc.vpc.id 
  route { 
    cidr_block = "0.0.0.0/0" 
    gateway_id = aws_internet_gateway.internetgateway.id 
  } 
  tags = { 
     Name = "${var.namespace}-publicroutetable" 
     Namespace = var.namespace 
  } 
  depends_on = [aws_internet_gateway.internetgateway] 
} 

# Route Table Association - Public Routes 
resource "aws_route_table_association" "routeTableAssociationPublicRoute" { 
  count = 3 
  route_table_id = aws_route_table.publicroutetable.id 
  subnet_id = aws_subnet.publicsubnet[count.index].id 
  depends_on = [aws_subnet.publicsubnet, aws_route_table.publicroutetable]
}

# Route Table for Private Routes 
resource "aws_route_table" "privateroutetable" { 
  count = 3 
  vpc_id = aws_vpc.vpc.id 
  route { 
    cidr_block = "0.0.0.0/0" 
    gateway_id = aws_nat_gateway.natgateway[count.index].id 
  } 
  tags = { 
    Name = "${var.namespace}-privateroutetable-${count.index + 1}"
    AZ = data.aws_availability_zones.availableAZ.names[count.index]
    Namespace = var.namespace 
  } 
  depends_on = [aws_nat_gateway.natgateway] 
} 

# Route Table Association - Private Routes 
resource "aws_route_table_association" "routeTableAssociationPrivateRoute" { 
  count = 3 
  route_table_id = aws_route_table.privateroutetable[count.index].id
  subnet_id = aws_subnet.privatesubnet[count.index].id 
  depends_on = [aws_subnet.privatesubnet, aws_route_table.privateroutetable] 
}
Enter fullscreen mode Exit fullscreen mode

Our entire module is ready. In order to run it, you have to first initialize the Terraform, see the plan and apply it to create your VPC using Terraform.

terraform init 
terraform plan 
terraform apply
Enter fullscreen mode Exit fullscreen mode

That’s all related to deploying and managing your VPC using Terraform. In upcoming articles, I will write more about creating other services and deploying some common things using Terraform. Till then Happy Coding.

Originally published at https://awsmag.com on August 1, 2021.

Top comments (0)