AWS Config rules allow you to determine if a resource is compliant or not. Previously when you wanted to do custom checks you needed to write AWS Lambda functions to validate the configuration of a resource. Since Aug 2, 2022 you have the ability to use cfn-guard rules to achieve the same.
Why should I use cfn-guard
Writing a Lambda function is not difficult. But it becomes harder when you add unit testing. When you determine your compliancy status based on Lambda function, you want to ensure that it works as intended. This is the advantage of cfn-guard
, you write a rule and you write some tests. These tests are a couple of snippets of yaml and per snippet you define if your rule should: PASS
, FAIL
or SKIP
.
The other advantage of cfn-guard
is that you have a single way of writing rules. On Nov 8, 2022 I gave a talk on this topic on the AWS User Group NL. In this talk I highlighted the differences between detective and preventive controls. Using cfn-guard
rules in AWS Config is a detective control. But the same language can be used to build preventive controls!
Yes, I said language and not rules
It turns out that the rules written for AWS Config cannot be used to validate AWS CloudFormation templates. They are similar but different!
Where an AWS Config rule has the following structure:
{
"version": "1.3",
"arn": "arn:aws:s3:::aws-meetup-2022-11-08-noncompliantbucket-xxxxxxxxxxxxx",
"resourceType": "AWS::S3::Bucket",
"resourceId": "aws-meetup-2022-11-08-noncompliantbucket-xxxxxxxxxxxxx",
"resourceName": "aws-meetup-2022-11-08-noncompliantbucket-xxxxxxxxxxxxx",
"awsRegion": "eu-west-1",
"supplementaryConfiguration": {
"ServerSideEncryptionConfiguration": {
"rules": [
{ "applyServerSideEncryptionByDefault": {"sseAlgorithm": "aws:kms"} }
]
}
}
}
A CloudFormation template has the following structure:
{
"Resources": {
"NonCompliantBucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketEncryption": {
"ServerSideEncryptionConfiguration": [
{
"ServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms"
}
}
]
}
}
},
"OtherResource": { ... }
}
}
The first thing that you can see is that the AWS Config rule only has the context of the resource it validates. While the CloudFormation template has one or more resources. So you can compare the to locations as followed:
supplementaryConfiguration
vs Resources > NonCompliantBucket > Properties
But looking closer you also notice that the structure and naming varies. Meaning you are doomed to maintain 2 types of rules. 1 for AWS Config (Detective) and 1 for CloudFormation (Preventive).
Why should you write a detective and a preventive rule?
The answer is to decrease your feedback cycle. For example, when you only have a detective rule you need to wait until the everything is deployed. Then you need to wait until a compliance issue pops up. When you use a preventive rule you can check this on different levels:
- You can run the
cfn-guard
rules at any time on your local development environment. - You can use a
pre-commit
hook, this will prevent you from committing non-compliant code. - You can run it during your Continuous Integration step. This prevents merging non-compliant code in your develop/main branches.
- You can run it before deployment to testing, acceptance and/or production.
Conclusion
cfn-guard
is a great tool to write compliancy checks for both detective and preventive controls. Interested in a working sample? I published my demo material to the Nr18/aws-meetup-2022-11-08 GitHub repository.
Photo by Joshua Miranda