DEV Community

Cover image for Using Terraform to Create AWS VPC Peering
Adeoluwa Adeyemo
Adeoluwa Adeyemo

Posted on

Using Terraform to Create AWS VPC Peering

Hi, Welcome to the first in the VPC Peering Series.
In this edition, you will learn how to create and peer VPCs together that are in the same region. This shows how to create VPC peering on AWS using terraform.

What is AWS VPC Peering?

Amazon Web Services (AWS) Virtual Private Cloud (VPC) peering is a networking feature that allows you to connect two VPCs together, enabling communication between them as if they were on the same network. VPC peering is a private and secure connection, which means traffic between the peered VPCs stays within the AWS network and does not traverse the public internet.

VPC Diagram

  • Requester VPC - This is the VPC from which we are initiating a request to establish a peering connection with another VPC.

  • Accepter VPC - This refers to the VPC that will receive and accept the peering request from the requester VPC.


Terraform Script

Terraform is an infrastructure as code (IaC) tool used to define and provision the creation of infrastructure resources.

  • Provider.tf - This shows the specific provider used for this script and in this case we are using AWS.
provider "aws" {
  access_key = var.access_key
  secret_key = var.secret_key
  region     = var.region
}

terraform {
  required_version = ">= 1.0.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Vpc.tf - This shows the creation of the respective vpcs (Requester Vpc and Accepter Vpc) and the Vpc peering connection.
# Create VPC for Requester
resource "aws_vpc" "requester_vpc" {
  cidr_block = var.vpc_cidr_block
  #  enable_dns_hostnames = true
  tags = {
    Name = "requester_vpc"
  }
}

# Create VPC for Accepter
resource "aws_vpc" "accepter_vpc" {
  cidr_block = var.peer_vpc_cidr_block
  #  enable_dns_hostnames = true
  tags = {
    Name = "accepter_vpc"
  }
}

# Create VPC peering connection between both vpcs
resource "aws_vpc_peering_connection" "vpc_peering_connection" {
  vpc_id      = aws_vpc.requester_vpc.id
  peer_vpc_id = aws_vpc.accepter_vpc.id
  auto_accept = true

  tags = {
    Name = "peering_connection"
  }

  depends_on = [
    aws_vpc.requester_vpc,
    aws_vpc.accepter_vpc
  ]
}

# Create Internet Gateway for Requester
resource "aws_internet_gateway" "requester-igw" {
  vpc_id = aws_vpc.requester_vpc.id
  tags = {
    Name = "requester-igw"
  }
}

# Create Route Table for Requester
resource "aws_route_table" "route_table_requester" {
  vpc_id = aws_vpc.requester_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.requester-igw.id
  }

  route {
    cidr_block                = "10.1.5.0/24"
    vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_connection.id
  }
}

# Create Route Table for Accepter
resource "aws_route_table" "route_table_accepter" {
  vpc_id = aws_vpc.accepter_vpc.id


  route {
    cidr_block                = "10.0.5.0/24"
    vpc_peering_connection_id = aws_vpc_peering_connection.vpc_peering_connection.id
  }
}

# Data for availability Zones
data "aws_availability_zones" "availability_zones" {}

# Create Subnet for Requester
resource "aws_subnet" "subnet_requester" {
  vpc_id                  = aws_vpc.requester_vpc.id
  cidr_block              = var.requester_subnet_cidr_block
  map_public_ip_on_launch = true # This makes public subnet
  availability_zone       = data.aws_availability_zones.availability_zones.names[0]
  tags = {
    Name = "requester-subnet"
  }
}

# Create Subnet for Accepter
resource "aws_subnet" "subnet_accepter" {
  vpc_id                  = aws_vpc.accepter_vpc.id
  cidr_block              = var.accepter_subnet_cidr_block
  map_public_ip_on_launch = false # This makes private subnet
  availability_zone       = data.aws_availability_zones.availability_zones.names[1]
  tags = {
    Name = "accepter-subnet"
  }
}

# Associate Requester Subnet to Requester Route Table
resource "aws_route_table_association" "route_table_requester" {
  subnet_id      = aws_subnet.subnet_requester.id
  route_table_id = aws_route_table.route_table_requester.id
}

# Associate Accepter Subnet to Accepter Route Table
resource "aws_route_table_association" "route_table_accepter" {
  subnet_id      = aws_subnet.subnet_accepter.id
  route_table_id = aws_route_table.route_table_accepter.id
}
Enter fullscreen mode Exit fullscreen mode
  • Variables.tf - This shows the variables declared.
variable "access_key" {
  description = "The Access Key"
  default     = [{}]
}

variable "secret_key" {
  description = "The Secret Key"
  default     = [{}]
}

variable "region" {
  type    = string
  default = "eu-west-1"
}

variable "vpc_cidr_block" {
  description = "VPC Cidr Block"
  default     = "10.0.0.0/16"
}

