How to Create, configure and peer two VPC on AWS using Terraform!!
By: Gaurav Kaushik
Tags: Vpc, DevOps, AWS, Vpc Peering, Terraform

AWS is one of the most stable and talked about Cloud IaaS(Infrastructure as a Service) as of today. Managing Cloud resources manually on IaaS platform can be a tedious task.

Automation and Orchestration comes handy while creating Cloud Infrastructure resources & this is where Terraform comes into picture.

HashiCorp’s Terraform is a tool for creating and managing Cloud Infrastructure for various Cloud Iaas vendors like AWS, Azure, Google Cloud to name a few.

Hereby, this post demonstrates a Virtual Private Cloud(VPC) Peering example & will cover all the necessary components of VPC Peering configuration as this is one of the most important & widespread use-case in AWS Cloud Networking.

I will be showing the configurations directly as I suppose the readers are well-versed with basics and willing to look for Terraform in action:

VPC Peering Objective:

1) Create two VPCs

2) Create 5 subnets in VPC-1: 4 subnets should be Private(names: app1, app2, DB, DBCache) and 1 public subnet(web1) for sending Internet requests

3) Create 2 subnets in VPC-2: 1 Private subnet(DB2) and 1 Public subnet(web2)

4) DBCache and app1 subnets should be able to send Internet requests

5) DB Instance from each VPC should be able to access each other

VPC-1 Configuration:

File: variables.tf

variable "aws_region" {

description = "Default AWS Region"

default = "us-east-1"

} variable "vpc_cidr1" {

description = "VPC CIDR by default"

default = "10.20.0.0/16"

} variable "vpc_cidr2" {

description = "VPC CIDR by default"

default = "11.20.0.0/16"

}

File: main.tf starts

# Provider provider "aws" {

profile = "default"

region = var.aws_region

}

Create VPCs

# VPC-1 resource “aws_vpc” “main” { cidr_block = var.vpc_cidr1

instance_tenancy = “default” tags = {

Name = “vpc_production”

}

} #VPC-2 resource “aws_vpc” “dev” { cidr_block = var.vpc_cidr2

instance_tenancy = “default” tags = { Name = “vpc_development”

}

}

Create Internet Gateway & attach it to VPC: This is going to provide Internet Connectivity to the instances in the ‘web’ subnet

resource "aws_internet_gateway" "gw1" {

vpc_id = aws_vpc.main.id tags = {

Name = "IGW_production"

} depends_on = [aws_internet_gateway.gw1]

}

Create & Attach NAT Gateway to the VPC: NAT Gateway will provide Internet connectivity to the instances which are in a private subnet but needs to send Internet requests:- “app1” & “DBCache”

resource "aws_eip" "nat_eip" {

vpc = true

} resource "aws_nat_gateway" "nat_gateway" {

allocation_id = aws_eip.nat_eip.id

subnet_id = aws_subnet.web1.id tags = {

"Name" = "NatGateway"

}

}

Create Subnets:

resource "aws_subnet" "web1" {

vpc_id = aws_vpc.main.id

cidr_block = "10.20.1.0/24"

map_public_ip_on_launch = true tags = {

Name = "web-production"

}

} resource "aws_subnet" "app1" {

vpc_id = aws_vpc.main.id

cidr_block = "10.20.2.0/24" tags = {

Name = "app1"

}

} resource "aws_subnet" "app2" {

vpc_id = aws_vpc.main.id

cidr_block = "10.20.3.0/24" tags = {

Name = "app2"

}

} resource "aws_subnet" "DB1" {

vpc_id = aws_vpc.main.id

cidr_block = "10.20.4.0/24" tags = {

Name = "DB-production"

}

} resource "aws_subnet" "DBCache" {

vpc_id = aws_vpc.main.id

cidr_block = "10.20.5.0/24" tags = {

Name = "DBCache"

}

}

Create Route tables and associate it to subnets: Route Table contains entry to specific networks & gateways

resource "aws_route_table" "r1" {

vpc_id = aws_vpc.main.id route {

cidr_block = "0.0.0.0/0"

gateway_id = aws_internet_gateway.gw1.id

} tags = {

Name = "Public Route Table"

} depends_on = [aws_internet_gateway.gw1]

} resource "aws_route_table" "r3" {

vpc_id = aws_vpc.main.id route {

cidr_block = "0.0.0.0/0"

gateway_id = aws_nat_gateway.nat_gateway.id

} tags = {

Name = "Private Route Table with Internet Requests"

} depends_on = [aws_internet_gateway.gw1]

}

Associate subnet to Route Table

resource "aws_route_table_association" "a" {

subnet_id = aws_subnet.web1.id

route_table_id = aws_route_table.r1.id

} resource "aws_route_table_association" "b" {

subnet_id = aws_subnet.app2.id

route_table_id = aws_route_table.r2.id

} resource "aws_route_table_association" "c" {

subnet_id = aws_subnet.DB1.id

route_table_id = aws_route_table.r2.id

} resource "aws_route_table_association" "e" {

subnet_id = aws_subnet.app1.id

route_table_id = aws_route_table.r3.id

} resource "aws_route_table_association" "f" {

subnet_id = aws_subnet.DBCache.id

route_table_id = aws_route_table.r3.id

}

VPC Peering: This is our main goal. VPC Peering connects two VPCs

