Tags Archives: cfn-init

AWS – CloudFormation

CloudFormation is a crucial exam topic.

 

CloudFormation is a way of automating the creation and modification of infrastructure in AWS. Infrastructure as code – is declarative code.

 

Makes it easy to re-deploy an environment configuration either in same az, region or other az or regions, and at other times.

 

 

Provides for separation of concern:

 

vpc stacks

 

app stacks

 

network stacks

 

There are existing CF templates available to use

 

CF templates can be manually created using CloudFormation Designer

 

you can also use the Console to input parameters

 

or automatically using YAML files and CLI commands to deploy.

 

 

A stack file always refers to a version of the CloudFormation template syntax. The last version is from 2010.

 

 

 

The CF building blocks are:

 

Template components:

 

Resources – these are MANDATORY – the AWS resources declared in your template

 

Parameters – the dynamic inputs for your template

 

Mappings – static variables for your template

 

Outputs – references to what has been created

 

Conditionals – List of conditions to perform resource creation

 

Metadata

 

Template helpers include references and functions

 

The exam does NOT require you to actually write CloudFormation templates – but it expects you to know how to read templates.

 

YAML and JSON can be used for CF – but JSON is not pleasant – YAML is much easier and appears in the exam. YAML uses key-value pairs.

 

 

Resources

 

are the core of the CF Template – they are mandatory. AWS provides over 224 CF resources

They represent the components that can be created by CF. They are declared and can also reference each other

 

Resource types identifiers are of the form:

 

AWS::aws-product-name::data-type-name

 

Where to find them: there is a link in docs.aws.amazon.com

 

listed under

 

AWS Resource Types Reference

 

 

Almost every AWS service is represented in the CF Resources List. for those which aren’t, you can use AWS Lambda Custom Resources.

 

 

Resource definitions in the YAML form always contain a Type field and a Properties field

 

The contents of the Properties field will be specific to the actual resource they define.

 

You cannot create resources “dynamically”, everything in the CF template has to be declared, it is not possible to perform code generation in the template.

 

 

CloudFormation automatically takes care of resolving dependencies between resources defined in the stack.

 

This means that if you define a subnet and a VPC, for example, CloudFormation creates the VPC before the subnet, since a subnet always refers to a specific VPC. And when you delete a stack, CF will automatically delete the subnet before it deletes the VPC.

 

 

Parameters

 

They provide a powerful way for you to enter inputs into your CF template.

 

Esp useful if you want to re-use your templates in other departments or functions of your company

 

and where some inputs can not be determined precisely ahead of time

 

and help to prevent errors occurring due to type setting in the template.

So you should use a parameter definition when you think the resource config value/s are likely to change in the future.

 

Types include string, number, comma-delimited list

 

there are min or max lengths, constraints, allowed patterns/values

 

how to reference… you use a function called Ref

 

Fn::Ref

 

you use it in the form !Ref <paramenter>

 

eg

 

VpcId: !Ref MyVPC

 

They can be deployed anywhere in a template.

 

The !Ref is a YAML convention

 

and it can reference other elements in the template.

 

Pseudo Parameters

 

these can be used any time and are enabled by default

 

Mappings 

 

are fixed variables that are hard-coded in the template.

 

They are often used to differentiate between different regions, AZs, environments, AMIs, etc.

 

Use when you are sure they will not change. They allow for safer templates. But if the values are more user specific, use parameters instead.

 

 

 

Fn::FindInMap

 

this returns a named value from a specific key…

 

this is used to access mapping values

 

!FindInMap [ MapName, TopLevelKey, SecondLevelKey ]

 

this is a way to read the value of the mapping.

 

Outputs

 

these are optional output values that can be imported into other stacks, provided you export them first.

 

You can view the outputs via Console or CLI.

 

 

Cross Stack Reference – know for the exam!

 

It is a way to do cross-stack collaboration to read variables from one stack into another.

 

in the other second template you use Fn::ImportValue function

 

eg

!ImportValue SSHSecurityGroup (or whatever)

 

Important; note that you cannot delete a CF stack if it has outputs referenced by another stack – you must remove those first (if possible).

 

 

Conditions

 

they are used to control creation of resources or outputs according to a set condition, usually if

 

Environment (dev /test /prod )

 

or any other parameter value…

 

then create or don’t create a resource

 

each condition can also reference another condition, parameter or mapping

 

 

