Recently I’ve been delving into CloudFormation, particularly writing templates. I often use a pretty minimal setup consisting of a devcontainer with an Ubuntu base image and Vim. One challenge I kept hitting, discovering errors only after triggering a deployment.
Now, I could use some editor like VSCode and add some plugins and it would help provide some feedback. But, that’s not how I roll, I needed some other way of getting feedback. Also, being frugal (cheap), if I can write a valid template and avoid deploying it and any associated costs, that’s a win!
The solution
I managed to find a few tools that I can use that together provide me with what I call a “dry-run” of a CloudFormation template. They all fit well with my command line focused workflow and are easy to use.
cfn-lint
This will check your template against the actual AWS resource structure. Basically it’s way to make sure your template uses the correct properties and valid values. This will catch most typos and other syntax errors.
It’s written in python, so you can install it using pip. Then it’s simple to use.
# you may want it in a virtual environmentpython3 -m venv .venvsource .venv/bin/activate
pip install cfn-lint
cfn-lint template.yamlvalidate-template
The CloudFormation API has a validate-template command. AWS will parse the file and ensure the overall schema and syntax is correct. This includes instrinsic functions eg: Fn::Sub or Fn::GetAtt. The difference here with cfn-lint is that cfn-lint runs checks locally (more checks) and validate-template runs against the actual AWS API. This confirms AWS understands your template.
You use the aws cli for this:
aws cloudformation validate-template --template-body file://template.yamlChange sets
To actually see what resources will be created then you can use a change set. CloudFormation will evaluate the template against your live AWS account. This can pick up issues like resource name conflicts or invalid IAM principals or malformed policy statements.
First you need to generate a preview. The --no-execute-changeset option is important to include for this.
aws cloudformation deploy \ --template-file template.yaml \ --stack-name my-dev-stack \ --no-execute-changesetThen you view the preview. The output of the above command will provide you another command to run to review the changes.
# otherwise you can do the following to get the changeset nameaws cloudformation list-change-sets --stack-name my-dev-stack
# Then, view the detailsaws cloudformation describe-change-set \ --stack-name my-dev-stack \ --change-set-name <your-change-set-name-or-arn>After this, you can choose to execute or delete the change-set.
# delete exampleaws cloudformation delete-change-set --change-set-name <change-set-name-or-arn>
# you will need to delete stack if it was a brand new oneaws cloudformation delete-stack --stack-name <my-stack-name>Limitations of this dry-run
Even if a change set is created successfully, it does not mean the deployment will succeed.
A couple of examples of issues (not-exhaustive) that can still arise at deployment time:
- The role that executes the deployment may not have necessary permissions so the deployment will fail.
- You reach a service quota limit. This could be an IAM role limit for the account or you’ve reached the limit for elastic IPs.
Whilst not perfect, I’ve found this dry-run a very welcome addition to my workflow when crafting CloudFormation templates.