Using Cloudformation, we can create and manage AWS resources very easily.  Cloudformation can be used to manage all AWS resources using a text file. Cloudformation allows us to create and model our infrastructure and applications without having to perform actions manually. Cloudformation helps us to manage our complete infrastructure in a text file, or template. Cloudformation template is a formatted text file in JSON or YAML language that describes our AWS infrastructure. 

In this article, we will see a Cloudformation to create a VPC with 2 Public and 2 Private Subnets.

Pre-requisites

  1. AWS Account (Create if you don’t have one). 
  2. Basic understanding of Cloudformation Templates.

What we will do?

  1. Login to AWS.
  2. Create a template.
  3. Create a Cloudformation Stack 

Login to AWS

  1. Click here to go to AWS Login Page.

When we hit the above link, we will see a web page as follows where we are required to login using our login details.

<img alt="Login to AWS" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.24_.58_PM_.png6177ebd62f63f.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

Once we login into AWS successfully, we will see the main console with all the services listed as follows.

<img alt="AWS Management Console" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.25_.16_PM_.png6177ebd64a6a6.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="400" loading="lazy" src="data:image/svg xml,” width=”750″>

Create a template

Before we proceed with creating a stack, we should have a template that will be used to create a VPC. Copy the following code and save in on a local machine.

---

AWSTemplateFormatVersion: 2010-09-09

Description: >

  This Templates creates a VPC with 3 public and 3 private subnets.

Parameters:

  VpcCIDR:

    TypeString

    DescriptionVPC CIDR (Do Not Change if no customization is required). 

    Default10.10.0.0/16

  PrivateAZ1SubnetCIDR:

    TypeString

    DescriptionSubnet CIDR for 1st Availability Zone (Do Not Change if no customization is required).

    Default10.10.80.0/21

  PrivateAZ2SubnetCIDR:

    TypeString

    DescriptionSubnet CIDR for 2nd Availability Zone (Do Not Change if no customization is required).

    Default10.10.88.0/21

  PrivateAZ3SubnetCIDR:

    TypeString

    DescriptionSubnet CIDR for 3rd Availability Zone (Do Not Change if no customization is required).

    Default10.10.96.0/21

  PublicAZ1SubnetCIDR:

    TypeString

    DescriptionSubnet CIDR for 1st Availability Zone (Do Not Change if no customization is required).

    Default10.10.0.0/21

  PublicAZ2SubnetCIDR:

    TypeString

    DescriptionSubnet CIDR for 2nd Availability Zone (Do Not Change if no customization is required).

    Default10.10.8.0/21

  PublicAZ3SubnetCIDR:

    TypeString

    DescriptionSubnet CIDR for 3rd Availability Zone (Do Not Change if no customization is required). 

    Default10.10.16.0/21

Metadata:

  AWS::CloudFormation::Interface:

    ParameterGroups:

      - Label:

          defaultVPC

        Parameters:

          - VpcCIDR

      - Label:

          defaultAvailabilty Zone 1

        Parameters:

          - PublicAZ1SubnetCIDR

          - PrivateAZ1SubnetCIDR

      - Label:

          defaultAvailabilty Zone 1

        Parameters:

          - PublicAZ2SubnetCIDR

          - PrivateAZ2SubnetCIDR

      - Label:

          defaultAvailabilty Zone 1

        Parameters:

          - PublicAZ3SubnetCIDR

          - PrivateAZ3SubnetCIDR