How to define a condition?

 

Conditions:

CreateProdResources: !Equals [ !ref EnvType, prod ]

that means if the env type is equal to prod, then do something

 

the logical ID you choose yourself.

 

the logical functions can be…

 

Fn::
And
Equals
If
Not
Or

 

How to use a condition:

 

apply it to resources, outputs etc

 

a resource may only be created if a condition applies

 

 

Intrinsic Functions – you must know these for the exam!

Ref
Fn::GetAtt
Fn::FindInMap
Fn::ImportValule
Fn::Join
Fn::Sub

 

plus the condition functions:

ie
Fn:If, Fn::Not, Fn::Equals etc etc

 

Fn::Ref

 

this will reference a given parameter, resource,

 

remember – the shorthand in YAML for this is !Ref <item>

 

 

Fn::GetAtt

 

 

attributes are attached to any resource you create, to find out the attributes relating specifically to each resource, check the documentation.

 

You can get use the GetAtt to access whichever attribute you want to reference

 

eg to find out the aZ of an EC2 instance:

 

AvailabilityZone:
!GetAtt EC2Instance.Availability zone

 

Fn::FindInMap

 

 

used to access the mapping values

 

 

see above – already covered

 

Fn::ImportValue

 

to import values that are exported in other templates

 

Fn::Join

 

you can use this to join values with a delimiter eg to create a list a,b,c

 

or A:B:C

 

or whatever

 

Fn::Sub

 

or !Sub

 

– substitution of variables with a string

 

Finally, condition functions

 

we saw those above..

 

!GetAtt

 

 

How to add your user data to CloudFormation

 

A user data script can also be passed to CF. This is done via the function:

 

Fn::Base64 | <your user script contents>

 

(not the script file, the actual contents copypasted)

 

important note: you MUST include the pipe symbol with the function when passing the script contents, else the function will not work!

 

 

the user data script log is maintained at /var/log/cloud-init-output.log

 

 

 

cfn-init

 

important:
AWS::CloudFormation::Init MUST be in the metadata of a resource

this makes EC2 configs more readable

 

the EC2 will query CF to get the init data.

 

The logs are written to /var/log/cfn-init.log

 

NOTE DONT CONFUSE cloud-init and cfn-init!

 

cfn-init vs cloud-init

 

There are two similarly named tools that it is important not to mix up: cfn-init and cloud-init.

 

Both of these tools provide a means of customizing EC2 instances, but they are in fact different tools. So what’s the difference between them?

 

 

cloud-init: is a Ubuntu project that provides a way of customizing Cloud instances.

 

cfn-init is an official AWS-supported tool for customizing EC2 instances.

 

 

cfn-init

 

The cfn-init tool is an AWS utility for customizing EC2 instances.It has 2 main documentation pages: AWS::CloudFormation::Init and cfn-init.

 

cfn-init supports various config management tasks such as creating packages, files, users, groups, commands, and services.

 

You can find these tasks grouped together under “Configsets” which form part of a CloudFormation template, defined using YAML or JSON.

 

The cfn-init script is pre-installed on AmazonLinux2 distros.

 

The cfn-init script obtains the Configset definition from the CloudFormation stack template.

 

 

cfn-init is a set of helper scripts that work with the CloudFormation stack.

 

cfn-init does two things. Firstly, it reads the instructions from CF on how the EC2 instance should be initialized stack and executes it.

 

Secondly, it informs CloudFormation when completed or if an error occurred. CloudFormation waits until the cfn-init process is completed, and it can roll back in the event of errors.

 

cfn-init doesn’t require credentials, so you don’t need to use the –access-key, –secret-key, –role, or –credential-file options.

cfn-init uses the user data to initialize and start the init process.

 

It performs 3 tasks:

 

1. installs the aws-cfn-bootstrap script

 

2. runs cfn-init

 

3. then signals to CloudFormation the result of step 2

 

This means you don’t have to change the user data when you want to install more services. The arguments for the functions are passed from CloudFormation directly via (–stack ${AWS::StackName}, –region ${AWS::Region}), or else through referencing other items in the template (–resource Instance, which is the resource name, or by using the –configsets setup).

 

For step 3 to complete, CloudFormation has to expect an initialization signal. this is done via CreationPolicy. Without this, CloudFormation will wait until the instance resource is created and up and running, and only then will mark it as completed.

 

