Project by: Dickson Ankamah

Last updated: 15th October, 2025

Secure Multi-VPC Cloud Architecture with VPC Peering

Building a Secure Jump-Point to Connect Development to Production.

This project was developed within a lab environment that automatically terminates all resources when lab timer lapses. To ensure continuity, I created an Infrastructure as Code (IaC) solution using CloudFormation. This allowed me to quickly redeploy the entire stack when the lab is restarted and pick up from where I left off without any manual reconfiguration.

Introduction: Initial Setup & Prerequisites

This project establishes two separate VPC environments (PROD and DEV) and then connects them securely using VPC Peering.

Below is the architecture of the project, we would build it step by step throughout this document

Topology Diagram
Topology Diagram

Prerequisites

  • • AWS Account with appropriate IAM users and permissions
  • • Familiarity with AWS Management Console
  • • A Command Line Interface (CLI) tool
  • I will be using a WSL terminal

  • • Familiarity with basic Linux Commands
  • • Familiarity with AWS CloudFormation (optional but recommended)

Step 1: Creating VPC and Subnets

We will first create two isoloated networks for the environments using a VPCTwo public and one private

• From the Management Console got to the VPC Dashboard.
Create VPC.
• "VPC only" and provide a name ("prod-vpc" for production environment).
I will be using this naming format for the entire project for simplicity, you can use any format that works for you• Set an IPv4 CIDR block of 10.0.0.0/16
• Review and Create VPC

PROD VPC CREATE

• Create another VPC
Create VPC.
• "VPC only" and provide a name ("dev-vpc" for development environment).
• Set an IPv4 CIDR block of 192.168.0.0/16
so that the prod and dev CIDRs do not overlap

DEV VPC CREATE

Now to create subnets, two for PROD and one for DEV,
Expand the VPC Dashboard sidebar and go to Subnets

Create Subnet
Choose the production VPC ("prod-vpc").
We will create a Public Subnet first
• So name it "prod-public-subnet"
• Set the Availability Zone to your preference (e.g., us-west-2a) and note it somewhere
becasue the second subnet must be in a different AZ• Set the IPv4 subnet CIDR block to 10.0.1.0/28
• Review and Create Subnet

production public create screenshot

We will follow similar procedure to create the private subnet also prod-vpc
• Name: prod-private-subnet
• Different AZ from prod-public-subnet
• CIDR: 10.0.2.0/28

Production private subnet create

And then create the DEV public subnet
• Must be in the dev-vpc
• Name: dev-public-subnet
• Same AZ as prod-public-subnet
• CIDR: 192.168.1.0/24

Subnet create screenshot

Cloudformation Code for Step 1 - (VPC and Subnets)

The part of the Cloudformation code that creates vpc and subnets as we discussed above

AWSTemplateFormatVersion: "2010-09-09"
                    
Description: >-
  This template creates a VPC Peering connection for 2 disparate networks
Parameters:
  VPCName:
    Description: The name of the VPC being created.
    Type: String
    Default: my-vpc
  
  AL2023AMI:
    Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64

Mappings:
  SubnetConfig:
    VPC:
      CIDR: 10.0.0.0/16
    Public1:
      CIDR: 10.0.1.0/28
    Public2:
      CIDR: 10.0.2.0/28
    Private:
      CIDR: 10.0.3.0/28
  
Resources:

                    

Step 2: Routing

While still in the VPC Dashboard we'll create and configure three route tables.
The purpose of routing is to control the traffic flow between the subnets, or between the subnets and the internet

What we'll create:
• A Route Table for the Public Subnet in Production with routes to an Internet Gateway to enable internet access.
• Another Route Table for the Public Subnet in Development with routes to it's own Internet Gateway to enable internet access.
• A Route Table for the Private Subnet with a route to the VPC Peering connection

That means the route tables have dependencies on Internet Gateways so let's create them first before we move on
Choose "Internet gateways" from the sidebar and click on Create Internet Gateway.
• Name it "prod-igw"
andCreate internet gateway.

Select Attach to VPC from the green pop-up and select the VPC ("prod-vpc").

Internet gateway attach

Create the second Internet Gateway call it "dev-igw" and attach it to "dev-vpc"

Now that we have both Internet Gateways created, we can create the route tables
Open "Route Tables" from the side menu
• Create Route Table.
• We'll name it "prod-public-rtb" and associate it with the prod-vpc.
Create route table

 production public route table create

You'll be redirected to the dashboard of the just created route table
There, select the "Routes" tab. Click on Edit routes and then Add route.
• Set the destination to 0.0.0.0/0 and the target to the production Internet Gateway("prod-igw")
Save changes

 prod public route table route

