In mid-September, AWS released a big update to CloudFormation.

The update contained:

YAML Support – You can now write your CloudFormation templates in YAML.

– You can now write your CloudFormation templates in YAML. Cross Stack References – You can now export values from one stack and use them in another.

– You can now export values from one stack and use them in another. Simplified Substitution – You can more easily embed variables in strings.

After one month of using the new features, I want to share my learnings with you.

YAML Support

During the last 4 weeks I discovered three main advantages of using YAML over JSON to describe my CloudFormation templates:

Support for multi-line strings It is possible to use comments within a template YAML is more compact than JSON

Let me explain them in more detail.

Support for multi-line strings

The UserData property usually consists of many lines. In JSON there was no elegant way to express this. Instead, you used the Fn::Join function of CloudFormation.

{

"Resources" : {

"MyLC" : {

"Type" : "AWS::AutoScaling::LaunchConfiguration" ,

"Properties" :

"UserData" : { "Fn::Join" : [ "

" ], [

"#!/bin/bash -x" ,

"/opt/aws/bin/cfn-init -v --stack my-stack --resource MyLC --region eu-west-1" ,

"/opt/aws/bin/cfn-signal -e $? --stack my-stac --resource MyASG --region eu-west-1"

]}

}

}

}

}



In YAML this looks much nicer:



Resources:

MyLC:

Type: 'AWS::AutoScaling::LaunchConfiguration'

Properties:

UserData: !Base64 |

#!/bin/bash -x

/opt/aws/bin/cfn-init -v --stack my-stack --resource MyLC --region eu-west-1

/opt/aws/bin/cfn-signal -e $? --stack my-stack --resource MyASG --region eu-west-1



In YAML you can add comments.



Resources:

MyLC:

Type: 'AWS::AutoScaling::LaunchConfiguration'

Properties:



UserData: !Base64 |

#!/bin/bash -x

/opt/aws/bin/cfn-init -v --stack my-stack --resource MyLC --region eu-west-1

/opt/aws/bin/cfn-signal -e $? --stack my-stack --resource MyASG --region eu-west-1



Nothing fancy, but very helpful :)

YAML is more compact than JSON

I converted all our Free Templates for AWS CloudFormation from JSON to YAML. See how the number of lines changed:

template JSON lines YAML lines ec2/ec2-auto-recovery 460 403 (-13%) jenkins/jenkins2-ha-agents 1636 1599 (-3%) jenkins/jenkins2-ha 747 656 (-13%) security/account-password-policy 160 161 (+0%) security/cloudtrail 134 101 (-25%) security/config 92 77 (-17%) static-website/static-website 147 183 (+24%) vpc/vpc-2azs 289 253 (-13%) vpc/vpc-3azs 356 306 (-15%) vpc/vpc-4azs 423 359 (-16%) vpc/vpc-nat-gateway 39 51 (+30%) vpc/vpc-nat-instance 518 446 (-14%) wordpress/wordpress-ha 670 602 (-11%)

On average the templates get smaller.

Ouch

What I do not like is that there is more than one way to represent strings:

Sometimes you need quotes; sometimes they are optional

Sometimes you need single quotes; sometimes you can use double quotes

The rules seem to be more complicated than just using double quotes all the time like in JSON. I finally ended up with using single quotes all the time unless the string contains only [a-zA-Z0-9]. However, that is just my personal style. It ends up in a total mess if multiple people work on a single template.

Cross Stack References

Instead of putting everything in a single template it can make sense to split them up. One very common example is the VPC. You create one CloudFormation stack that contains your VPC. Each application that you run is also a stack, but they depend on the VPC stack. Before Cross Stack References you could solve this problem with Parameters.

Application template

{

"AWSTemplateFormatVersion" : "2010-09-09" ,

"Parameters" : {

"Subnet" : {

"Description" : "Use Subnet output from vpc stack." ,

"Type" : "AWS::EC2::Subnet::Id"

}

},

"Resources" : {

"VirtualMachine" : {

"Type" : "AWS::EC2::Instance" ,

"Properties" : {

"SubnetId" : { "Ref" : "Subnet" },

}

}

}

}



with Cross Stack References you can export values in one stack and import them in another stack. Let’s see how this works.

VPC template



AWSTemplateFormatVersion: '2010-09-09'

Resources:

VPC:

Type: 'AWS::EC2::VPC'

Properties:

CidrBlock: !Sub '10.0.0.0/16'

SubnetAPublic:

Type: 'AWS::EC2::Subnet'

Properties:

AvailabilityZone: !Select [0, !GetAZs '' ]

CidrBlock: '10.0.0.0/20'

VpcId: !Ref VPC



Outputs:

Subnet:

Description: 'Subnet.'

Value: !Ref SubnetAPublic

Export:

Name: 'vpc-subnet'

