Validate Cloud Formation
Project description
CFN Check
A tool for checking CloudFormation
| 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
.pyfile containing at least oneRulesclass 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f4fd8cafec18045dccbdf349a9a82426507d9b28f31c7df830d0044e9ce99665
|
|
| MD5 |
89a634bdb6c06b2efa2a0b3039bea31b
|
|
| BLAKE2b-256 |
6eb0341654364014b2ae01842930a83ca4ab5f3e7db737cd6467768d626c7cca
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e235f1f9098b559816545f29e5a990b653cd9f3d0f8dc70562929ad3bf53c800
|
|
| MD5 |
ef6ca052d342837e4b493d17fc9656f5
|
|
| BLAKE2b-256 |
0218f98c80003af29bbdf5b001e972ea8e3eeb74334e23d5c98092db41ee4619
|