top of page
Derek Hutson

Anatomy of a CloudFormation Template


 



 

In a world where changes are best done automatically, it is important to have the right set of tools for this. Automation helps improve your level of operational efficiency exponentially.


There is much debate about the best IaC (Infrastructure as Code) provider. Some of the most popular options are Terraform, Ansible, and CloudFormation. All of them have pros and cons, but some of the underlying themes of all IaC providers include:

  • Maintaining Infrastructure in a desired state

  • Consistent deployment of resources

  • Significantly higher level of scalability and velocity

  • Adherence to company policy for resources

If your resources are mostly on AWS, then it makes sense to use CloudFormation. In a nutshell, CloudFormation templates are just JSON (or YAML) files that describe how you want your resources deployed.


So let’s look at the anatomy of a template to better understand how they allow us to have much better control over our cloud infrastructure.


Below, I have laid out a sample template designed to install the CloudWatch Agent on amazon linux. We will talk more about what each section is and does.



 

---

AWSTemplateFormatVersion: '2010-09-09'

Description: 'Template to install CloudWatchAgent on amazon linux. It was validated on amazon linux 2'

Parameters:

KeyName:

Description: Name of an existing EC2 KeyPair to enable SSH access to the instance

Type: AWS::EC2::KeyPair::KeyName

ConstraintDescription: must be the name of an existing EC2 KeyPair.

InstanceType:

Description: EC2 instance type

Type: String

Default: m4.2xlarge

ConstraintDescription: must be a valid EC2 instance type.

InstanceAMI:

Description: Managed AMI ID for EC2 Instance

Type : String

Default: ami-7707a10f

IAMRole:

Description: EC2 attached IAM role

Type: String

Default: CloudWatchAgentAdminRole

ConstraintDescription: must be an existing IAM role which will be attached to EC2 instance.

SSHLocation:

Description: The IP address range that can be used to SSH to the EC2 instances

Type: String

MinLength: '9'

MaxLength: '18'

Default:0.0.0.0/0

AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})

ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.

Resources:

EC2Instance:

Type: AWS::EC2::Instance

Metadata:

AWS::CloudFormation::Init:

configSets:

default:

- 01_setupCfnHup

- 02_config-amazon-cloudwatch-agent

- 03_restart_amazon-cloudwatch-agent

UpdateEnvironment:

- 02_config-amazon-cloudwatch-agent

- 03_restart_amazon-cloudwatch-agent

# Definition of json configuration of AmazonCloudWatchAgent, you can change the configuration below.

02_config-amazon-cloudwatch-agent:

files:

'/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json':

content: !Sub |

{

"metrics":{

"append_dimensions":{

"AutoScalingGroupName":"${!aws:AutoScalingGroupName}",

"ImageId":"${!aws:ImageId}",

"InstanceId":"${!aws:InstanceId}",

"InstanceType":"${!aws:InstanceType}"

},

"metrics_collected":{

"mem":{

"measurement":[

"mem_used_percent"

]

},

"swap":{

"measurement":[

"swap_used_percent"

]

}

}

}

}

# Invoke amazon-cloudwatch-agent-ctl to restart the AmazonCloudWatchAgent.

03_restart_amazon-cloudwatch-agent:

commands:

01_stop_service:

command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop

02_start_service:

command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s

# Cfn-hup setting, it is to monitor the change of metadata.

# When there is change in the contents of json file in the metadata section, cfn-hup will call cfn-init to restart the AmazonCloudWatchAgent.

01_setupCfnHup:

files:

'/etc/cfn/cfn-hup.conf':

content: !Sub |

[main]

stack=${AWS::StackId}

region=${AWS::Region}

interval=1

mode: '000400'

owner: root

group: root

'/etc/cfn/hooks.d/amazon-cloudwatch-agent-auto-reloader.conf':

content: !Sub |

[cfn-auto-reloader-hook]

triggers=post.update

path=Resources.EC2Instance.Metadata.AWS::CloudFormation::Init.02_config-amazon-cloudwatch-agent

action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region} --configsets UpdateEnvironment

runas=root

mode: '000400'

owner: root

group: root

"/lib/systemd/system/cfn-hup.service":

content: !Sub |

[Unit]

Description=cfn-hup daemon

[Service]

Type=simple

ExecStart=/opt/aws/bin/cfn-hup

Restart=always

[Install]

WantedBy=multi-user.target

commands:

01enable_cfn_hup:

command: !Sub |

systemctl enable cfn-hup.service

02start_cfn_hup:

command: !Sub |

systemctl start cfn-hup.service


Properties:

InstanceType:

Ref: InstanceType

IamInstanceProfile:

Ref: IAMRole

KeyName:

Ref: KeyName

ImageId:

Ref: InstanceAMI

SecurityGroups:

- Ref: InstanceSecurityGroup

UserData:

# This script below is to install AmazonCloudWatchAgent, restart AmazonCloudWatchAgent and tell the result to cloudformation.

Fn::Base64: !Sub |

#!/bin/bash

rpm -Uvh https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm

/opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region} --configsets default

/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region}


CreationPolicy:

ResourceSignal:

Count:1

Timeout:"PT15M"

InstanceSecurityGroup:

Type: AWS::EC2::SecurityGroup

Properties:

GroupDescription: Enable SSH access via port 22

SecurityGroupIngress:

- IpProtocol: tcp

FromPort: '22'

ToPort: '22'

CidrIp:

Ref: SSHLocation


 

Format Version:

  • This is the CloudFormation template version that the template conforms to. I generally haven’t ever had to mess with this and as you can see the versions don’t change too often.

Description

  • This is a text string that describes the template. Useful to say what the purpose of this template is, the only requirement here is that it follows the version section.

Parameters

  • Our first very important section, these are sets of values that you want to pass to your template at runtime. You can refer to parameters in the Resources and Outputs section. For example, you can say what type of EC2 instance you want created.

Resources

  • This is the only required section of a template. It specifies your stack resources and their properties, such as instances or buckets. You can refer to resources in the Resources and Outputs section.

Outputs

  • Describes the values that are returned whenever you view your stacks properties. Mostly used to view values via the CLI.

Conditions

  • Conditional statements determine whether certain resources are created or whether certain resource properties are assigned a value during stack creation/update. For example, you could deny creation of IAM users if MFA is not enabled.

Metadata

  • Objects that provide further information about a template, or resources.

 

These are some core components to CloudFormation templates. If you want to take a peek at more templates, AWS has a GitHub repo full of them you can browse through here.


I hope this is helpful for you if you are looking to understand more about IaC, and CloudFormation in particular. If DevOps is something that interests you, then you should become quite familiar with deploying Infrastructure as Code.


3 views0 comments

Comentarios


bottom of page