Configs

 

The basic building block for cfn.init is a config. This defines (and in this order):

 

packages – these define which package is to be installed via a package manager (eg apt or yum).

 

sources – these download compressed files and then extract them to a directory.

 

files – this creates files with defined content.

 

commands – this runs arbitrary commands, eg building an app or copying files.

 

services – these instruct the system service manager – generally systemd – to start a service and to keep it up and running

 

ConfigSets

 

ConfigSets are a configuration that defines which configs are to be run and in which order. Each config has to complete running before cfn-init will start the next one.

 

 

Ordering

 

It’s important to know in which order cfn-init runs the various component parts of the configuration, as it does not necessarily follow the order in which the elements are placed in the template file.

 

First, the configSet defines the order for the configs. Anything else in the list gets run later on.

 

Secondly, within a config the elements will run according to a fixed ordering defined by AWS.

 

As an example of this, it will always install packages before running any commands. Generally you should maintain the template order in the same order as when cfn-init will run it.

 

Finally, there is also ordering inside a config step. In this case note that commands will be run in alphabetical ordering. For this reason, it is advisable to number the commands with 01, 02, 03, 04, nd so on to ensure the correct running order is followed.

 

/opt/aws/cfn-init and /opt/aws/cfn-signal

 

Some best practices for using cfn-init:

Comment out the CreationPolicy from the template before you write the cfn-init scripts. This is because otherwise CloudFormation will roll back the whole stack, and with that destroy the instance, if you make a mistake. But be sure to uncomment it when you’re finished.

 

You can run the cfn-init command if you SSH into the instance too, in order to run a quick deploy test.

 

Remember when debugging you can check the logs at /var/log/cfn-init.log and /var/log/cfn-init-cmd.log.

 

Aim to maintain the template in the correct ordering of the elements, keeping the configs listed according to the configSet, and the parts of the config listed according to their own implicit ordering. And be sure to prefix the commands with 01, 02, 03, and so on, so you can follow what is happening in which order.

 

Refer to the AWS-provided CF template at https://s3.eu-west-1.amazonaws.com/cloudformation-templates-eu-west-1/WordPress_Single_Instance.template.

 

Define a WAIT CONDITION – this blocks the template until it receives a signal from cfn-signal

 

Attach a CREATIONPOLICY

 

 

Exam question:

 

what to do if the wait condition hasn’t received the required number of signals back from an EC2 instance?

 

1. Ensure the AMI image you used has the CF helper scripts installed. (you can also download them to the instance) – check this first!

 

2. Verify that cfn-init and cfn-signal have run ok on the instance, check the logs at /var/log/cloud-init.log or cfn-init.log

 

retrieve the logs by logging into the instance, but!

 

make sure you DISABLE ROLLBACK ON FAILURE else CloudFormation deletes the EC2 after your stack fails to create!

 

3. Ensure the EC2 has a connection to the internet – via a NAT device if on a private subnet, or via IGW if on a public subnet

 

 

Nested Stacks

 

 

these are stacks that are repeated patterns or common components for other stacks that you can reuse to avoid having to rewrite code each time.

 

eg a load balancer config that is often used, or a security group config that is often deployed.

 

exam question: remember you never alter or update or configure the nested stack, only the PARENT stack.

 

To update a stack, use ChangeSets

 

But – exam q: ChangeSets do NOT tell you if the update will work!

 

To declare a nested stack:

 

first, in your nestedstacks yaml file, declare the Resource type AWS::CloudFormation::Stack – this is essential to create the stack as a “nested stack” type. You give this resource a name eg

 

Resources:
myStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL:
https://s3.amazonaws.com/<the file name of the template (can be yaml or json>

 

 

When you click on create stack – you have to confirm that you might be creating iam resources with custom names, and that it might require the CAPABILITY_AUTO_EXPAND

 

– this means CF will expand the nested stack into other stacks if you invoke it.

 

 

confirm these two and click on Create stack…

 

 

 

CloudFormation Drift

 

This allows you to protect your CF infra from manual config changes

 

CF Drift tracks the changes made manually so you can check them

 

Retaining Data: Deletion Policy for any resource

 

eg DeletionPolicy =

 

= Retain – you specify which resource to preserve or backup

 

= Snapshot – for EBS, Elasticache, RDS, Redshift

 

= delete – this is the default – to delete s3 bucket the bucket must first be empty! – remember this for exam!

 