Resources:

  Vpc:

    TypeAWS::EC2::VPC

    Properties:

      CidrBlock!Ref VpcCIDR

      Tags:

        - KeyName

          Value!Sub ${AWS::StackName}

  InternetGateway:

    TypeAWS::EC2::InternetGateway

    Properties:

      Tags:

        - KeyName

          Value!Sub ${AWS::StackName}

  VPCGatewayAttachment:

    TypeAWS::EC2::VPCGatewayAttachment

    Properties:

      InternetGatewayId!Ref InternetGateway

      VpcId!Ref Vpc

  # Public Subnets - Route Table

  PublicRouteTable:

    TypeAWS::EC2::RouteTable

    Properties:

      VpcId!Ref Vpc

      Tags:

        - KeyName

          Value!Sub ${AWS::StackName}-public

        - KeyType

          Valuepublic

  PublicSubnetsRoute:

    TypeAWS::EC2::Route

    Properties:

      RouteTableId!Ref PublicRouteTable

      DestinationCidrBlock0.0.0.0/0

      GatewayId!Ref InternetGateway

    DependsOnVPCGatewayAttachment

  # Public Subnets

  PublicAZ1Subnet:

    TypeAWS::EC2::Subnet

    Properties:

      VpcId!Ref Vpc

      CidrBlock!Ref PublicAZ1SubnetCIDR

      AvailabilityZone!Select [0!GetAZs ""]

      MapPublicIpOnLaunchtrue

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-public-${AZ}

            - { AZ!Select [0!GetAZs ""] }

        - KeyType

          Valuepublic

  PublicAZ1SubnetRouteTableAssociation:

    TypeAWS::EC2::SubnetRouteTableAssociation

    Properties:

      SubnetId!Ref PublicAZ1Subnet

      RouteTableId!Ref PublicRouteTable

  PublicAZ2Subnet:

    TypeAWS::EC2::Subnet

    Properties:

      VpcId!Ref Vpc

      CidrBlock!Ref PublicAZ2SubnetCIDR

      AvailabilityZone!Select [1!GetAZs ""]

      MapPublicIpOnLaunchtrue

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-public-${AZ}

            - { AZ!Select [1!GetAZs ""] }

        - KeyType

          Valuepublic

  PublicAZ2SubnetRouteTableAssociation:

    TypeAWS::EC2::SubnetRouteTableAssociation

    Properties:

      SubnetId!Ref PublicAZ2Subnet

      RouteTableId!Ref PublicRouteTable

  PublicAZ3Subnet:

    TypeAWS::EC2::Subnet

    Properties:

      VpcId!Ref Vpc

      CidrBlock!Ref PublicAZ3SubnetCIDR

      AvailabilityZone!Select [2!GetAZs ""]

      MapPublicIpOnLaunchtrue

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-public-${AZ}

            - { AZ!Select [2!GetAZs ""] }

        - KeyType

          Valuepublic

  PublicAZ3SubnetRouteTableAssociation:

    TypeAWS::EC2::SubnetRouteTableAssociation

    Properties:

      SubnetId!Ref PublicAZ3Subnet

      RouteTableId!Ref PublicRouteTable

  # Private Subnets - NAT Gateways

  AZ1NatGatewayEIP:

    TypeAWS::EC2::EIP

    Properties:

      Domainvpc

    DependsOnVPCGatewayAttachment

  AZ1NatGateway:

    TypeAWS::EC2::NatGateway

    Properties:

      AllocationId!GetAtt AZ1NatGatewayEIP.AllocationId

      SubnetId!Ref PublicAZ1Subnet

  AZ2NatGatewayEIP:

    TypeAWS::EC2::EIP

    Properties:

      Domainvpc

    DependsOnVPCGatewayAttachment

  AZ2NatGateway:

    TypeAWS::EC2::NatGateway

    Properties:

      AllocationId!GetAtt AZ2NatGatewayEIP.AllocationId

      SubnetId!Ref PublicAZ2Subnet

  AZ3NatGatewayEIP:

    TypeAWS::EC2::EIP

    Properties:

      Domainvpc

    DependsOnVPCGatewayAttachment

  AZ3NatGateway:

    TypeAWS::EC2::NatGateway

    Properties:

      AllocationId!GetAtt AZ3NatGatewayEIP.AllocationId

      SubnetId!Ref PublicAZ3Subnet

  # Private Subnets

  PrivateAZ1Subnet:

    TypeAWS::EC2::Subnet

    Properties:

      VpcId!Ref Vpc

      CidrBlock!Ref PrivateAZ1SubnetCIDR

      AvailabilityZone!Select [0!GetAZs ""]

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-private-${AZ}

            - { AZ!Select [0!GetAZs ""] }

        - KeyType

          Valueprivate

  PrivateAZ1RouteTable:

    TypeAWS::EC2::RouteTable

    Properties:

      VpcId!Ref Vpc

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-private-${AZ}

            - { AZ!Select [0!GetAZs ""] }

        - KeyType

          Valueprivate

  PrivateAZ1Route:

    TypeAWS::EC2::Route

    Properties:

      RouteTableId!Ref PrivateAZ1RouteTable

      DestinationCidrBlock0.0.0.0/0

      NatGatewayId!Ref AZ1NatGateway

  PrivateAZ1RouteTableAssociation:

    TypeAWS::EC2::SubnetRouteTableAssociation

    Properties:

      SubnetId!Ref PrivateAZ1Subnet

      RouteTableId!Ref PrivateAZ1RouteTable

  PrivateAZ2Subnet:

    TypeAWS::EC2::Subnet

    Properties:

      VpcId!Ref Vpc

      CidrBlock!Ref PrivateAZ2SubnetCIDR

      AvailabilityZone!Select [1!GetAZs ""]

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-private-${AZ}

            - { AZ!Select [1!GetAZs ""] }

        - KeyType

          Valueprivate

  PrivateAZ2RouteTable:

    TypeAWS::EC2::RouteTable

    Properties:

      VpcId!Ref Vpc

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-private-${AZ}

            - { AZ!Select [1!GetAZs ""] }

        - KeyType

          Valueprivate

  PrivateAZ2Route:

    TypeAWS::EC2::Route

    Properties:

      RouteTableId!Ref PrivateAZ2RouteTable

      DestinationCidrBlock0.0.0.0/0

      NatGatewayId!Ref AZ2NatGateway

  PrivateAZ2RouteTableAssociation:

    TypeAWS::EC2::SubnetRouteTableAssociation

    Properties:

      SubnetId!Ref PrivateAZ2Subnet

      RouteTableId!Ref PrivateAZ2RouteTable

  PrivateAZ3Subnet:

    TypeAWS::EC2::Subnet

    Properties:

      VpcId!Ref Vpc

      CidrBlock!Ref PrivateAZ3SubnetCIDR

      AvailabilityZone!Select [2!GetAZs ""]

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-private-${AZ}

            - { AZ!Select [2!GetAZs ""] }

        - KeyType

          Valueprivate

  PrivateAZ3RouteTable:

    TypeAWS::EC2::RouteTable

    Properties:

      VpcId!Ref Vpc

      Tags:

        - KeyName

          Value!Sub

            - ${AWS::StackName}-private-${AZ}

            - { AZ!Select [2!GetAZs ""] }

        - KeyType

          Valueprivate

  PrivateAZ3Route:

    TypeAWS::EC2::Route

    Properties:

      RouteTableId!Ref PrivateAZ3RouteTable

      DestinationCidrBlock0.0.0.0/0

      NatGatewayId!Ref AZ3NatGateway

  PrivateAZ3RouteTableAssociation:

    TypeAWS::EC2::SubnetRouteTableAssociation

    Properties:

      SubnetId!Ref PrivateAZ3Subnet

      RouteTableId!Ref PrivateAZ3RouteTable

  

