AWS CloudFormation Linter (cfn-lint)

repository·main·Indexed 25 days ago

https://github.com/aws-cloudformation/cfn-lint

cfn-lint validates AWS CloudFormation YAML and JSON templates against official AWS resource provider schemas and best practices. It checks for valid resource properties, provides feedback on potential issues, and supports custom rule creation. The tool can be used via a command line interface, integrated into Python codebases via its API, or run using Docker. It supports configuration through CLI parameters, .cfnlintrc files, and template metadata.

Tokens
21.5K
Snippets
42
Records
140
Agent score
82%

What's inside cfn-lint

  1. Understand Rule Levels in cfn-lint

    main

    Rules in cfn-lint return feedback categorized into three levels. Each level is identified by a specific prefix in its ID:

    • Errors (E): These indicate issues that may result in a hard failure for the template validation.
    • Warnings (W): These alert you when a template deviates from best practices but is still expected to function (e.g., missing NoEcho: true on an RDS master password parameter).
    • Informational (I): These alert you to best practice deviations in a non-blocking way. Informational results are disabled by default.
  2. How cfn-lint handles Intrinsic Functions and NoValue

    main

    To ensure accurate validation of CloudFormation-specific logic, cfn-lint implements the following:

    • Intrinsic Function Validation: cfn-lint validates the structure of intrinsic functions (like Ref, GetAtt, etc.). When possible, it resolves the function value (e.g., resolving {"Ref": "AWS::Region"} to us-east-1) and validates the resulting value against the resource schema.
    • Handling AWS:NoValue: When a property is set to {"Ref": "AWS:NoValue"}, cfn-lint treats it as if the property were not specified. This ensures that object and array validators (like required properties or dependencies) function correctly by cleaning these 'no value' entries before validation.
  3. Understand how cfn-lint handles CloudFormation Conditions

    main
    CloudFormation Conditions allow you to create multiple scenarios within a single template. Because cfn-lint does not use specific parameter values to determine template validity, it attempts to validate all possible scenarios created by your conditions. This ensures that your template is valid regardless of which condition branch is taken during deployment.
  4. Understand the `format` keyword in cfn-lint

    main
    In cfn-lint, the format keyword (extended from JSON Schema) is used to validate that a string value adheres to specific AWS resource patterns or constraints. While standard JSON Schema uses format for general patterns, cfn-lint provides custom AWS-specific formats to ensure CloudFormation templates contain valid resource identifiers, ARNs, and names.
  5. Understand cfn-lint configuration precedence

    main

    When multiple configuration sources are used, cfn-lint applies them in a specific order. Higher levels override lower levels:

    1. CLI parameters (Highest precedence)
    2. Template Metadata configurations
    3. cfnlintrc configurations (Lowest precedence)
  6. Integrate cfn-lint with pre-commit

    main

    To run cfn-lint automatically during Git commits, add it to your .pre-commit-config.yaml.

    If you want to restrict linting to specific files, use the cfn-lint hook with a files regex. If you prefer using a .cfnlintrc configuration file to manage which templates are scanned or ignored, use the cfn-lint-rc hook instead.

    Warning: Avoid mixing .cfnlintrc ignore_templates with the files: option in .pre-commit-config.yaml, as this may cause 'file not found' errors.

    # Option 1: Standard hook with file filtering
    repos:
      - repo: https://github.com/aws-cloudformation/cfn-lint
        rev: v1.53.3
        hooks:
          - id: cfn-lint
            files: path/to/cfn/dir/.*\.(json|yml|yaml)$
    
    # Option 2: Using .cfnlintrc configuration
    repos:
      - repo: https://github.com/aws-cloudformation/cfn-lint
        rev: v1.53.3
        hooks:
          - id: cfn-lint-rc
  7. Update cfn-lint resource schemas

    main

    To ensure the linter uses the most up-to-date resource schemas for accurate validation, you can manually trigger a download of the latest schemas. This downloads the schemas-cfn-lint.zip artifact from the resource-provider-enhanced-schemas repository and extracts it into the local data directories. These directories are gitignored and managed at runtime.

    cfn-lint --update-specs
  8. Run cfn-lint using Docker

    main

    To use cfn-lint with Docker, follow these two steps:

    1. Build the image from the source tree:
    docker build --tag cfn-lint:latest .
    1. Run the container against a template in your current directory by mounting the current path to /data:
    docker run --rm -v `pwd`:/data cfn-lint:latest /data/template.yaml
  9. Implement a custom CloudFormationLintRule

    main

    To create a new rule for cfn-lint, inherit from the CloudFormationLintRule class. A rule must be a standalone Python class and include specific metadata attributes. Because cfn-lint loads rules as plugins from the rules folder, the filename and the Class name must match (e.g., mynewrule.py must contain class MyNewRule).

    Required metadata attributes:

    • id: The unique Rule ID.
    • shortdesc: A short description.
    • description: A long description.
    • source_url: A URL to documentation or references.
    • tags: A list of strings for searching.

    The core logic resides in the match(self, cfn) method, which must return a list of RuleMatch objects.

    from cfnlint.rules import CloudFormationLintRule
    from cfnlint.rules import RuleMatch
    
    
    class MyNewRule(CloudFormationLintRule):
        id = '' # New Rule ID
        shortdesc = '' # A short description about the rule
        description = '' # (Longer) description about the rule
        source_url = '' # A url to the source of the rule
        tags = [] # A set of tags (strings) for searching
    
        def match(self, cfn):
            """Basic Rule Matching"""
            matches = []
            # Your Rule code goes here
            return matches
  10. Create custom rules for cfn-lint

    main

    Custom rules allow you to define validation logic using a pre-defined set of operators to check resource properties. Each rule must be on a single line and follows this syntax:

    <Resource Type> <Property[*]> <Operator> <Value> [Error Level] [Custom Error Message]

    Syntax Components

    • Resource Type: The AWS resource type (e.g., AWS::EC2::Instance).
    • Property: The resource property to check. Use dot notation for nested properties (e.g., AssumeRolePolicyDocument.Version).
    • Operator: The comparison logic (see Operator Reference).
    • Value: The value to compare against. Supports multi-word strings and arrays (e.g., [Apples, Oranges]).
    • Error Level (Optional): The severity of the breach (e.g., ERROR or WARN).
    • Custom Error Message (Optional): A message to override the default fallback. Note: You must specify an Error Level if you want to use a custom error message.

    General Guidelines

    • Rule IDs: IDs are auto-generated based on the line number in the rules file. Custom rules use the E9XXX (for ERROR) and W9XXX (for WARN) blocks.
    • Comments: Use the # symbol at the start of a line to add comments.
    • Quote Flexibility: Values can be quoted or unquoted (e.g., EQUALS "Value" or EQUALS Value).
    AWS::EC2::Instance InstanceType != "p3.2xlarge"
    AWS::Lambda::Function Environment.Variables.NODE_ENV IS DEFINED