AWS CloudFormation Series

AWS CloudFormation Series

While learning about CloudFormation, I noticed there were not a lot of beginner-friendly articles available. Hence, the reason for this series of mine.

In this series, I aim to cover foundational concepts around AWS EC2 instances and services to help people new to CloudFormation.

What is CloudFormation

I refer to AWS CloudFormation as Terraform for AWS services.

Cloudformation, like Terraform, is an Infrastructure as Code (IaC) tool that helps you provision resources. CloudFormation is AWS focused, while Terraform works across various cloud and on-prem services.

According to the official documentation, "CloudFormation is a service that helps you model and set up your AWS resources so that you can spend less time managing those resources and more time focusing on your applications that run in AWS."

What are EC2 instances, and what goes into creating them?

EC2 instances are AWS's virtual machines. According to AWS, an EC2 instance provides scalable computing capacity in the Amazon Web Services (AWS) Cloud.

To provision an EC2 instance, you need to set up the following:

  • Virtual Private Cloud: you create a VPC to isolate your EC2 instance within the AWS cloud.

  • Security Group: acts as a virtual firewall for your EC2 instances controlling incoming and outgoing traffic.

  • Key Pair: this consists of a public key and a private key. You use this key when connecting to an EC2 instance.

  • Internet Gateway: Allocates an internet gateway for use with a VPC. After creating the Internet gateway, you then attach it to a VPC.

  • VPC GateWay Attachment: Attaches an internet gateway, or a virtual private gateway to a VPC, enabling connectivity between the internet and the VPC.

  • Subnet (public and private): a logical partition of an IP network into multiple, smaller network segments.

  • Route Table (public and private): a rule called routes determines where network traffic from your subnet or gateway is directed.

  • Route (public and private): within a VPC, the route consists of a single destination prefix in CIDR format and a single next hop.

  • Subnet route table association (public and private): Associates a subnet with a routeing table.

Cloudformation's Syntax

In this section, we'd see hands-on examples of how to provision resources using CloudFormation.

Prerequisites

  • Feel free to set up an Identity and Access Management user. Grant this user full access to the service AWS CloudFormation.

  • Download and configure your AWS CLI with your login credentials.

    aws configure
    

Creating an EC2 Instance

main.yml

Description: 
  Creating an EC2 Instance

Parameters:

  EnvironmentName:
    Description: Prefixed to resources
    Type: String

  VpcCIDR:
    Description: IP range (CIDR notation)
    Type: String
    Default: 10.0.0.0/16

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties: 
      CidrBlock: !Ref VpcCIDR
      EnableDnsHostnames: 'true'   
      Tags:
        - Key: Name 
          Value:  !Ref EnvironmentName

  InternetGateway:
      Type: 'AWS::EC2::InternetGateway'
      Properties:
        Tags:
          - Key: Name
            Value: !Ref EnvironmentName

  AttachGateway:
      Type: 'AWS::EC2::VPCGatewayAttachment'
      Properties:
        InternetGatewayId: !Ref InternetGateway
        VpcId: !Ref VPC

  KeyName:
      Type: 'AWS::EC2::KeyPair'
      Properties:
        KeyName: <keyname>
        KeyType: rsa
        Tags:
          - Key: Name
            Value: !Ref EnvironmentName

  PublicSubnet:
      Type: 'AWS::EC2::Subnet'
      Properties:
        VpcId: !Ref VPC
        CidrBlock: 10.0.1.0/24
        AvailabilityZone: <your-az-zone>
        MapPublicIpOnLaunch: true
        Tags:
          - Key: Name
            Value: !Ref EnvironmentName

  PrivateSubnet:
      Type: 'AWS::EC2::Subnet'
      Properties:
        VpcId: !Ref VPC
        CidrBlock: 10.0.2.0/24
        MapPublicIpOnLaunch: false
        AvailabilityZone: <your-az-zone>
        Tags:
          - Key: Name
            Value: !Ref EnvironmentName

  PublicRouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
          - Key: Name
            Value: !Ref EnvironmentName

  PublicRoute:
    Type: 'AWS::EC2::Route'
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable  

  PrivateRouteTable:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Ref EnvironmentName

  PrivateSubnetRouteTableAssociation:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable    

  EC2Instance:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: ami-xxxxxx
      InstanceType: t2.micro
      SecurityGroupIds:
        - !Ref SecurityGroup
      SubnetId: !Ref PublicSubnet
      KeyName: !Ref KeyName    

  SecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: Security group to allow traffic to and from ports 80 and 22.
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: !Ref EnvironmentName

parameters.json

[
    {
        "ParameterKey": "EnvironmentName",
        "ParameterValue": "cfArticle"
    }    

]

The parameters.json file, holds the values of variables we defined in the main.yml file.

To provision your VPC, run:

$ aws cloudformation create-stack --stack-name stackname --template-body file://file.yml --parameters file://file.json
{
    "StackId": "arn:aws:cloudformation:us-west-1:5000:stack/stack/xxxx-xxxx-xxxx-xxxxx-xxxxxxx"
}

image

CloudFormation Stack showing a collection of AWS resources that you can manage as a single unit

Connecting to your EC2 Instance

For you to SSH into your instance, you have to create the keypair and reference it in your CloudFormation script like so:

KeyName: your-ec2-keypair

You can also connect to your instance using the EC2 Instance Connect (if you created the KeyPair using CloudFormation).

Screenshot 2022-09-15 at 14 36 26 EC2 Instance Connect

CloudFormation Commands

  • To create a stack:

    aws cloudformation create-stack \
    --stack-name <value> \
    --template-body file://file.yml \
    --parameters file://file.json \
    
  • To update an existing stack

    aws cloudformation update-stack \
    --stack-name <value> \
    --template-body file://file.yml \
    --parameters file://file.json \
    
  • To delete a stack

    delete-stack \
    --stack-name <value>
    

You can find more CloudFormation commands here.

Note:

  • Deleting a stack deletes all resources that the stack provisioned.
  • After updating or creating your stack, you can validate your script using AWS CloudFormation's designer by:

    • Clicking on 'View in Designer'. Screenshot 2022-09-14 at 14 01 25

      View in Designer

      • Editing and validating your code. Viewing your code in JSON format clearly shows the error source.

        Screenshot 2022-09-14 at 15 31 31

        Validate button

Conclusion

CloudFormation is your go-to tool when you only want to provision AWS resources. Your CloudFormation scripts can be in JSON or YAML file formats; however, there is a caveat where your files cannot exceed 51MB. If your files exceed 51MB, you must create nested stacks.

Feel free to refer to my GitHub Repo.

Thanks for your time. Kindly look forward to other articles in this series.