you can set max concurrent actions and failure tolerance level as well

 

 

Termination Protection for CloudFormation

 

 

Very Important when using CF:

 

Termination Protection – this protects your CF stack from being inadvertently deleted

 

 How to control who can change termination protection on stacks.

 

To enable or disable termination protection on stacks, a user requires permission to perform the cloudformation:UpdateTerminationProtection action.

 

Here is an example of how to allow users to enable or disable termination protection on stacks:

 

{
     “Version”:”2012-10-17″,
     “Statement”:[

     {
     “Effect”:”Allow”, 
     “Action”:[“cloudformation:UpdateTerminationProtection”
      ],
     “Resource”:”*”
     }]
}

 

ASG Creation Policy and
ASG Update Policy – need to know these for the exam!

 

“depends on” – waits for another action to complete first

 

StackPolicy – enables you to enable/deny certain actions from being made.

 

StackSets

 

 

CloudFormation StackSets are used to create update or delete stacks across multiple accounts and regions via single operation..

 

Very useful for maintaining CF stacks across multiple regions and accounts.

 

 

The admin account must first create the stackset

 

a trusted account can then create update or delete the stackset

 

when updating – all associated stack instances are updated across all accounts and regions

 

You can set a maximum concurrent actions on targets (either #number  or a %)

 

Important: because StackSets operate across multiple accounts,  you must first create the necessary IAM permissions before you can use them. 

 

Determine which AWS account is the administrator account – because the Stacksets are created using this account. The target account will then be the account in which you create the individual stacks which belong to the Stackset.

 

Decide how you want to set the permissions for the Stacksets.. easiest is where you give ALL users and groups permission to create and update all Stacksets. But you may want to restrict this, by specifying specific users and groups, and the resources they can include in their Stacksets and which Stackset operations they are permitted to perform.

 

Then create the necessary IAM services roles in your admin and target accounts to define these chosen permissions.

 

There is a CF pre-defined template that can create a set of IAM permissions for this task to make it easier.

 

CloudFormation will then go ahead and create these permissions in IAM for you  when you run it.

 

 

 

How CloudFormation Rollbacks Work

 

If the stack creation fails:

 

then the default is for everything to be rolled back, ie deleted. Check the logs.

 

remember you have the option to disable this rollback and then troubleshoot exactly where it went wrong.

 

if the stack update fails:

 

then the stack automatically rolls back to the previous known working stage, you can check in the logs and error messages for what went wrong.

 

 

Some CloudFormation CLI Command Examples

 

 

Two AWS CLI commands to display information about your CloudFormation stacks:

 

aws cloudformation list-stacks and

 

aws cloudformation describe-stacks

 

 

 

Creating a Stack

 

aws cloudformation create-stack –stack-name example –template-body file://templates/single-instance.yml –parameters file://parameters/single-instance.json

 

To create the change set, example:

 

aws cloudformation create-change-set –stack-name example –template-body file://templates/instance-and-route53.yml –parameters file://parameters/instance-and-route53.json –change-set-name changeset-1

 

 

Listing the Stack Resources

 

After running the aws cloudformation create-stack command, you can list the stack’s resources by running the aws cloudformation list-stack-resources command.

 

 

This displays a summary of each resource in the stack specified with the –stack-name parameter – including a summary of the stack and the creation or deletion status.

 

 

Updating a Stack

 

 

for example:

 

aws cloudformation update-stack –stack-name example –template-body file://templates/instance-and-route53.yml –parameters file://parameters/instance-and-route53.json

 

Check the status of the stack with the AWS CloudFormation console via the Events tab.

 

aws cloudformation execute-change-set –stack-name example –change-set-name changeset-1

 

Alternatively you can execute the Change Set from the CloudFormation console. However, the CLI execute-change-set method shows you the Change Set was applied and so gives you a clear audit trail.

 

 

Deleting Stacks

 

this can be done from the dashboard as well as from the CLI, example:

 

aws cloudformation delete-stack –stack-name <name of stack>

 

 

 

 

Managing events with CloudFormation and EventBridge

 

CloudFormation can send events to EventBridge whenever a create, update, delete, or drift-detection action takes place on your stack.

 

Unlike for other destinations, you don’t need to select which event types you want to track.

 

You can use EventBridge rules to route events to your defined targets.

 

 

Continue Reading