Create a Virtual Private Cloud (VPC) on AWS using Terraform

In this article, I will show you how to create a VPC along with Subnets, Internet Gateway, NAT Gateways, and Route Tables. We will be making 1 VPC with 4 Subnets: 2 Private and 2 Public, 2 NAT Gateways, 1 Internet Gateway, and 4 Route Tables.

Before proceeding, I assume that you have a basic understanding of Terraform and VPC on AWS. To learn the VPC and its creation from the AWS console, you can click here and to learn the basics of Terraform you can search for "What is Terraform and how to install it on the AWS EC2 Instance?"

Pre-requisites

  1. Basic understanding of Terraform.
  2. Terraform installed on your system.
  3. AWS Account (Create if you don’t have one).
  4. 'access_key' & 'secret_key' of an AWS IAM User. (Click here to learn to create an IAM user with 'access_key' & 'secret_key' on AWS, )

What we will do

  1. Write Terraform configuration files for creating a VPC with other dependent resources.
  2. Create a VPC and other dependent resources using the Terraform configuration files
  3. Delete the created VPC and other dependent resources using Terraform

Write Terraform configuration files for creating a VPC with other dependent resources.

Create a dedicated directory where you can create terraform configuration files.

Use the following command to create a directory and change your present working directory to it.

mkdir terraform
cd terraform/

I am using "vim" as an editor to write in files. You can use an editor of your choice and copy-paste the following configurations to create variables.tf, terraform.tfvars, and main.tf

Create 'main.tf', which is responsible for creating VPC on to AWS with the dependent resources. This main.tf will read values of variables from variables.tf and terraform.tfvars.

vim main.tf
provider "aws" {
      region     = "${var.region}"
      access_key = "${var.access_key}"
      secret_key = "${var.secret_key}"
}


# VPC resources: This will create 1 VPC with 4 Subnets, 1 Internet Gateway, 4 Route Tables. 

resource "aws_vpc" "default" {
  cidr_block           = var.cidr_block
  enable_dns_support   = true
  enable_dns_hostnames = true
}

resource "aws_internet_gateway" "default" {
  vpc_id = aws_vpc.default.id
}

resource "aws_route_table" "private" {
  count = length(var.private_subnet_cidr_blocks)

  vpc_id = aws_vpc.default.id
}

resource "aws_route" "private" {
  count = length(var.private_subnet_cidr_blocks)

  route_table_id         = aws_route_table.private[count.index].id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.default[count.index].id
}

resource "aws_route_table" "public" {
  vpc_id = aws_vpc.default.id
}

resource "aws_route" "public" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.default.id
}

resource "aws_subnet" "private" {
  count = length(var.private_subnet_cidr_blocks)

  vpc_id            = aws_vpc.default.id
  cidr_block        = var.private_subnet_cidr_blocks[count.index]
  availability_zone = var.availability_zones[count.index]
}

resource "aws_subnet" "public" {
  count = length(var.public_subnet_cidr_blocks)

  vpc_id                  = aws_vpc.default.id
  cidr_block              = var.public_subnet_cidr_blocks[count.index]
  availability_zone       = var.availability_zones[count.index]
  map_public_ip_on_launch = true
}

resource "aws_route_table_association" "private" {
  count = length(var.private_subnet_cidr_blocks)

  subnet_id      = aws_subnet.private[count.index].id
  route_table_id = aws_route_table.private[count.index].id
}

resource "aws_route_table_association" "public" {
  count = length(var.public_subnet_cidr_blocks)

  subnet_id      = aws_subnet.public[count.index].id
  route_table_id = aws_route_table.public.id
}


# NAT resources: This will create 2 NAT gateways in 2 Public Subnets for 2 different Private Subnets.

resource "aws_eip" "nat" {
  count = length(var.public_subnet_cidr_blocks)

  vpc = true
}

resource "aws_nat_gateway" "default" {
  depends_on = ["aws_internet_gateway.default"]

  count = length(var.public_subnet_cidr_blocks)

  allocation_id = aws_eip.nat[count.index].id
  subnet_id     = aws_subnet.public[count.index].id
}
 

Create 'variables.tf' which contains the declaration and definition of the variables.

vim variables.tf
variable "access_key" {
     description = "Access key to AWS console"
     
}
variable "secret_key" {
     description = "Secret key to AWS console"
     
}

variable "region" {
  default     = "eu-west-3"
  type        = string
  description = "Region of the VPC"
}


variable "cidr_block" {
  default     = "10.0.0.0/16"
  type        = string
  description = "CIDR block for the VPC"
}

variable "public_subnet_cidr_blocks" {
  default     = ["10.0.0.0/24", "10.0.2.0/24"]
  type        = list
  description = "List of public subnet CIDR blocks"
}

variable "private_subnet_cidr_blocks" {
  default     = ["10.0.1.0/24", "10.0.3.0/24"]
  type        = list
  description = "List of private subnet CIDR blocks"
}

variable "availability_zones" {
  default     = ["eu-west-3a", "eu-west-3b"]
  type        = list
  description = "List of availability zones"
}
 

Create 'terraform.tfvars' which contains the definition of access_key and secret_key variables defined in the above file. We have kept the declaration of these two variables in 'terraform.tfvars' file.

The following keys need to be changed with the keys of your IAM user.

vim terraform.tfvars
access_key = "AKIAQ6GAIA5XIHHM2GJM"
secret_key = "pEPqnBW1jZ/PJPGn/wlydEge3kgGdCPzQ+xkJqG1"

Now, you should have 3 files, viz, variables.tf, terraform.tfvars, and main.tf

Create a VPC and other dependent resources using the Terraform configuration files

Before you execute the following commands, make sure you have configured the valid access_key and secret_key.

The first command to be used is 'terraform init'. This command downloads and installs plugins for providers used within the configuration. In our case, it is AWS.

terraform init

The second command to be used is 'terraform plan'. This command is used to see the changes that will take place on the infrastructure.

terraform plan

'terraform apply' command will create the resources on the AWS mentioned in the main.tf file. You will be prompted to provide your input to create the resources.

terraform apply

When you execute the above command,  you can see that 20 new resources have been added and 0 has been destroyed in the output.

You can go to the AWS VPC console to verify if the VPC is created along with Subnets, Route Tables NAT Gateways, and an Internet Gateway.

Delete the created VPC and other dependent resources using Terraform

If you no longer require resources you created using the configuration mentioned in the main.tf file, You can use the "terraform destroy" command to delete all those resources.

terraform destroy

When you execute the above command,  you can see that 20 resources that have been created are destroyed in the output. You can verify the same by visiting AWS in the VPC Dashboard.

Conclusion

In this article, we saw the steps to create a VPC with 4 Subnets, 4 Route Tables, 2 NAT Gateways, and 1 Internet Gateway. We also saw how the resources which were created can be destroyed.

Share this page:

Suggested articles

1 Comment(s)

Add comment

Comments

By: s at: 2020-06-06 15:52:17

very informative