Skip to main content

Validate Cloud Formation

Project description

CFN Check

A tool for checking CloudFormation

PyPI version License Contributor Covenant PyPI - Python Version

Package Cocoa
Version 0.1.0
Download https://pypi.org/project/cfn-check/
Source https://github.com/adalundhe/cfn-check
Keywords cloud-formation, testing, aws, cli

CFN-Check is a small, fast, friendly tool for validating AWS CloudFormation YAML templates. It is code-driven, with rules written as simple, Rule decorator wrapped python class methods for Rules-inheriting classes.


Why CFN-Check?

AWS has its own tools for validating Cloud Formation - cfn-lint and cfn-guard. cfn-check aims to solve problems inherint to cfn-lint more than cfn-guard, primarily:

  • Confusing, unclear syntax around rules configuration
  • Inability to parse non-resource wildcards
  • Inability to validate non-resource template data
  • Inabillity to use structured models to validate input

In comparison to cfn-guard, cfn-check is pure Python, thus avoiding YADSL (Yet Another DSL) headaches. It also proves significantly more configurable/modular/hackable as a result.

CFN-Check uses a combination of simple depth-first-search tree parsing, friendly cfn-lint like query syntax, Pydantic models, and pytest-like assert-driven checks to make validating your Cloud Formation easy while offering both CLI and Python API interfaces.


Getting Started

cfn-check requires:

  • Python 3.12
  • Any number of valid CloudFormation templates or a path to said templates.
  • A .py file containing at least one Rules class with at least one valid @Rule() decorated method

To get started (we recommend using uv), run:

uv venv
source .venv/bin/activate

uv pip install cfn-check

touch rules.py
touch template.yaml

Next open the rules.py file and create a basic Python class as below.

from cfn_check import Rules, Rule


class ValidateResourceType(Rules):

    @Rule(
        "Resources::*::Type",
        "It checks Resource::Type is correctly definined",
    )
    def validate_test(self, value: str): 
        assert value is not None, '❌ Resource Type not defined'
        assert isinstance(value, str), '❌ Resource Type not a string'

This provides us a basic rule set that validates that the Type field of our CloudFormation template(s) exists and is the correct data type.

[!NOTE] Don't worry about adding an __init__() method to this class!

Next open the template.yaml file and paste the following CloudFormation:

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  ExistingSecurityGroups:
    Type: List<AWS::EC2::SecurityGroup::Id>
  ExistingVPC:
    Type: AWS::EC2::VPC::Id
    Description: The VPC ID that includes the security groups in the ExistingSecurityGroups parameter.
  InstanceType:
    Type: String
    Default: t2.micro
    AllowedValues:
      - t2.micro
      - m1.small
Mappings:
  AWSInstanceType2Arch:
    t2.micro:
      Arch: HVM64
    m1.small:
      Arch: HVM64
  AWSRegionArch2AMI:
    us-east-1:
      HVM64: ami-0ff8a91507f77f867
      HVMG2: ami-0a584ac55a7631c0c
Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow HTTP traffic to the host
      VpcId: !Ref ExistingVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
  AllSecurityGroups:
    Type: Custom::Split
    Properties:
      ServiceToken: !GetAtt AppendItemToListFunction.Arn
      List: !Ref ExistingSecurityGroups
      AppendedItem: !Ref SecurityGroup
  AppendItemToListFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: !Join
          - ''
          - - var response = require('cfn-response');
            - exports.handler = function(event, context) {
            - '   var responseData = {Value: event.ResourceProperties.List};'
            - '   responseData.Value.push(event.ResourceProperties.AppendedItem);'
            - '   response.send(event, context, response.SUCCESS, responseData);'
            - '};'
      Runtime: nodejs20.x
  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !FindInMap
        - AWSRegionArch2AMI
        - !Ref AWS::Region
        - !FindInMap
          - AWSInstanceType2Arch
          - !Ref InstanceType
          - Arch
      SecurityGroupIds: !GetAtt AllSecurityGroups.Value
      InstanceType: !Ref InstanceType
  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:*
                Resource: arn:aws:logs:*:*:*
Outputs:
  AllSecurityGroups:
    Description: Security Groups that are associated with the EC2 instance
    Value: !Join
      - ', '
      - !GetAtt AllSecurityGroups.Value

This represents a basic configuration for an AWS Lambda function.

Finally, run:

cfn-lint validate -r rules.py template.yaml

which outputs:

2025-09-17T01:46:41.542078+00:00 - INFO - 19783474 - /Users/adalundhe/Documents/Duckbill/cfn-check/cfn_check/cli/validate.py:validate.80 - ✅ 1 validations met for 1 templates

Congrats! You've just made the cloud a bit better place!

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cfn_check-0.1.1.tar.gz (13.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cfn_check-0.1.1-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file cfn_check-0.1.1.tar.gz.

File metadata

  • Download URL: cfn_check-0.1.1.tar.gz
  • Upload date:
  • Size: 13.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for cfn_check-0.1.1.tar.gz
Algorithm Hash digest
SHA256 f4fd8cafec18045dccbdf349a9a82426507d9b28f31c7df830d0044e9ce99665
MD5 89a634bdb6c06b2efa2a0b3039bea31b
BLAKE2b-256 6eb0341654364014b2ae01842930a83ca4ab5f3e7db737cd6467768d626c7cca

See more details on using hashes here.

File details

Details for the file cfn_check-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: cfn_check-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 15.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for cfn_check-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e235f1f9098b559816545f29e5a990b653cd9f3d0f8dc70562929ad3bf53c800
MD5 ef6ca052d342837e4b493d17fc9656f5
BLAKE2b-256 0218f98c80003af29bbdf5b001e972ea8e3eeb74334e23d5c98092db41ee4619

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page