How to create AWS Cloud Formation Template in simple way

      Comments Off on How to create AWS Cloud Formation Template in simple way

This Guide will walk you through the concepts involved in creating AWS CloudFormation Template in a very understandable way.

AWS Cloud Formation is a very useful service which will help us to provision whole stack of AWS resources. This will help developers to create infrastructure in AWS. Instead of jumping in and doing Cloud Admin stuffs developer can give the input parameters and it will create the stack for him.

AWS Cloud Formation has so many reference on Internet and many of them are very helpful but what I found while going through them is that you have to go through 100s of them to consolidate a single template. So finally decided to put most of things here.
 
Few important points worth considering while working on complex templates
 
1) It is better to divide the Stack in Logical Components then create Cloud Formation Template for them. You can even break your template into multiple template and refer them where ever it requires. This will reduce the number of lines and this will also give a proper structure for template.
eg: VPC , Subnets and NAT Gateway
DB Subnet Group, RDS, Replica and CloudWatch Alarms,
 
2) Tags are very important as it helps in filtering the resources for Cost monitoring and other automations.
 
3) Parameterise template instead of hardcoding  : Always try to pass variables from Parameters. This helps to make the template Universal.
 

Main parts of Cloud Formation Template :

 
Cloudformation template will be divided in 3 Parts.

1, Parameters

2, Resources

3, Output

  1. Parameters

Inside parameters section we can define what all parameter we are going to use in this template. This will help us to reduce the complexity of the template maintenance.  It is better to parameterize things like AMI ID Subnet, Keypair name etc.

Keeping these values in Parameters help in making the template universal.

Tip: Always create your AWS Resources with proper tags. Leaving the tagging part for later is time consuming activity.

Types:
“VPC” : {
   “Description” : “The VPC in which you want to Launch your EC2”,
   “Type” : “AWS::EC2::VPC::Id”
}

Parameter type should be the existing parameters which is given by AWS.

Existing AWS values that are in the template user’s account. You can specify the following AWS-specific types: Few examples are below.
 
AWS::EC2::AvailabilityZone::Name
An Availability Zone, such as us-west-2a.
AWS::EC2::Image::Id
An Amazon EC2 image ID, such as ami-aq863dsg. Note that the AWS CloudFormation console won’t show a drop-down list of values for this parameter type.
AWS::EC2::Instance::Id
An Amazon EC2 instance ID, such as i-7hbckj8s6fewffrv.
AWS::EC2::KeyPair::KeyName
An Amazon EC2 key pair name.
AWS::EC2::SecurityGroup::GroupName
An EC2-Classic or default VPC security group name, such as my-sg-abc.
AWS::EC2::SecurityGroup::Id
A security group ID, such as sg-7hbckj8s6.
AWS::EC2::Subnet::Id
A subnet ID, such as subnet-7hbckj8s6.
AWS::EC2::Volume::Id
An Amazon EBS volume ID, such as vol-7hbckj8s6.
AWS::EC2::VPC::Id
A VPC ID, such as vpc-a890hsb3.
AWS::Route53::HostedZone::Id
An Amazon Route 53 hosted zone ID, such as Z98JJHA4SAXS8BHB.

  1. Resources

Resource part is the heart of the template. Here we will specify what all resource we want to create using this template. In this example I am creating EC2 Security Group and EC2 Instance.

Syntax of Resources:

"Resources" : {

    "Logical ID" : {

        "Type" : "Resource type",

        "Properties" : {

            Set of properties

        }

    }

}

Properties should be from the list of available properties from AWS.

  1. Outputs

Output will help us to verify the resources created and also this will help us to export the resources to the next template.

Things like Static IP and stuffs we can export to next template to do some activities.

What’s the use of this OUTPUTS?

It is not mandatory to provide output section in template but if use a Nested Template where 2nd Resource is dependent on the values from 1st Resource then this comes in picture.
 
Sample Cloudformation template to create Single EC2 instance with Security Group,

