Building a Secure VPC Architecture with AWS CloudFormation: A Step-by-Step Guide

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:

  1. 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).

  2. Availability Zones (AZs): Determine how many availability zones you need for high availability. AWS recommends a minimum of two.

  3. 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.

  4. Security Groups: When setting up your VPC, it's crucial to consider routing and select a strategy that allows for internet access.

  5. Routing: To enable internet access and establish VPN connections.

  6. 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.

  7. 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

CAUTION:- Deleting this stack will delete all stack resources