variable "peer_vpc_cidr_block" {
  description = "Peer VPC Cidr Block"
  default     = "10.1.0.0/16"
}

variable "requester_subnet_cidr_block" {
  description = "Requester Subnet Cidr Block"
  default     = "10.0.5.0/24"
}

variable "accepter_subnet_cidr_block" {
  description = "Accepter Subnet Cidr Block"
  default     = "10.1.5.0/24"
}

variable "instance_type" {
  type    = string
  default = "t2.micro"
}

variable "ami_id" {
  type    = string
  default = "ami-0136ddddd07f0584f"
}

variable "ami_key_pair_name" {
  type    = string
  default = "peering" #key pair has been created in this case
}
Enter fullscreen mode Exit fullscreen mode
  • Security.tf - This shows how any EC2 instance created in the different vpcs communicate with each other. Security groups for both Requester Vpc and Accepter Vpc are created. Here we are testing the vpc peering created above.
# Create Security Group for EC2 Instance for Requester
resource "aws_security_group" "requester_security_group" {
  name        = "requester_security_group"
  description = "requester security group"
  vpc_id      = aws_vpc.requester_vpc.id

  # Allow inbound traffic from Accepter CIDR block
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.accepter_vpc.cidr_block]
  }

  # Allow inbound traffic from Accepter CIDR block
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "udp"
    cidr_blocks = [aws_vpc.accepter_vpc.cidr_block]
  }

  # Allow inbound ICMP traffic from Accepter CIDR block
  ingress {
    from_port   = -1
    to_port     = -1
    protocol    = "icmp"
    cidr_blocks = [aws_vpc.accepter_vpc.cidr_block]
  }

  # Allow SSH for EC2 Connect or SSH from a terminal
  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }


  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]

  }
  tags = {
    Name = "requester_security_group"
  }
}

# Create Security Group for EC2 Instance for Accepter
resource "aws_security_group" "accepter_security_group" {
  name        = "accepter_security_group"
  description = "accepter security group"
  vpc_id      = aws_vpc.accepter_vpc.id

  # Allow inbound traffic from Requester CIDR block
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.requester_vpc.cidr_block]
  }

  # Allow inbound traffic from Requester CIDR block
  ingress {
    from_port   = 0
    to_port     = 65535
    protocol    = "udp"
    cidr_blocks = [aws_vpc.requester_vpc.cidr_block]
  }

  # Allow inbound ICMP traffic from Requester CIDR block
  ingress {
    from_port   = -1
    to_port     = -1
    protocol    = "icmp"
    cidr_blocks = [aws_vpc.requester_vpc.cidr_block]
  }

  # Allow SSH from Requester EC2 Instance
  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.requester_vpc.cidr_block]
  }


  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]

  }
  tags = {
    Name = "accepter_security_group"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • Ec2.tf - This shows the EC2 instances created to test the vpc peering connection associated with the different vpcs created. Ec2 instances for both Requester Vpc and Accepter Vpc are created. Here we are testing the vpc peering created above. Note: Requester-server has both public and private ip and Accepter-server has a private ip only.
resource "aws_instance" "requester_server" {
  ami             = var.ami_id
  instance_type   = var.instance_type
  key_name        = var.ami_key_pair_name # This is an existing key pair that has already been created
  security_groups = [aws_security_group.requester_security_group.id]
  subnet_id       = aws_subnet.subnet_requester.id
  monitoring      = false

  tags = {
    Name = "requester_server"
  }
}

resource "aws_instance" "accepter_server" {
  ami             = var.ami_id
  instance_type   = var.instance_type
  key_name        = var.ami_key_pair_name # This is an existing key pair that has already been created
  security_groups = [aws_security_group.accepter_security_group.id]
  subnet_id       = aws_subnet.subnet_accepter.id
  monitoring      = false

  tags = {
    Name = "accepter_server"
  }
}
Enter fullscreen mode Exit fullscreen mode

Testing

This shows the outcome of the terraform script and also shows the communication between the vpcs.

  • terraform apply
    After Terraform Apply has been applied

  • Vpc Peering Connection
    Vpc Peering Connection

  • VPCs
    VPCs

  • Security Groups
    Security Groups

  • EC2 Instances
    Ec2 Instances

  • Requester-server Communicating with Accepter-server
    Pinging the private ip of the Accepter instance.
    Requester-server pings Accepter-server ip

  • ssh into Accepter-server from Requester-server
    ssh into Accepter-server from Requester-server

  • Accepter-server Communicating with Requester-server
    Pinging the private ip of the Requester instance.
    Accepter-server pings Requester-server ip


Conclusion

VPC peering is useful for scenarios where you want to share resources, services, or data securely between separate VPCs, such as connecting development and production environments, sharing databases, or integrating different applications within your AWS infrastructure. It provides a convenient way to build complex multi-tier architectures in a scalable and isolated manner. As shown above, its shows the connection between 2 ec2 instances on different VPCs connecting with each other via the VPC Peering.

Top comments (0)