Outputs:

  VpcId:

    DescriptionVPC Id

    Value!Ref Vpc

    Export:

      Name!Sub "${AWS::StackName}-VPC-ID"

Create a Cloudformation Stack

To create a Cloudformation Stack, click on “Services” in the top left and search for “Cloudformation”.

<img alt="Cloudformation Stack" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.25_.26_PM_.png6177ebd65ea1a.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

On the main dashboard, click on “Create stack” -> “With new resorces(standard)”.

<img alt="Create Stack" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.25_.45_PM_.png6177ebd67139e.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="400" loading="lazy" src="data:image/svg xml,” width=”750″>

The stack needs a template file which can be a local file or an object file in the S3 Bucket. Since we will be having a local template, click on “Template is ready” -> “Upload a template file”, click on “Choose file” and select the local template file and proceed further.

<img alt="Stack template" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.26_.46_PM_.png6177ebd68a815.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

Give a name to the stack, keep all other parameters unchanged.

<img alt="Stack name and parameters" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.27_.19_PM_.png6177ebd6a2271.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="399" loading="lazy" src="data:image/svg xml,” width=”750″>

Give Tags if required.

<img alt="Tags" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.27_.38_PM_.png6177ebd6be31c.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

Scroll down the page and click on “Create stack”

<img alt="Create stack" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.27_.48_PM_.png6177ebd6d415e.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="402" loading="lazy" src="data:image/svg xml,” width=”750″>

This will take some time, wait till then.

<img alt="My VPC" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.27_.57_PM_.png6177ebd6e86e6.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

You can see the status or event taking place under “Events” tab.

<img alt="Events" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.31_.19_PM_.png6177ebd70ff7f.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="400" loading="lazy" src="data:image/svg xml,” width=”750″>

Now, you can go to VPC and check for the VPC that got created. To go to VPC, click on “Services” at the top and left search for VPC.Advertisement

<img alt="AWS VPC" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.32_.55_PM_.png6177ebd726248.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

In the main dashboard, you can see the number of VPC, Subnets, Route Tables, Internet Gateway, Nat Gateway which got created.

<img alt="Launch VPC" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.33_.13_PM_.png6177ebd73dc86.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

You can delete the VPC by just deleting the Stack if you no more need it.

<img alt="List of created Stacks" data-ezsrc="https://kirelos.com/wp-content/uploads/2021/10/echo/Screenshot_2020-01-24_at_5.35_.37_PM_.png6177ebd750cc5.jpg" ezimgfmt="rs rscb5 src ng ngcb5" height="401" loading="lazy" src="data:image/svg xml,” width=”750″>

Conclusion

In this article, we saw the steps to create a Cloudformation Stack to create a VPC with 2 Public and 2 Private Subnet.