AWS Professional : CloudFormation

Alberto Cubeddu
4 min readNov 30, 2018

What is an AWS CloudFormation Template?

A template is a text file written in JSON or YAML that define a declaration of the AWS resources that make up a stack.

AWS Cloudformation contains six section: AWSTemplateVersion, Description, Metadata, Parameters, Mappings, Conditions, Transform, Resources, Outputs.

AWS Cloudformation display different event such: CREATE_IN_PROGRESS, CREATE_COMPLETE, DELETE_IN_PROGRESS or CREATE_FAILED where the Status Reason column displays the issue that caused the failure

Various of the cloudformation’s status

It’s always good to DO NOT DEFINE name! This is because we want to create the stack 1, 10, N times!

Parameters

Are the way to pass values into the CF Template
A parameter has a type that can have:
* Default Value
* Allowed Value
* Allowed Pattern (Regex)
* Min/Max (Number or String)

NoEcho -> Will display ***** (useful for password)

Resource

It’s the only mandatory section in a CF Template! a logical ID and a type MUST be specified. Some of the resource it can have properties (some of which can be required), take the example here:

#AWS::ProductIdentifier::ResourceTypeResources: 
LogicaId:
Type: AWS:S3:Bucket

Resource References
To avoid to hardcode resources values, we can use Parameters as a source of truth, in this case we can just Refer the value of the Parameter into the Resource section:

"Parameters" : {
"Username": {
"Type" : "String"
}
}
"Resources" : {
"logical-ID" : {
"Type" : { "AWS::RDS::DBInstance" },
"Properties" : {
"MasterUsername" : {"Ref": "Username"}
}
}
}

Conditions:

Conditions are really useful when you have a “boolean problem”. For example you need to create a resource just for production you can do:

isProduction: !Equals [ !Ref "Vpc", "production" ]#and this can be used for the decision of the resource creation:
GenericLogicalIDForSecurity:
Condition:
"isProduction" #Create the securityGroup just on Prod.
Type: "AWS::EC2::SecurityGroupIngress"

Outputs

Displaying result from the stack creation to be able to display it into the CLI/UI or to be used in other stacks!

#Where VPC is a Parameter of the stack{
"Resources" : {
"Bucket-LogicalID" : {
"Type" : "AWS::S3::Bucket"
}
},
"Outputs" : {
"BucketName" {
"Value" : {"Ref" : "Bucket-LogicalID"}
Export:
Name: !Join ["", [ !Ref "Vpc", "-export-this-logical-id"]]
}
}
}
## Those can now be called in other stacks e.g.
Fn::ImportValue:
!Sub "${Vpc}-export-this-logical-id"

Intrinsic Function & Conditionals

Fn::Base64
Fn::FindInMap
Fn::getAtt
Fn::getAzs
Fn::Join
Fn::Select
Ref
===== Conditional =====
Fn::And
Fn::Equals
Fn::If
Fn::Not
Fn::Or

Base64: It accepts a string (plain text) and converts it to base64. This is useful for various resource in AWS that accept just base64 data

{ "Fb::Base64" : "apt-get update && apt-get install" }

FindInMap: Allow to perform lookups into hash/dictionary using mapping object.

GetAtt: Return an attribute from an object (template or nested template). The difference between ref is the retrieval of the REAL value (for example an IP address)

GetAZs: Return a list of availability zone

Join: Its just join values together

"Fn::Join" : [";",["1","2","3"]]
#Will return 1;2;3

Select: its select a single object from a list of object

#Get the first AZ returned from GetAZs
{ "Fn:::Select" : [ "0", { "Fn::GetAZs" : "" } ] }

Ref: We use it to refer object or parameter value created in the template. Already done example before

Mapping

Mapping can be used for conditional statement, let’s use the example of selecting an AMI ID, as we know they change in every different region:

#Get the first AZ returned from GetAZs
Mappings:
RegionMap:
us-east-1:
AMI: ami-12312312
us-east-2:
AMI: ami-12312312
#Retrieve
!FindInMap["RegionMap", !Ref "AWS::Region", AMI]
#Different Syntax
!FindInMap
- RegionMap
- !Ref "AWS::Region"
- AMI

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/gettingstarted.templatebasics.html (Constructed Values and Output Values)

Metadata

You can use the optional Metadata section to include arbitrary JSON or YAML objects that provide details about the template.

Metadata:   
Instances:
Description: "Information about the instances"
Databases:
Description: "Information about the databases"

TIPS AND TRICKS

Read the documentation, cloudformation is very powerful, however without following the documentation you will lose your mind really quick!

Always try to have everything in the same template, group resource by service, if you need to have access to a RDS database, create a SecurityGroupIngress rule instead of modifying the real security group.

Always try to define Monitor and Alert in your template, this will allow you to have everything under control!

Do not use name, EXPORT name, so you can create your stack 1,N times, and most important if you have to do a major update cloudformation will take care of the up/down instead of bring your stack down for the time that you need.

If you are getting stuck because some of the cfn-init are failing, just remove the:

#/opt/aws/bin/cfn-signal -e $? — region ${AWS::Region} — stack ${AWS::StackName} — resource ECSAutoScalingGroup

in this case you are not sending the cfn-signal and the instance will be not killed by the autoscaling group if there is some error and you can check the /var/logs/cfn-init.log to see if there is something wrong.

--

--

Alberto Cubeddu

Leadership || Management || Innovation - Technology Director & Former Head Of Engineering