Step By Step Guide On How To Set Up And Automate VPC Peering Using Terraform
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!