Validating CloudFormation Templates With cfn-lint

I’ve been working with CloudFormation in some form for about five years now. Two years ago at Time Out, I helped write an in-house tool that performed some basic template linting. One year ago at Genus AI, I started using the AWS Labs tool cfn-lint to validate my templates before deployment. It’s really neat, covers a lot more than our in-house tool did, and has saved me from a number of mistakes.

Here’s my review!

More Like SlowFormation

Editing and testing a CloudFormation template can come with a slow feedback cycle. Creating and deleting resources can take anywhere from a few seconds (such as SNS topics) to a soul-sucking 30 minutes (CloudFront, I’m looking at you!). There’s a limit to how many tea breaks you can take! Anything you can do to pre-validate your templates is totally worth it.

One tool that CloudFormation provides for this is the ValidateTemplate API. Unfortunately it’s not particularly strict.

Many CloudFormation resources act like thin wrappers around the underlying service API’s. ValidateTemplate seems to only check the template generally, maybe against the resource specification. This means it often misses extra constraints that exist only in the service API’s, such as which instance types RDS allows for a given database engine.

Thus only a subset of “validated” templates are actually valid.

Enough Fluff, Show Me the Lint

cfn-lint to the rescue! Besides checking against the resource specification, it also implements many per-resource rules. These try to cover the most common of the underlying service constraints, but also help encode some best practices.

For example, some rules that cover underlying service constraints:

Rule E2530 checks that Lambda functions have correctly configured memory sizes.

checks that Lambda functions have correctly configured memory sizes. Rule E3013 checks that CloudFront aliases are valid domain names.

checks that CloudFront aliases are valid domain names. Rule E3025 checks that your RDS instances use correct instance types for the database engine.

And some rules that cover best practices:

Rule W2001 checks that each parameter is used at least once.

checks that each parameter is used at least once. Rule W2509 checks that if you use a parameter as a CIDR, you also added parameter validation that it looks like a CIDR. This helps keep your templates strict - I know I often don’t add parameter validation when I really should.

checks that if you use a parameter as a CIDR, you also added parameter validation that it looks like a CIDR. This helps keep your templates strict - I know I often don’t add parameter validation when I really should. Rule W2531 checks that you aren’t using outdated Lambda runtimes. This can alert you to the deprecation even if you don’t keep up with all the AWS news (hint: for that, subscribe to Last Week in AWS).

You can read the full list of rules here.

Some Usage Tips

First, I’d like to draw attention to the ability to ignore certain rules. Like most linters, cfn-lint flags the occasional false positive. The first time I had one, I panicked a bit. I started diving through the source code to eventually discover the ignore_checks metadata key was what I wanted. But then I found it’s right there in the README.

Second, keep it up to date. cfn-lint bundles its own copy of the resource specification, so if you’re not on the latest version, it won’t recognize legitimate new resources or properties. They’re also frequently adding new rules which will help you improve your templates.

I normally suggest to my clients they they update all their Python dependencies every two weeks, at least where feasible. cfn-lint is definitely one to have a plan for keeping updated.

Third, engage with the developers. I’ve often found one or two rough edges when upgrading. I think all of the issues I’ve opened got a response or a fix within a day or two. This turned into a virtuous cycle and I ended up able to fix some issues myself. So far I’ve made 25 issues/pull requests. A well run open source project! 🌟

Fourth, look into custom rules. You can use these to check something specific to your organization, for example ensuring every taggable resource has a tag called “Environment”. There isn’t much documentation on this apart from the description of the --append-rules flag, but there are some examples here.

Conclusion

As I’m sure you’ve gathered, I like cfn-lint. I recommend it to anyone using CloudFormation. I’ve had a very positive experience with it, and I haven’t seen any rules, just the occasional bug.

The biggest frustration for me is that it exists as a separate tool, rather than ongoing enhancements to ValidateTemplate (or similar). Many CloudFormation users are unlikely to use it, simply due to the effort of discovering and installing it.

Also if you use a template generator, such as Troposphere or AWS’s own CDK, you will probably get more false positives. I haven’t used either much, but from my limited experience, they don’t always output cfn-lint compatible templates.

Fin

Thanks for reading - I hope this review was useful for you,

—Adam

Working on a Django project? Check out my book Speed Up Your Django Tests which covers loads of best practices so you can write faster, more accurate tests.

Subscribe via RSS, Twitter, or email: Your email address:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: aws, cloudfront, cloudformation

© 2020 All rights reserved.