We need to associate this route table with the public subnet so that it's reachable from the internet.
• Select the "Subnet associations" tab and Edit subnet associations.
• Select the public subnet ("prod-public-subnet)
Save associations

prod public route table association

We repeat the process to create route tables for the prod private subnet and dev public subnet
Prod Private Route Table:
• Name: "prod-private-rtb" and associate it with the prod-vpc as well
• Don't set any routes yet as this subnet is private and can only relate with other subnets internally
we'll come back to add a route to the VPC Peering Connection later• In the "Subnet associations" tab, associate the prod private subnet ("prod-private-subnet) with this route table.

Dev Public Route Table:
• Name: "dev-public-rtb" and associate it with the dev-vpc.
• Set a route with destination 0.0.0.0/0 and target to the development Internet Gateway("dev-igw")

• In the "Subnet associations" tab, associate the dev public subnet ("dev-public-subnet) with this route table.

Key Points / Best Practices

- Private subnets should not have a direct route to the Internet Gateway, they only interact with the internet for their needs through the NAT Gateway
- Ensure that the route tables are correctly associated with their respective subnets
- Double-check the CIDR blocks to avoid overlaps and ensure proper segmentation

Cloudformation Code for Step 2 - (Routing)

The part of the Cloudformation code that creates the IGWs and Route Tables as discussed above
Uploading only this part to Cloudformation will fail to create unless the VPC and Subnets from Step 1 are already created
Append this code to the code from Step 1 to make it work, and ensure the indentations are correct

# Resources: ...

# VPC and Subnets section  
#    ....


# Routing section


      
              

Step 3: VPC Peering

In this section we are going to a create a peering connection between the two VPCs we created in Step 1

Go to Peering connections in the VPC side menu
• Click on Create peering connection
• Assign it a name, "peer-con-interface"
• We'll make the prod-vpc make the peering request to dev-vpc
required in VPC peering to establish the connection• Review andCreate peering connection

vpc peering requester
vpc peering accepter

You'll see a alert at the top of the page asking to accept the connection request
you need to accept the connection request made by prod-vpc to dev-vpc since they're both managed in the same account
-Go to "Actions" and accept the request

accept peering request

Now we can go and modify "prod-private-rtb"
-You can select "Modify route tables now" from the green popup or go to the Route tables from the sidebar
Set a new route to the dev-public-subnet CIDR 192.168.1.0/24 and target the Peering Connection
- Update "dev-public-rtb" with a route to the prod-private-subnet CIDR10.0.2.0/28 and target the Peering Connection
now both subnets know the route to communicate with each other is through the Peering Connection

Route table update
route table update

Cloudformation Code for Step 3 - (VPC Peering)

The part of the Cloudformation code that creates the Load Balancer dicussed above
Uploading only this part to Cloudformation will fail to create unless the VPC and Subnets from Step 1 are already created
Append this code to the code from Step 1 and step 2 to make it work, and ensure the indentations are correct

# Resources: ...

# VPC and Subnets section  
#    ....
# Routing section
#    ....
# VPC Peering
  
              

Step 4: Security Groups

In this step we will set up Security Groups to control access to the Instances we will create in the next step
We will create a Secuity Group for an Elastic Network Interface (ENI)
Security Groups act as virtual firewalls that regulate inbound and outbound traffic. We will create rules to allow only necessary traffic, ensuring a robust architecture.

What we'll create:
• A Security Groups for the Bastion Hosts in both VPCs to allow ssh connection from anywhere.
• A Security Group for the ENI to allow ssh from the bastion in dev-vpc
possible, thanks to VPC Peering!

We'll start with the Bastion Security Groups
• Go to Security Groups in the VPC Dashboard.
Create Security Group.
• We'll name it "ProdBastionSG"
• Add a description
• Select VPC (prod-vpc)
For Inbound rules:
• Add a rule for SSH access from anywhere

Prod Bastion SG screenshot

• Create another one with name "DevBastionSG"
• Add a description
• Select VPC (dev-vpc)
• Set ssh inbound rule from anywhere

Dev Bastion SG screenshot

• We also need a security group for the private instance
a secondary network interface (ENI) will be governed by the ENI security group
- We'll create the ENI and attach it to the private instance in the next step
• Let's name it "PrivateInstanceSG"
• Add a description
• Select VPC (prod-vpc)
• Set ssh inbound rule from "ProdBastionSG" (search "sg" from the dropdown and choose ProdBationSG )

Instance SG screenshot

For ENI Security Group.
• We'll name it "ENISG"
• Will be in the prod-vpc
• Add inbound rule:
SSH - Source: Custom 192.168.1.0/24 from dev bastion's subnet

 ENI security group

Key Points / Best Practices

- The instances security should allow traffic from only the load balancer security group
- Ensure to use descriptive names and comments for rules to make management easier

Cloudformation Code for Step 4 - (Security Groups)

The part of the Cloudformation code that creates the Security Groups as dicussed above
Uploading only this part to Cloudformation will fail to create unless the VPC and Subnets from Step 1 are already created
Append this code to the code from Step 1 and 2 to make it work, and ensure the indentations are correct

# Resources: ...

# VPC and Subnets section  
#    ....
# Routing section
#    ....
# VPC Peering
#    ....
# Security groups

  ENISecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH from dev bastion
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 192.168.1.0/24
      Tags:
        - Key: Name
          Value: ENISG

  DevBastionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access from anywhere
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: DevBastionSG

  ProdBastionSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access from anywhere
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: ProdBastionSG

  PrivateInstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access from prod bastion security group
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          SourceSecurityGroupId: !Ref ProdBastionSecurityGroup
      Tags:
        - Key: Name
          Value: PrivateInstanceSG

              

Step 5: ENI & EC2 Instances

In this step, we will launch three EC2 instances and attach a Network Interface to one of them, and configure them with their appropriate security groups created in the previous step

• Search for "EC2" in the Search bar and open the EC2 Dashboard.
• Go to "Network Interfaces".
• Create a new network interface
• Add a description
• Select prod-private-subnet, so that it will be assigned a private ip form this subnet
• Check the "ENISG" security group andCreate network interface

ENI creation
ENI creation

Now create the private instance first: • Go "Instances" and create a new instance.
• We'll name it "PrivateInstance".
• Leave the next sections as default go to Key Pair
• Select a key pair for SSH access. If you don't have one, create a new key pair and download the ".pem" file
will be required to connect to the instances later when we test ssh access.

Edit Network Settings:
- Select the VPC (prod-vpc)
- Select the the subnet (prod-private-subnet)
- Disable Auto-assign Public IP
the instance is private and doesn't require a public IP.- Under Security Group, "Select an existing security group" and choose the "PrivateInstanceSG" security

EC2 Network Settings

• Leave everything else untouched and review
Launch instance when done.

Lauch two more instance for bastion hosts:

For "ProdBastion Server":
In the network settings select "prod-vpc" and the "prod-public-subnet"
Enable auto-assign IP
- And then select the ProdBastionSG security group

For "DevBastion Server":
In the network settings select "dev-vpc" and the "dev-public-subnet"
Enable auto-assign IP
- And then select the DevBastionSG security group

One last thing to seal it all,
Go to Network Interfaces select the ENI we created
Select "Attach" from "Actions"
Choose the "prod-vpc"
And then choose the instance to attach the interface,i.e "Private Instance"
Check if everything is correct and hitAttach

EC2 Network Settings

Cloudformation Code for Step 5 - (ENI & EC2 Instances)

The part of the Cloudformation code that creates the EC2 Instances as dicussed above
Uploading only this part to Cloudformation will fail to create unless you combine with the codes from the previous steps, and ensure the indentations are correct

# Resources: ...
      
# VPC and Subnets section  
#    ....
# Routing section
#    ....
# VPC Peering
#    ....
# Security groups
#    ....

# ENI & EC2 Instances

  
                    

Step 6: Testing

In this final step, we will test the entire setup to ensure that all components are functioning correctly. We will verify that the Bastion in the development environment can ssh into the private instance in the production environment

Make sure your key pair file has the right permissions set.

Run this command to do so:

chmod 400 YOUR-KEY-PAIR.pem

Upload your Key Pair .pem file to the dev bastion so you can use it to ssh into the prod private instance
Run the command below to do that(make sure the key pair file is in the current working directory):

scp -i YOUR-KEY-PAIR.pem YOUR-KEY-PAIR.pem ec2-user@DEV-BASTION-PUBLIC-IP:~/Note that the repetition of "YOUR-KEY-PAIR.pem" isn't a mistake

Let's try to ssh into the private instance from the dev bastion
ssh -i YOUR-KEY-PAIR.pem ec2-user@ENI-PRIVATE-IP

We have confirmed the whole setup is working as expected!

You can run further tests on your own to verify if the security groups are working as intended

Congratulations!

That's all about it, we've been able to successfully complete the design
Topology Diagram

Thank You

Thank you for following this project on establishing a connection between two VPCs, using VPC Peering. I hope you found it informative and helpful. If you have any questions or need further assistance, feel free to reach out!

Get In Touch

Have questions about this project or want to collaborate? I'd love to hear from you!

Dickson Ankamah

Dickson Ankamah

Cloud Practitioner

I'm always open to discussing new opportunities, interesting projects, or just having a chat about technology. Feel free to reach out through any of the channels above!