DEV Community

Daniel Kim
Daniel Kim

Posted on

Using cfn-lint to validate your CloudFormation template

If you've used CloudFormation before you'll already know about the validate-template command on AWS CLI. If you've used this command before, you might also know that this validator only checks the syntax of your template. I can think of countless cases where my deployments failed due to a simple mistake that wasn't caught by this validator. This post will use a simple CloudFormation template to explain how cfn-lint can help you identify various errors in your stack before deploying it.

Sections

Example Template Setup

AWSTemplateFormatVersion: "2010-09-09"
Description: Example template
Parameters:
  Environment:
    Type: String
    Default: 'dev'
Conditions:
  IsDev: !Equals [ !Ref Environment, 'dev' ]
Resources:
  Function:
    Type: AWS::Lambda::Function
    Condition: IsDev
    Properties:
      Role: !Ref FunctionRole # Role property requires an ARN, not the resource ID
      Handler: index.handler
      Code:
        S3Bucket: my-bucket
        S3Key: function.zip
      MemorySize: 3000 # Invalid memory size
      Runtime: nodejs12.x
      Timeout: 5
      TracingConfig:
        Mode: !If [IsTracingActive, 'true', 'false'] # Undefined condition IsTracingActive
  FunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Policies:
        - PolicyName: all
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: '*'
                Resource: '*'
Outputs:
  FunctionArn: # Export without matching condition to resource
    Description: Lambda ARN
    Value: !GetAtt Function.Arn
    Export:
      Name: !Sub ${Environment}-lambda-arn

This is the template that we'll use to test cfn-lint. It sets up a simple Lambda function with an IAM role and the lambda ARN is exported as an output. Before we start, let's highlight some of the issues with this template:

  1. Role property on the lambda is not an ARN. Running a Ref on an IAM role will return the logical ID of the role.

  2. MemorySize of 3000 is invalid. Lambda memory size can range from 128 MB to 3008 MB in 64 MB increments.

  3. Condition IsTracingActive is undefined.

  4. LambdaFunction is only deployed when the condition IsDev is true, but it's export does not have the condition defined.

Here's the output of the built-in validate-template command for this stack:

{
    "CapabilitiesReason": "The following resource(s) require capabilities: [AWS::IAM::Role]", 
    "Description": "Example template", 
    "Parameters": [
        {
            "DefaultValue": "dev", 
            "NoEcho": false, 
            "ParameterKey": "Environment"
        }
    ], 
    "Capabilities": [
        "CAPABILITY_IAM"
    ]
}

As you can see, the validator does not identify any issues with this stack. Deploying this stack however will result in a failure. Let's see what cfn-lint can do for us in the next section.

cfn-lint Usage

cfn-lint is a command line tool which examines your CloudFormation template and returns various suggestions. Let's run this tool and see what it has to say about our example stack.

> cfn-lint template.yml

E3008 Property "Role" has no valid Refs to Resources at Resources/Function/Properties/Role/Ref
template.yml:14:7

E2530 You must specify a value that is greater than or equal to 128, and it must be a multiple of 64. You cannot specify a size larger than 3008. Error at Resources/Function/Properties/MemorySize
template.yml:19:7

E8002 Condition IsTracingActive is not defined.
template.yml:23:9

W1001 GetAtt to resource "Function" that may not be available when condition "IsDev" is False at Outputs/FunctionArn/Value/Fn::GetAtt
template.yml:47:5

As you can see, cfn-lint output covers all 4 issues that we previously highlighted in the form of warnings and errors. Errors indicate issues that will prevent your CloudFormation stack from deploying, and warnings indicate potential issues in your stack that you might want to think about.

It's worth noting that not all warnings are necessarily highlighting an issue that you must fix. Everything depends on the context. If you wish to ignore warnings from the output, you can use the ignore_checks argument:

> cfn-lint template.yml -i W

cfn-lint also comes with extensive configuration support which allows you to customise your linting rules.

For a complete set of commands and installation guides, please refer to the github repository.

Conclusion

We looked at how cfn-lint can be used as an additional validator for our CloudFormation templates. It provides a way to check the semantics of our templates and helps us catch mistakes before making a deployment. Some of the CI pipelines that I work on uses cfn-lint to decide whether the deployment step should execute. I hope this tool can help you iterate quicker and make your CloudFormation development experience a bit more enjoyable.

Top comments (1)

Collapse
 
starpebble profile image
starpebble

Way to raise our automation potential. Sometimes editing CloudFormation is icky. The slightest CloudFormation mistep can stop a deployment. It's silly. cfn-lint looks like the next best thing to a deployment simulator.