resource "aws_vpc_peering_connection" "Prod-Dev" {

peer_vpc_id = aws_vpc.main.id

vpc_id = aws_vpc.dev.id

auto_accept = true

}

VPC-2 Configuration: Mostly same as config. for VPC-1

Create Internet Gateway & attach it to VPC

resource "aws_internet_gateway" "gw2" {

vpc_id = aws_vpc.dev.id tags = {

Name = "IGW_development"

} depends_on = [aws_internet_gateway.gw2]

}

Create Subnets

resource "aws_subnet" "web2" {

vpc_id = aws_vpc.dev.id

cidr_block = "11.20.1.0/24"

map_public_ip_on_launch = true tags = {

Name = "web-development"

}

} resource "aws_subnet" "DB2" {

vpc_id = aws_vpc.dev.id

cidr_block = "11.20.4.0/24" tags = {

Name = "DB-development"

}

}

Create Route tables and associate it to subnets

resource "aws_route_table" "r2" {

vpc_id = aws_vpc.main.id route {

cidr_block = "11.20.4.0/24"

gateway_id = aws_vpc_peering_connection.Prod-Dev.id

} tags = {

Name = "Private Route Table"

} depends_on = [aws_vpc_peering_connection.Prod-Dev]

} resource "aws_route_table" "r4" {

vpc_id = aws_vpc.dev.id route {

cidr_block = "0.0.0.0/0"

gateway_id = aws_internet_gateway.gw2.id

} tags = {

Name = "Public Route Table Development"

} depends_on = [aws_internet_gateway.gw2]

} resource "aws_route_table" "r5" {

vpc_id = aws_vpc.dev.id route {

cidr_block = "10.20.4.0/24"

gateway_id = aws_vpc_peering_connection.Prod-Dev.id

} tags = {

Name = "Private Route Table Development"

} depends_on = [aws_vpc_peering_connection.Prod-Dev]

}

Associate subnet to Route Table

resource "aws_route_table_association" "g" {

subnet_id = aws_subnet.web2.id

route_table_id = aws_route_table.r4.id

} resource "aws_route_table_association" "h" {

subnet_id = aws_subnet.DB2.id

route_table_id = aws_route_table.r5.id

}

Create Security Groups

resource "aws_security_group" "all_traffic1" {

name = "SG_VPC"

description = "Allow inbound traffic"

vpc_id = aws_vpc.main.id ingress {

description = "TLS from VPC"

from_port = 0

to_port = 0

protocol = "-1"

cidr_blocks = [aws_vpc.main.cidr_block]

} egress {

from_port = 0

to_port = 0

protocol = "-1"

cidr_blocks = ["0.0.0.0/0"]

}

depends_on = [aws_vpc.main] tags = {

Name = "allow_ssh"

}

} resource "aws_security_group_rule" "ssh_inbound_access1" {

from_port = 22

protocol = "tcp"

security_group_id = aws_security_group.all_traffic1.id

to_port = 22

type = "ingress"

cidr_blocks = ["0.0.0.0/0"]

} resource "aws_security_group" "all_traffic2" {

name = "SG_VPC"

description = "Allow inbound traffic"

vpc_id = aws_vpc.dev.id ingress {

description = "TLS from VPC"

from_port = 0

to_port = 0

protocol = "-1"

cidr_blocks = [aws_vpc.dev.cidr_block]

} egress {

from_port = 0

to_port = 0

protocol = "-1"

cidr_blocks = ["0.0.0.0/0"]

}

depends_on = [aws_vpc.dev] tags = {

Name = "allow_ssh"

}

} resource "aws_security_group_rule" "ssh_inbound_access2" {

from_port = 22

protocol = "tcp"

security_group_id = aws_security_group.all_traffic2.id

to_port = 22

type = "ingress"

cidr_blocks = ["0.0.0.0/0"]

}

Create EC2 Instances in their respective VPCs

resource "aws_instance" "web1" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic1.id}"]

associate_public_ip_address = true tags = {

Name = "web-production"

}

subnet_id = aws_subnet.web1.id provisioner "file" {

source = "/home/ubuntu/terraform/vpc_prod.pem"

destination = "/home/ubuntu/vpc_prod.pem"

}

}



resource "aws_instance" "web2" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic2.id}"] tags = {

Name = "web-development"

}

subnet_id = aws_subnet.web2.id

} resource "aws_instance" "DB1" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic1.id}"] tags = {

Name = "DB-production"

}

subnet_id = aws_subnet.DB1.id

} resource "aws_instance" "DB2" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic2.id}"] tags = {

Name = "DB-development"

}

subnet_id = aws_subnet.DB2.id

} resource "aws_instance" "app1" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic1.id}"] tags = {

Name = "app1-production"

}

subnet_id = aws_subnet.app1.id

} resource "aws_instance" "app2" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic1.id}"] tags = {

Name = "app2-production"

}

subnet_id = aws_subnet.app2.id

} resource "aws_instance" "DBCache" {

ami = "ami-0885b1f6bd170450c"

instance_type = "t2.micro"

key_name = "vpc_prod"

vpc_security_group_ids = ["${aws_security_group.all_traffic1.id}"] tags = {

Name = "DBCache"

}

subnet_id = aws_subnet.DBCache.id

}

At this stage all the Instances are properly Instantiated in their respective subnets :)

For VPC Full code visit my git repo:

https://github.com/gauravk29/full_vpc