How to use cfn-lint and cfn-nag to verify CloudFormation templates
You can download this article in PDF format via the link below to support us.
Download the guide in PDF formatturn off
This article guides readers how to use the cfn-lint and cfn-nag tools to verify their CloudFormation templates. It also explains how to create a pipeline for validating CloudFormation templates and deploying them to CloudFormation.
The good practice of DevOps is to always include steps to check our code/template for safety and syntax errors. Likewise, in our case, it allows us to avoid pipeline failures due to syntax errors.
Requirements/prerequisites
- An AWS account.
- A user is created on the account, and the user has permission to provision resources on the account.
- A CodeCommit repository containing your buildspec.yml and CloudFormation templates to verify.
buildspec.yml directory
The buildspec.yml file uploaded in our CodeCommit repository should contain the following code.
First, it will install the cfn-lint and cfn-nag tools. Then, it uses these two tools to check CloudFormation templates.
version: 0.2
phases:
install:
runtime-versions:
ruby: 2.6
commands:
- pip3 install awscli --upgrade --quiet
- pip3 install cfn-lint --quiet
- apt-get install jq git -y -q
- gem install cfn-nag
build:
commands:
- cd ./
- cfn-lint ECR.yaml
- cfn_nag_scan -i ECR.yaml
where ECR.yaml It should be replaced with the name of the template you want to verify. Your cloudformation template must be uploaded to the CodeCommit repository.
CloudFormation cfn-lint
Use cfn-lint to enable syntax error checking on CloudFormation templates. To check the template, run the following command. Suppose our template is written in YAML format.
cfn-lint templatename.yaml
CloudFormation CFN-NAG
The cfn-nag tool is used for security checks. It checks whether there is any insecure infrastructure in the CloudFormation template, such as a security group that allows everyone to access. To check the template, run the following command. Suppose our template is written in YAML format.
cfn_nag_scan -i template.yaml
Create a CodeBuild project
Before deploying it to CloudFormation, we will create a CodeBuild project to check and validate CloudFormation templates. We will use the CloudFormation template below to create our build project.
AWSTemplateFormatVersion: "2010-09-09"
Description: "Template to create codebuild Project"
Parameters:
ProjectName:
Type: String
Description: The CodeBuild Project Name
Default: Validate-CF-Template
CodeBuildRole:
Type: String
Description: The name codebuild role
Default: CodeBuild-ValidateCF
Resources:
IAMRole:
Type: 'AWS::IAM::Role'
Properties:
Description: The CodeBuild Validate CF Template Role
RoleName: !Ref CodeBuildRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- codebuild.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
- arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref CodeBuildRole
BuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: !Ref ProjectName
Description: build project to validate our CF Template
ServiceRole: !Ref IAMRole
Artifacts:
Type: NO_ARTIFACTS
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:4.0
PrivilegedMode: true
Source:
Location: https://git-codecommit.eu-central-1.amazonaws.com/v1/repos/test-lint
Type: CODECOMMIT
BuildSpec: buildspec.yml
TimeoutInMinutes: 15
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref ProjectName
Outputs:
Project:
Description: The codebuild build project
Value: !Ref ProjectName
Export:
Name: "BuildProject"
Value: !Ref ProjectName
First, the template first provides the CodeBuild role. Then, it creates the build project.
N/B: Users should customize the template. The names of resources, attributes and tags should meet the specific requirements of the user.
When you run the build project, you will get the following output:Build project results
After the template is validated, we will get results showing any failures or warnings. My template has no syntax or security errors, but there is 1 warning.
If we fail, the build project will fail. For example, if there is a syntax error on the template. See the results below.Result of failed project creation
Create a CodePipeline to deploy the template to CloudFormation
We can add the above build project to the pipeline to deploy our CloudFormation template. Use the following template to create a pipeline that validates your CloudFormation template and deploys it to CloudFormation for resource allocation.
AWSTemplateFormatVersion: "2010-09-09"
Description: "Template to create codepipeline"
Parameters:
PipelineName:
Type: String
Description: The CodePipeline Name
Default: Deploy-to-CloudFormation
Stack:
Type: String
Description: The Cloudformation Stack Name
Default: eu-central-1-create-ECR-Stack
PipelineRole:
Type: String
Description: The Cloudformation Deploy Role Name
Default: codepipeline-ECR
CFRole:
Type: String
Description: The CodePipeline Role Name
Default: codepipeline-cloudformation
CWEventsRole:
Type: String
Description: The Cloudwatch Events Role Name
Default: codepipeline-cwevents
BucketName:
Type: String
Description: The vpc where our bastion hosts will be located
Default: maureen-test-cp
Resources:
S3:
Type: AWS::S3::Bucket
Properties:
AccessControl: Private
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
BucketName: !Ref BucketName
PublicAccessBlockConfiguration:
BlockPublicAcls: TRUE
BlockPublicPolicy: TRUE
IgnorePublicAcls: TRUE
RestrictPublicBuckets: TRUE
VersioningConfiguration:
Status: Enabled
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref BucketName
CodePipelineRole:
Type: 'AWS::IAM::Role'
Properties:
Description: The CodeBuild Validate CF Template Role
RoleName: !Ref PipelineRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- "codepipeline.amazonaws.com"
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: root
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'iam:PassRole'
Resource: '*'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AWSCodePipeline_FullAccess
- arn:aws:iam::aws:policy/AWSCodeCommitFullAccess
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/AWSCodeBuildAdminAccess
- arn:aws:iam::aws:policy/AWSCodeDeployFullAccess
- arn:aws:iam::aws:policy/AWSCloudFormationFullAccess
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref PipelineRole
CloudFormationRole:
Type: 'AWS::IAM::Role'
Properties:
Description: The CodeBuild Validate CF Template Role
RoleName: !Ref CFRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- "cloudformation.amazonaws.com"
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonS3FullAccess
- arn:aws:iam::aws:policy/PowerUserAccess
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref CFRole
AmazonCloudWatchEventRole:
Type: 'AWS::IAM::Role'
Properties:
Description: The CodeBuild Validate CF Template Role
RoleName: !Ref CWEventsRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- "events.amazonaws.com"
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: root
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 'codepipeline:StartPipelineExecution'
Resource: !Join [ '', [ 'arn:aws:codepipeline:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref DeployPipeline ] ]
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref CWEventsRole
AmazonCloudWatchEventRule:
Type: AWS::Events::Rule
Properties:
EventPattern:
source:
- aws.codecommit
detail-type:
- 'CodeCommit Repository State Change'
resources:
- arn:aws:codecommit:eu-central-1:429758582529:test-lint
detail:
event:
- referenceCreated
- referenceUpdated
referenceType:
- branch
referenceName:
- master
Targets:
-
Arn:
!Join [ '', [ 'arn:aws:codepipeline:', !Ref 'AWS::Region', ':', !Ref 'AWS::AccountId', ':', !Ref DeployPipeline ] ]
RoleArn: !GetAtt AmazonCloudWatchEventRole.Arn
Id: codepipeline-DeployPipeline
DeployPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
RoleArn: !GetAtt CodePipelineRole.Arn
Name: !Ref PipelineName
ArtifactStore:
Location: !Ref S3
Type: S3
Stages:
-
Name: Source
Actions:
-
Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Version: 1
Provider: CodeCommit
OutputArtifacts:
-
Name: SourceArtifact
Configuration:
RepositoryName: test-lint
BranchName: master
PollForSourceChanges: false
RunOrder: 1
-
Name: Build
Actions:
-
Name: BuildAction
InputArtifacts:
- Name: SourceArtifact
ActionTypeId:
Category: Build
Owner: AWS
Version: 1
Provider: CodeBuild
Configuration:
ProjectName: !ImportValue BuildProject
BatchEnabled: 'false'
OutputArtifacts: []
RunOrder: 1
-
Name: Deploy
Actions:
-
Name: DeployAction
InputArtifacts:
- Name: SourceArtifact
ActionTypeId:
Category: Deploy
Owner: AWS
Version: 1
Provider: CloudFormation
Configuration:
ActionMode: CREATE_UPDATE
StackName: !Ref Stack
Capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM
RoleArn: !GetAtt CloudFormationRole.Arn
TemplatePath: "SourceArtifact::ECR.yaml"
RunOrder: 1
Tags:
-
Key: "Project"
Value: "test-blog"
-
Key: "Environment"
Value: "test"
-
Key: "createdBy"
Value: "Maureen Barasa"
-
Key: "Name"
Value: !Ref PipelineName
The template first provides an S3 bucket to upload our CodePipeline artifacts. Then, it created three roles. CodePipeline role assumed by CodePipeline, CloudFormation role and CloudWatch event role to be used in the deployment phase. CloudWatch event rules use the CloudWatch event role to monitor changes in the CodeCommit repository and trigger the pipeline to start.
Finally, the template provides the pipeline. The pipeline is divided into three stages. Source, build and deploy. Upload code from CodeCommit in the source code phase. The build phase uses the build project to validate our CloudFormation template. The last is the deployment phase, where the template is deployed to CloudFormation.
N/B: Users should customize the template. The names of resources, attributes and tags should meet the specific requirements of the user.
CodePipeline
Important link
Other AWS guidelines:
- How to set up AWS VPC network using CloudFormation
- Use CloudFormation to create and configure AWS Application Load Balancer
- Create Amazon DocumentDB (MongoDB) database on AWS
Happy Building! ! !
You can download this article in PDF format via the link below to support us.
Download the guide in PDF formatturn off