{ 
“AWSTemplateFormatVersion”:“2010-09-09”,
“Description”:“Template to create EC2 Instance and Security group”,
“Parameters”:{  
  “TagValue1”:{  
    “Description”:“The Project Name “,
    “Type”:“String”
  },
  “TagValue2”:{  
    “Description”:“The Environment name”,
    “Type”:“String”,
    “AllowedValues”:[  
      “dev”,
      ”qa”,
      ”prod”
    ]
  },
  “TagValue3”:{  
    “Description”:“The EC2 Instance Name”,
    “Type”:“String”
  },
  “TagValue4”:{  
    “Description”:“The Server Name”,
    “Type”:“String”
  },
  “VPC”:{  
    “Description”:“The VPC in which you want to Launch your EC2”,
    “Type”: “AWS::EC2::VPC::Id”
  },
  “AMI”:{  
    “Description”:“The AMI that you’ll use for your EC2”,
    “Type”: “AWS::EC2::Image::Id”
  },
  “IAMROLE”:{  
    “Description”:“The IAM you’ll use for your EC2”,
    “Type”:“String”
  },
  “Subnet”:{  
    “Description”:“The Subnet that you’ll use for your EC2”,
    “Type”: “AWS::EC2::Subnet::Id”
  },
  “KeyPairName”:{  
    “Description”:“Name of an existing Amazon EC2 KeyPair for SSH access to the Web Server”,
    “Type”:“AWS::EC2::KeyPair::KeyName”,
    “Default”:“devopstree-key”
  },
  “InstanceClass”:{  
    “Description”:“EC2 instance type”,
    “Type”:“String”,
    “Default”:“t2.micro”,
    “AllowedValues”:[  
      “t2.micro”,
      ”t2.medium”,
      ”t2.small”,
      ”t2.large”,
      ”m4.large”,
      ”m4.xlarge”,
      ”m4.2xlarge”,
      “m4.4xlarge”,
      ”m4.10xlarge”,
      ”m3.medium”,
      ”m3.large”,
      ”m3.xlarge”,
      ”m3.2xlarge”,
      “c4.large”,
      ”c4.xlarge”,
      ”c4.2xlarge”,
      ”c4.4xlarge”,
      ”c4.8xlarge”,
      ”c3.large”,
      “c3.xlarge”,
      ”c3.2xlarge”,
      ”c3.4xlarge”,
      ”c3.8xlarge”
    ],
    “ConstraintDescription”:“must be a valid EC2 instance type.”
  }
},
“Resources”:{  
  “EC2SecurityGroup”:{  
    “Type”: “AWS::EC2::SecurityGroup”,
    “Properties”:{  
      “GroupDescription”:“SecurityGroup”,
      “VpcId”:{  
        “Ref”:“VPC”
      },
      “SecurityGroupIngress”:[  
        {  
          “IpProtocol”:“tcp”,
          “FromPort”:“22”,
          “ToPort”:“22”,
          “CidrIp”:“0.0.0.0/32”
        },
        {  
          “IpProtocol”:“tcp”,
          “FromPort”:“80”,
          “ToPort”:“80”,
          “CidrIp”:“0.0.0.0/32”
        },
        {  
          “IpProtocol”:“tcp”,
          “FromPort”:“443”,
          “ToPort”:“443”,
          “CidrIp”:“0.0.0.0/32”
        }
      ]
    }
  },
  “Ec2Instance”:{  
    “Type”: “AWS::EC2::Instance”,
    “Properties”:{  
      “ImageId”:{  
        “Ref”:“AMI”
      },
      “InstanceType”:{  
        “Ref”:“InstanceClass”
      },
      “IamInstanceProfile”:{  
        “Ref”:“IAMROLE”
      },
      “KeyName”:{  
        “Ref”:“KeyPairName”
      },
      “SecurityGroupIds”:[  
        {  
          “Ref”:“EC2SecurityGroup”
        }
      ],
      “SubnetId”:{  
        “Ref”:“Subnet”
      },
      “Tags”:[  
        {  
          “Key”:“Project”,
          “Value”:{  
            “Ref”:“TagValue1”
          }
        },
        {  
          “Key”:“Environment”,
          “Value”:{  
            “Ref”:“TagValue2”
          }
        },
        {  
          “Key”:“Name”,
          “Value”:{  
            “Ref”:“TagValue3”
          }
        },
        {  
          “Key”:“Server”,
          “Value”:{  
            “Ref”:“TagValue4”
          }
        }
      ],
      “Tenancy”:“default”
    }
  }
},
“Outputs”:{  
  “InstanceId”:{  
    “Description”:“InstanceId of the newly created EC2 instance”,
    “Value”:{  
      “Ref”:“Ec2Instance”
    }
  },
  “AZ”:{  
    “Description”:“Availability Zone of the newly created EC2 instance”,
    “Value”:{  
      “Fn::GetAtt”:[  
        “Ec2Instance”,
        “AvailabilityZone”
      ]
    }
  },
  “PublicIP”:{  
    “Description”:“Public IP address of the newly created EC2 instance”,
    “Value”:{  
      “Fn::GetAtt”:[  
        “Ec2Instance”,
        “PublicIp”
      ]
    }
  },
  “PrivateIP”:{  
    “Description”:“Private IP address of the newly created EC2 instance”,
    “Value”:{  
      “Fn::GetAtt”:[  
        “Ec2Instance”,
        “PrivateIp”
      ]
    }
  }
 }
}

Now our template is ready.  We can create the stack using the template which we have created.

 

Sharing is caring!

About Dinesh Sobitharaj C

An IT professional having multiple years of experience in IT Infrastructure planning, System integrations, Project implementation and delivery. Devops Enthusiast skilled with broad ranges of technology adoption. Well versed with Cloud Computing and Application Service Offerings such as SaaS/PaaS/IaaS. Expert in aligning business goals, mission and process to architect innovative solutions and strategies.