Deploy AWS VPC using AWS CloudFormation
Welcome to our comprehensive guide on deploying AWS Virtual Private Cloud (VPC) using AWS CloudFormation. In this blog, we will dive deep into the world of VPCs and explore how CloudFormation can streamline the deployment process, making it easier and more efficient for you. Whether you’re a beginner or an experienced AWS user, this guide will provide you with valuable insights and practical tips to master VPC deployment with CloudFormation.
CloudFormation makes it easy to automate the deployment of resources in the AWS Cloud. Instead of manually launching services through the console, CloudFormation allows you to define your infrastructure as code using JSON or YAML templates. This approach offers several benefits, including faster deployment, repeatability, and reduced risk of misconfiguration.
In this blog, we will guide you through the process of deploying a VPC and associated resources using CloudFormation. We will use YAML as the language of choice for our templates, but you can also use JSON if you prefer. The complete code for this tutorial can be found on our GitHub repository.
Let’s begin by creating the following resources:
- VPC: A Virtual Private Cloud with a CIDR block range of 10.0.0.0/16.
- Internet Gateway: A gateway that connects the VPC to the internet.
- Public Subnets: Two subnets that are accessible from the internet.
- Private Subnets: Two subnets that are not accessible from the internet.
- Route tables: Route tables associated with the subnets.
- Security Group: A security group for a web server.
- EC2 Instance: An EC2 instance that will serve as our web server.
To create the VPC, add the following YAML code to your CloudFormation template:
Resources:
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: VPC Blog Post
In this section, we define the VPC resource using the AWS::EC2::VPC
type. We specify the CIDR block range as 10.0.0.0/16 and enable DNS support and hostnames. Additionally, we assign the name "VPC Blog Post" to the VPC using tags.
Next, let’s create the Internet Gateway and attach it to the VPC:
InternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: VPC Blog Post
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
Here, we define the Internet Gateway resource and associate the name “VPC Blog Post” with it using tags. The InternetGatewayAttachment
resource attaches the Internet Gateway to the VPC. The !Ref
syntax refers to the resources created earlier, allowing us to specify dependencies.
In the next sections of the blog, you will continue building the remaining resources, including subnets, route tables, security groups, and the EC2 instance. you will also provide detailed explanations for each step along the way.
Now that we have created the VPC, internet gateway, and route tables, it’s time to add the subnets to our infrastructure. We’ll create two public subnets (PublicSubnet1
and PublicSubnet2
) and two private subnets (PrivateSubnet1
and PrivateSubnet2
). Here's the code to add the subnets:
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: VPC Blog Post Public Subnet 1
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [1, !GetAZs '']
CidrBlock: 10.0.2.0/24
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: VPC Blog Post Public Subnet 2
PrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: 10.0.11.0/24
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: VPC Blog Post Private Subnet 1
PrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [1, !GetAZs '']
CidrBlock: 10.0.12.0/24
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: VPC Blog Post Private Subnet 2
In the code above, we define each subnet using the AWS::EC2::Subnet
resource type. We set the VpcId
property to reference the VPC we created (!Ref VPC
). The AvailabilityZone
property is set to select the respective availability zone (!Select [0, !GetAZs '']
or !Select [1, !GetAZs '']
) based on the index value. The CidrBlock
property defines the range of IP addresses for each subnet. The MapPublicIpOnLaunch
property is set to true
for the public subnets and false
for the private subnets. Finally, we assign names to the subnets using tags.
With the addition of the subnets, we have now created the foundational components of our VPC infrastructure. In the upcoming sections of the blog, we will cover the creation of a security group, launching an EC2 instance, and displaying the output of the web server’s public IP address.
Now that we have the VPC, internet gateway, and subnets in place, we can proceed to create a route table for the public subnets and associate them accordingly. Let’s go through the code you provided:
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: VPC Blog Public Routes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1
PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
Now that we have the VPC, internet gateway, and subnets in place, we can proceed to create a route table for the public subnets and associate them accordingly. Let’s go through the code you provided:
yamlCopy code
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: VPC Blog Public Routes
DefaultPublicRoute:
Type: AWS::EC2::Route
DependsOn: InternetGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGatewayPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet1PublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnet2
In the code above, we create the PublicRouteTable
resource using the AWS::EC2::RouteTable
type. We specify the VPC to associate the route table with (VpcId: !Ref VPC
). Additionally, we assign a name to the route table using tags.
Next, we define the DefaultPublicRoute
which represents the route to the internet gateway. This route allows all traffic (0.0.0.0/0
) to be routed through the internet gateway. The DependsOn
attribute ensures that the internet gateway attachment is created before adding the route.
Following that, we create the PublicSubnet1RouteTableAssociation
and PublicSubnet2RouteTableAssociation
resources. These associations link the public subnets (PublicSubnet1
and PublicSubnet2
) with the PublicRouteTable
. This ensures that the subnets use the specified route table for routing.
Now let’s proceed with creating the security group for our web server and launching an EC2 instance with the desired configuration. Here’s the code to accomplish this:
WebServerSecurityGroup:
Type: 'AWS::EC2::SecurityGroup'
Properties:
GroupDescription: Web Server Traffic
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: 0.0.0.0/0
VpcId: !Ref VPC
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0e1d30f2c40c4c701
InstanceType: t2.micro
SubnetId: !Ref PublicSubnet1
SecurityGroupIds:
- !Ref WebServerSecurityGroup
Tags:
- Key: Name
Value: VPC Blog Post EC2
UserData:
Fn::Base64: |
#!/bin/bash
yum install httpd -y
service httpd start
echo "<html><body><h1>Hello from DCT!<h1></body></html>" > /var/www/html/index.html
In the code above, we create the WebServerSecurityGroup
resource using the AWS::EC2::SecurityGroup
type. We provide a description for the security group and define an inbound rule that allows TCP traffic over port 80 (HTTP) from any source (0.0.0.0/0
). The security group is associated with the VPC (VpcId: !Ref VPC
).
Next, we define the EC2Instance
resource using the AWS::EC2::Instance
type. We specify the Amazon Linux 2 AMI (ami-0e1d30f2c40c4c701
) and choose a t2.micro instance type. The instance will be launched in PublicSubnet1
. The security group for the instance is set to WebServerSecurityGroup
. We also assign a name to the instance using tags.
The UserData
section allows us to run custom scripts when the instance is launched. In this case, we use yum
to install the Apache web server, start the service, and create a basic HTML page with the "Hello from DCT!" message.
To complete the configuration, you can add the necessary outputs to retrieve the public IP address of the web server. For example:
Outputs:
WebServerPublicIP:
Value: !GetAtt EC2Instance.PublicIp
Description: Public IP address of the web server
With this output, you can easily grab the IP address of the web server and access the web page.
You now have a fully functional AWS VPC infrastructure with a web server running!