Building a Secure VPC Architecture with AWS CloudFormation: A Step-by-Step Guide
Introduction to Virtual Private Cloud (VPC): AWS Virtual Private Cloud (VPC) is a secure section of the AWS Cloud where you can manage your network and host virtual computers, databases, and applications. You have complete control over the addresses, secure zones, and access permissions. VPC is highly adaptable and easy to expand across different cloud regions. It's a secure and flexible way to manage cloud control.
We will guide you through setting up a basic VPC architecture with AWS CloudFormation templates. This includes creating VPCs, subnets, security groups, and routing tables.
Before creating your VPC with CloudFormation, ensure a clear understanding of requirements. Consider:
IP Address Range: Decide on the IP address range for your VPC. This is usually done in CIDR notation (e.g., 10.0.0.0/16).
Availability Zones (AZs): Determine how many availability zones you need for high availability. AWS recommends a minimum of two.
Subnet Design: Design public and private subnets for internet access and resources. Private subnets are used for resources that should be isolated from the Internet.
Security Groups: When setting up your VPC, it's crucial to consider routing and select a strategy that allows for internet access.
Routing: To enable internet access and establish VPN connections.
Internet Gateway: An Internet Gateway (IGW) allows resources in public subnets to communicate with the Internet while blocking direct access from the Internet to resources in private subnets.
NAT Gateways/Instances: Network Address Translation (NAT) gateways or instances in public subnets enable resources in private subnets to initiate outbound traffic to the internet while remaining hidden from incoming connections.
Use Case: Secure Access to Private Resources within the VPC
Our aim is to create a thorough arrangement of subnets that includes both public and private ones. Our main focus is to maintain the security and segregation of the VPC's private subnet from any external interference, while also allowing authorized users to access the gateway in a regulated way. To achieve this, we have included a public jump machine within the VPC, which serves as a secure entry point to the private resources. This ensures that the use case is carried out securely and dependably.
Private Resources: Our use case involves shielding our servers from direct internet access to enhance security. Additionally, we have deployed a public-facing virtual machine (EC2 instance) within the VPC.
Public Jump Machine: We've deployed a public-facing virtual machine (EC2 instance) within the VPC, residing in a public subnet. This jump machine is a gateway for authorized users to access private resources securely.
Controlled Access: To access private resources securely, it's essential to control access through security group rules and either SSH key pairs or login credentials. A public jump machine can act as a bastion host or "jump box," allowing authorized users to access private resources after connecting to the jump machine.
Jump Machine as a Bastion Host: The public jump machine acts as a bastion host or a "jump box." Once connected to the jump machine, authorized users can initiate additional secure connections to private resources within the VPC.
Before we create a VPC architecture, let's review important CloudFormation concepts.
1. AWSTemplateFormatVersion
:
AWSTemplateFormatVersion: "2010-09-09"
This line specifies the version of the CloudFormation template being used, with the value corresponding to the release in September 2010.
2. Description
:
The purpose of the field is to offer a concise and understandable explanation of the function of the CloudFormation template
.
Description: Create a VPC with two public and two private subnets in ap-south-1
3. Parameters
:
In this section, users can customize the template's behavior when creating a stack by defining input parameters. These parameters can be considered as configurations. One of these parameters is "CIDR block(IP Range)", which allows the user to specify the VPC's block. The default value is currently set to [10.0.0.0/16].
VpcName
: Allows the user to set a name for the VPC. In our case my VPC name is "MyVPC"
.
PublicSubnetCidr1
and PublicSubnetCidr2
: These parameters let the user define the CIDR blocks for the two public subnets.
PrivateSubnetCidr1
and PrivateSubnetCidr2
: Similar to the public subnets, these parameters let the user define the CIDR blocks for the two private subnets, with default values. (You can change parameters according to you.)
PublicRouteTableName
and PrivateRouteTableName
: These parameters allow the naming of route tables for the public and private subnets.
InternetGatewayName
: Enables naming of the Internet Gateway.
NatGatewayName
: Enables naming of the NAT Gateway. duration options for the template.
4. Resources
:
The section where the bulk of the infrastructure definition occurs is where AWS resources are created and configured during CloudFormation stack deployment.
A VPC
An Internet Gateway
Attachment of the Internet Gateway to the VPC
Public and private subnets
Route tables for public and private subnets
Elastic IP for NAT Gateway
NAT Gateway
Routes to public and private subnets
5. Outputs
:
This section specifies the values that can be accessed once the CloudFormation stack is generated. These outputs can serve multiple purposes, like referring to resource identifiers or displaying details about the generated resources. Your template contains outputs for:
VPC ID
Internet Gateway ID
IDs for public and private subnets
IDs of public and private route tables
Elastic IP ID
NAT Gateway ID
Creating VPC Resources Using Cloudformationirtual
Step 1:- Create VPC(Virtual Private Cloud).
In this step, we create vpc (Virtual Private Cloud) using cloud formation.
AWSTemplateFormatVersion: "2010-09-09"
Description: Create a VPC with two public and two private subnets in ap-south-1
Parameters:
VpcCidrBlock:
Description: CIDR block for the VPC
Type: String
Default: "10.0.0.0/16"
VpcName:
Description: Name for the VPC
Type: String
Default: "MyVPC"
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrBlock
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref VpcName
Outputs:
VPCId:
Description: VPC ID
Value:
Ref: VPC
Step 2:- Create IGW(Internet Gateway).
AWSTemplateFormatVersion: "2010-09-09"
Description: Create a VPC with two public and two private subnets in ap-south-1
Parameters:
VpcCidrBlock:
Description: CIDR block for the VPC
Type: String
Default: "10.0.0.0/16"
VpcName:
Description: Name for the VPC
Type: String
Default: "MyVPC"
InternetGatewayName:
Description: Name for the Internet Gateway
Type: String
Default: "MyInternetGateway"
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrBlock
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref VpcName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref InternetGatewayName
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
Outputs:
VPCId:
Description: VPC ID
Value:
Ref: VPC
InternetGatewayId:
Description: Internet Gateway ID
Value:
Ref: InternetGateway
Step 3:- Create Public and Private Subnetes.
Parameters:
VpcCidrBlock:
Description: CIDR block for the VPC
Type: String
Default: "10.0.0.0/16"
VpcName:
Description: Name for the VPC
Type: String
Default: "MyVPC"
InternetGatewayName:
Description: Name for the Internet Gateway
Type: String
Default: "MyInternetGateway"
PublicSubnetCidr1:
Description: CIDR block for the first public subnet
Type: String
Default: "10.0.1.0/24"
PublicSubnetCidr2:
Description: CIDR block for the second public subnet
Type: String
Default: "10.0.2.0/24"
PrivateSubnetCidr1:
Description: CIDR block for the first private subnet
Type: String
Default: "10.0.3.0/24"
PrivateSubnetCidr2:
Description: CIDR block for the second private subnet
Type: String
Default: "10.0.4.0/24"
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrBlock
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref VpcName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref InternetGatewayName
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCidr1
AvailabilityZone: ap-south-1a
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${VpcName}-PublicSubnet1"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCidr2
AvailabilityZone: ap-south-1b
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${VpcName}-PublicSubnet2"
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidr1
AvailabilityZone: ap-south-1a
Tags:
- Key: Name
Value: !Sub "${VpcName}-PrivateSubnet1"
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidr2
AvailabilityZone: ap-south-1b
Tags:
- Key: Name
Value: !Sub "${VpcName}-PrivateSubnet2"
Outputs:
VPCId:
Description: VPC ID
Value:
Ref: VPC
InternetGatewayId:
Description: Internet Gateway ID
Value:
Ref: InternetGateway
PublicSubnet1Id:
Description: Public Subnet 1 ID
Value:
Ref: PublicSubnet1
PublicSubnet2Id:
Description: Public Subnet 2 ID
Value:
Ref: PublicSubnet2
PrivateSubnet1Id:
Description: Private Subnet 1 ID
Value:
Ref: PrivateSubnet1
PrivateSubnet2Id:
Description: Private Subnet 2 ID
Value:
Ref: PrivateSubnet2
step 4: Create a Public and Private Routes Table.
AWSTemplateFormatVersion: "2010-09-09"
Description: Create a VPC with two public and two private subnets in ap-south-1
Parameters:
VpcCidrBlock:
Description: CIDR block for the VPC
Type: String
Default: "10.0.0.0/16"
VpcName:
Description: Name for the VPC
Type: String
Default: "MyVPC"
InternetGatewayName:
Description: Name for the Internet Gateway
Type: String
Default: "MyInternetGateway"
PublicSubnetCidr1:
Description: CIDR block for the first public subnet
Type: String
Default: "10.0.1.0/24"
PublicSubnetCidr2:
Description: CIDR block for the second public subnet
Type: String
Default: "10.0.2.0/24"
PrivateSubnetCidr1:
Description: CIDR block for the first private subnet
Type: String
Default: "10.0.3.0/24"
PrivateSubnetCidr2:
Description: CIDR block for the second private subnet
Type: String
Default: "10.0.4.0/24"
PublicRouteTableName:
Description: Name for the public route table
Type: String
Default: "PublicRouteTable"
PrivateRouteTableName:
Description: Name for the private route table
Type: String
Default: "PrivateRouteTable"
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrBlock
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref VpcName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref InternetGatewayName
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCidr1
AvailabilityZone: ap-south-1a
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${VpcName}-PublicSubnet1"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCidr2
AvailabilityZone: ap-south-1b
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${VpcName}-PublicSubnet2"
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidr1
AvailabilityZone: ap-south-1a
Tags:
- Key: Name
Value: !Sub "${VpcName}-PrivateSubnet1"
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidr2
AvailabilityZone: ap-south-1b
Tags:
- Key: Name
Value: !Sub "${VpcName}-PrivateSubnet2"
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref PublicRouteTableName
PublicDefaultRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref PrivateRouteTableName
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateRouteTable
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet2
RouteTableId: !Ref PrivateRouteTable
Outputs:
VPCId:
Description: VPC ID
Value:
Ref: VPC
InternetGatewayId:
Description: Internet Gateway ID
Value:
Ref: InternetGateway
PublicSubnet1Id:
Description: Public Subnet 1 ID
Value:
Ref: PublicSubnet1
PublicSubnet2Id:
Description: Public Subnet 2 ID
Value:
Ref: PublicSubnet2
PrivateSubnet1Id:
Description: Private Subnet 1 ID
Value:
Ref: PrivateSubnet1
PrivateSubnet2Id:
Description: Private Subnet 2 ID
Value:
Ref: PrivateSubnet2
PublicRouteTableId:
Description: Public Route Table ID
Value:
Ref: PublicRouteTable
PrivateRouteTableId:
Description: Private Route Table ID
Value:
Ref: PrivateRouteTable
Step 5:- Create Nat Gateway and associate with EIP.
AWSTemplateFormatVersion: "2010-09-09"
Description: Create a VPC with two public and two private subnets in ap-south-1
Parameters:
VpcCidrBlock:
Description: CIDR block for the VPC
Type: String
Default: "10.0.0.0/16"
VpcName:
Description: Name for the VPC
Type: String
Default: "MyVPC"
InternetGatewayName:
Description: Name for the Internet Gateway
Type: String
Default: "MyInternetGateway"
PublicSubnetCidr1:
Description: CIDR block for the first public subnet
Type: String
Default: "10.0.1.0/24"
PublicSubnetCidr2:
Description: CIDR block for the second public subnet
Type: String
Default: "10.0.2.0/24"
PrivateSubnetCidr1:
Description: CIDR block for the first private subnet
Type: String
Default: "10.0.3.0/24"
PrivateSubnetCidr2:
Description: CIDR block for the second private subnet
Type: String
Default: "10.0.4.0/24"
PublicRouteTableName:
Description: Name for the public route table
Type: String
Default: "PublicRouteTable"
PrivateRouteTableName:
Description: Name for the private route table
Type: String
Default: "PrivateRouteTable"
NatGatewayName:
Description: Name for the NAT Gateway
Type: String
Default: "MyNATGateway"
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref VpcCidrBlock
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Ref VpcName
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Ref InternetGatewayName
AttachGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCidr1
AvailabilityZone: ap-south-1a
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${VpcName}-PublicSubnet1"
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PublicSubnetCidr2
AvailabilityZone: ap-south-1b
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub "${VpcName}-PublicSubnet2"
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidr1
AvailabilityZone: ap-south-1a
Tags:
- Key: Name
Value: !Sub "${VpcName}-PrivateSubnet1"
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
CidrBlock: !Ref PrivateSubnetCidr2
AvailabilityZone: ap-south-1b
Tags:
- Key: Name
Value: !Sub "${VpcName}-PrivateSubnet2"
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref PublicRouteTableName
PublicDefaultRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
PrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Ref PrivateRouteTableName
PrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1
RouteTableId: !Ref PrivateRouteTable
PrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet2
RouteTableId: !Ref PrivateRouteTable
ElasticIP:
Type: AWS::EC2::EIP
NatGateway:
Type: AWS::EC2::NatGateway
Properties:
AllocationId: !GetAtt ElasticIP.AllocationId
SubnetId: !Ref PublicSubnet1
PrivateDefaultRoute:
Type: AWS::EC2::Route
DependsOn: NatGateway
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NatGateway
Outputs:
VPCId:
Description: VPC ID
Value:
Ref: VPC
InternetGatewayId:
Description: Internet Gateway ID
Value:
Ref: InternetGateway
PublicSubnet1Id:
Description: Public Subnet 1 ID
Value:
Ref: PublicSubnet1
PublicSubnet2Id:
Description: Public Subnet 2 ID
Value:
Ref: PublicSubnet2
PrivateSubnet1Id:
Description: Private Subnet 1 ID
Value:
Ref: PrivateSubnet1
PrivateSubnet2Id:
Description: Private Subnet 2 ID
Value:
Ref: PrivateSubnet2
PublicRouteTableId:
Description: Public Route Table ID
Value:
Ref: PublicRouteTable
PrivateRouteTableId:
Description: Private Route Table ID
Value:
Ref: PrivateRouteTable
ElasticIPId:
Description: Elastic IP ID
Value:
Ref: ElasticIP
NatGatewayId:
Description: NAT Gateway ID
Value:
Ref: NatGateway
Step 6:- Run the cloud-formation templates to create VPC.
open cloudformation service on AWS
Now click on Create Stack and choose "with new resources"
Next, choose Create template in Designer then Json to YMAL
Select the Template option from the bottom left corner and paste the final yaml
In our case, the final YAML is "Create Nat Gateway and associate with EIP."
Validate the YAML file by clicking on cloud-like icon on the top left
Fill in the details click next and your resources will start creating