Step By Step Guide On How To Set Up And Automate VPC Peering Using Terraform

Emmanuel
7 min readMay 16, 2024

--

Introduction

AWS VPC peering allows networking connections between two VPCs, facilitating traffic routing through private IPv4 or IPv6 addresses.

VPC peering is a key feature in AWS’s suite of networking services, empowering architects and developers to design scalable, secure, and highly available cloud network architectures.

This article will guide you through creating a VPC peering connection using Terraform.

Prerequisites:

  • An Account with AWS. Click here to create an account.
  • Terraform is installed and configured on your local Machine. Go here to find the documentation on how to install Terraform.

Step 1: Creating Two VPCs.

  • Write a main.tf file and add the following code.
# Creating T2S VPC Dev
resource "aws_vpc" "t2s-vpc-dev" {
cidr_block = var.t2s-vpc-dev-cidr

tags = {
Name = "t2s-vpc-dev"
}
}

# Creating T2S VPC Stage
resource "aws_vpc" "t2s-vpc-stage" {
cidr_block = var.t2s-vpc-stage-cidr

tags = {
Name = "t2s-vpc-stage"
}
}

data "aws_availability_zones" "available_zones" {
state = "available"
}

The code above will create the following:

  • The first VPC we named was the T2S VPC Dev.
  • The second VPC we named was the T2S VPC Stage.

Step 2: Creating a Subnet in each VPC.

Add the following script to the main.tf file:

# Creating Subnet Dev in T2S VPC Dev
resource "aws_subnet" "subnet-dev" {
vpc_id = aws_vpc.t2s-vpc-dev.id
cidr_block = var.subnet-dev-cidr
availability_zone = data.aws_availability_zones.available_zones.names[0]

tags = {
Name = "Dev-Subnet"
}
}

# Creating Subnet Stage in T2S VPC Stage
resource "aws_subnet" "subnet-stage" {
vpc_id = aws_vpc.t2s-vpc-stage.id
cidr_block = var.subnet-stage-cidr
availability_zone = data.aws_availability_zones.available_zones.names[1]

tags = {
Name = "Stage-Subnet"
}
}

The code will create two Subnets:

  • Subnet Dev in T2S VPC Dev.
  • Subnet Stage in T2S VPC Stage.

Step 3: Creating and Configuring the VPC Peering Connection.

Add the following script to the main.tf file to create and configure the VPC Peering connection:

# Creating and Configuring the Peering connection.
resource "aws_vpc_peering_connection" "vpc_peering" {
vpc_id = aws_vpc.t2s-vpc-dev.id
peer_vpc_id = aws_vpc.t2s-vpc-stage.id
}

resource "aws_vpc_peering_connection_accepter" "vpc_peering_accepter" {
vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering.id
auto_accept = true
}

Your final main.tf file should look like this:

# Creating T2S VPC Dev
resource "aws_vpc" "t2s-vpc-dev" {
cidr_block = var.t2s-vpc-dev-cidr

tags = {
Name = "t2s-vpc-dev"
}
}

# Creating T2S VPC Stage
resource "aws_vpc" "t2s-vpc-stage" {
cidr_block = var.t2s-vpc-stage-cidr

tags = {
Name = "t2s-vpc-stage"
}
}

data "aws_availability_zones" "available_zones" {
state = "available"
}

# Creating Subnet Dev in T2S VPC Dev
resource "aws_subnet" "subnet-dev" {
vpc_id = aws_vpc.t2s-vpc-dev.id
cidr_block = var.subnet-dev-cidr
availability_zone = data.aws_availability_zones.available_zones.names[0]

tags = {
Name = "Dev-Subnet"
}
}

# Creating Subnet Stage in T2S VPC Stage
resource "aws_subnet" "subnet-stage" {
vpc_id = aws_vpc.t2s-vpc-stage.id
cidr_block = var.subnet-stage-cidr
availability_zone = data.aws_availability_zones.available_zones.names[1]

tags = {
Name = "Stage-Subnet"
}
}

# Creating and Configuring the Peering connection.
resource "aws_vpc_peering_connection" "vpc_peering" {
vpc_id = aws_vpc.t2s-vpc-dev.id
peer_vpc_id = aws_vpc.t2s-vpc-stage.id
}

resource "aws_vpc_peering_connection_accepter" "vpc_peering_accepter" {
vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering.id
auto_accept = true
}

Step 4: Creating an Internet Gateway.

Create a file, name it igw.tf, and add the following content:

# Creating internet gateway
resource "aws_internet_gateway" "t2s-igw" {
vpc_id = aws_vpc.t2s-vpc-dev.id
}

# Associate internet gateway with VPC Dev's Route Table
resource "aws_route" "route_to_internet" {
route_table_id = aws_route_table.route-table-dev.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.t2s-igw.id
}

The above code will create an Internet Gateway, exposing your resources over the Internet.

After creating the Internet Gateway, the script will associate it with the VPC Dev’s Route Table.

Step 5: Creating an S3 Bucket to Store Our Terraform State File (Remotely).

Create a file, name it provider.tf, and add the following content:

# configure aws provider
provider "aws" {
region = var.region
}

# configure backend
terraform {
backend "s3" {
bucket = "t2s-terraform"
key = "peering.terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock-dynamodb"
}
}

The code above will do the following:

  • The provider block will set up the AWS provider and specify the region from a variable, which will be a part of the variables.tf we will create next.
  • The Terraform block configures the backend to store the Terraform state file in an S3 bucket and lock the state in a DynamoDB table.

To use S3 buckets as a backend, you will need to create first a directory, and in this folder, add the following files and content:

The above illustration shows the main directory (or parent folder), where all the files you need for this project are located.

In the backend directory (child folder), create a file, name it backend.tf, and add this script:

# configure aws provider
provider "aws" {
region = var.region
}

resource "aws_s3_bucket" "terraform_state" {
bucket = "t2s-terraform" # Change this to a unique bucket name

# lifecycle {
# prevent_destroy = true
# }

tags = {
Name = "Terraform State Bucket"
Environment = "Production"
}
}

resource "aws_s3_bucket_versioning" "versioning" {
bucket = aws_s3_bucket.terraform_state.id

versioning_configuration {
status = "Enabled"
}
}

Then, create a variables.tf file and add this code:

# Inputting the Region Where To Deploy. 
variable "region" {
default = "us-east-1"
description = "The Region where to deploy"
}

Step 6: Creating the Route Tables.

Create a file, name it routing.tf, and add the following content:

# Creating Route tables
resource "aws_route_table" "route-table-dev" {
vpc_id = aws_vpc.t2s-vpc-dev.id
}

resource "aws_route_table" "route-table-stage" {
vpc_id = aws_vpc.t2s-vpc-stage.id
}

# Creating Routes in Route Tables for VPC Peering
resource "aws_route" "t2s-route-dev" {
route_table_id = aws_route_table.route-table-dev.id
destination_cidr_block = aws_vpc.t2s-vpc-stage.cidr_block
vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering.id
}

resource "aws_route" "t2s-route-stage" {
route_table_id = aws_route_table.route-table-stage.id
destination_cidr_block = aws_vpc.t2s-vpc-dev.cidr_block
vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering.id
}

The code above will create the following two Route Tables: one for the development VPC (t2s-vpc-dev) and the other for the stage VPC (t2s-vpc-stage).

The script will also configure the route in the development VPC route table that points to the stage VPC’s CIDR block via the VPC peering connection.

It will also configure the route in the stage VPC route table pointing to the development VPC’s CIDR block via the VPC peering connection.

Step 7: Inputting Variables.

Create a file, name it variables.tf, and add the following content:

# Inputting The CIDR of VPC Dev
variable "t2s-vpc-dev-cidr" {
type = string
description = "The CIDR of VPC Dev"
}

# Inputting The CIDR of VPC Stage
variable "t2s-vpc-stage-cidr" {
type = string
description = "The CIDR of VPC Stage"
}

# Inputting The CIDR of Subnet Dev
variable "subnet-dev-cidr" {
type = string
description = "The CIDR of Dev subnet"
}

# Inputting The CIDR of Subnet Stage
variable "subnet-stage-cidr" {
type = string
description = "The CIDR of Stage subnet"
}

# Inputting the Region Where We Deploy Our Infrastructure
variable "region" {
type = string
description = "Region"
}

Step 8: Your Secrets.

Create a file, and name it terraform.tfvars. This file contains information you don’t want to share.

But, for the sake of learning, I will show you how below you will input your secrets on this file. Keep in mind you do not have to share this with anyone.

region = "us-east-1"
t2s-vpc-dev-cidr = "20.0.0.0/16"
t2s-vpc-stage-cidr = "75.0.0.0/16"
subnet-dev-cidr = "20.0.15.0/24"
subnet-stage-cidr = "75.0.35.0/24"

Another way to input your secrets into Terraform is to use environment variables:

export region = "us-east-1"
export t2s-vpc-dev-cidr = "20.0.0.0/16"
export t2s-vpc-stage-cidr = "75.0.0.0/16"
export subnet-dev-cidr = "20.0.15.0/24"
export subnet-stage-cidr = "75.0.35.0/24"

Step 9: Initialize, Plan, and Apply

You use the following commands to initialize, plan, and apply.

terraform init
terraform plan
terraform apply

You should create an S3 Bucket before sending your Terraform State file to it. That’s the backend resource you will need to deploy.

Go into the backend directory (folder), and use the above terraform commands to initialize, plan, and apply to create the backend S3 bucket where we store the state file.

After doing so, move into the parent directory, where you will see all the files we’ve created and the backend directory.

Run the following commands:

terraform init
terraform plan
terraform apply

If you encounter error messages stating that the state file is locked or something similar, add the—lock=false flag.

Remember that the -lock=false flag should be used cautiously and only in specific scenarios where you can guarantee that no other operations are modifying the state simultaneously.

Your commands then should look like this:

terraform plan -lock=false
terraform apply -lock=false

If all is done the right way, you will see something like this:

Two VPCs were created: Dev and Stage.

Two Subnets were created: Dev and Stage.

One VPC Peering was created.

Conclusion

Congrats! You have deployed a VPC peering connection between two VPCs you've created using Terraform.

Now, you need to clean up so you don’t get charged. Use this command:

terraform destroy

Happy Learning, and God bless you!

--

--

Emmanuel
Emmanuel

Written by Emmanuel

Certified Cloud Solutions Architect passionate about Cloud & DevOps, Technology Evangelism, Pastoral Ministry, Educator and Mentor, and World Travel.

No responses yet