logo
Menu
Use custom rules to validate your compliance

Use custom rules to validate your compliance

Learn how you can built custom rules to validate compliance in your AWS accounts, using AWS Config and cfn-guard.

Published Feb 3, 2024
Last Modified Mar 6, 2024
AWS has a lot of controls built in, but what if you need more? AWS Config allows you to create your own rules. These rules can then inspect your resources and determine if they are compliant. This is useful when you want to enforce certain configuration settings. Giving you an overview of how compliant your workloads are.
Let’s use a specific example, but you can apply this concept to other scenarios.

Check S3 access logs configuration

When an engineer creates an Amazon S3 bucket, they need to enable access logging on the bucket. AWS has a built-in config rule for this called s3-bucket-logging-enabled. When you enable the AWS Foundational Security Best Practices v1.0.0 standard in Security Hub it becomes available.
When we create a new account, part of the bootstrapping is the deployment of a bucket. The engineers who use the account only have read rights on this bucket. When an engineer creates a bucket, we expect him to use this bucket for the access logs.

Creating rules: Lambda vs CloudFormation Guard

You can build a custom config rules in 2 ways, using AWS Lambda and CloudFormation Guard. Lambda gives you a lot of flexibility, but it also brings complexity of maintaining. CloudFormation Guard is a bit more lightweight in that regard. Yes, you still need to maintain the logic to determine when your resource is compliant or not. But you need to do this in both cases, thus my go to preference is CloudFormation Guard.

Config Rule

When you start to define your custom config rule you need to think about the scenarios that happen:
  • When the resource is not an S3 bucket, we should skip the rule.
  • When the resource is the actual logging bucket, we should skip the rule.
  • When the resource does not have logging configured, we should fail the rule.
  • When the resource has logging configured on a different bucket then the one we want. We should fail the rule.
  • When the resource has logging configured with the expected bucket, we should pass the rule.
With AWS Config you can define InputParameters. We will use this to pass in the name of the bucket that will store the access logs. We named the parameter loggingBucket. You can reference that value of this parameter using: CONFIG_RULE_PARAMETERS.loggingBucket.

Deployment

I use CloudFormation for the deployment of the rule here is a snippet of the template:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Resources:
S3AccessLogging:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: lz-s3-access-logging
Description: Validate that access logging has been enabled and that the correct logging bucket is used.
EvaluationModes:
- Mode: DETECTIVE
InputParameters:
Fn::Sub: '{"loggingBucket": "s3-access-logs-${AWS::AccountId}-${AWS::Region}"}'
Scope:
ComplianceResourceTypes: ["AWS::S3::Bucket"]
Source:
Owner: CUSTOM_POLICY
SourceDetails:
- EventSource: aws.config
MessageType: ConfigurationItemChangeNotification
- EventSource: aws.config
MessageType: OversizedConfigurationItemChangeNotification
CustomPolicyDetails:
EnableDebugLogDelivery: 'true'
PolicyRuntime: guard-2.x.x
PolicyText: |-
rule s3_logging_configuration when resourceType == "AWS::S3::Bucket" resourceName != CONFIG_RULE_PARAMETERS.loggingBucket {
supplementaryConfiguration.BucketLoggingConfiguration exists
<<
Violation: S3 Bucket needs to have access logging configured
Fix: Configure the destinationBucketName on your S3 bucket
>>
}

rule s3_logging_correct_bucket when s3_logging_configuration {
supplementaryConfiguration.BucketLoggingConfiguration {
destinationBucketName == CONFIG_RULE_PARAMETERS.loggingBucket
<<
Violation: S3 Bucket needs to have access logging configured
Fix: Configure the destinationBucketName on your S3 bucket
>>
}
}
Let’s walk over this policy and explain what is happening. The first rule only applies when the resource is a S3 bucket and the name is not equal to the name of the logging bucket. The name of the loggingBucket is configurable via the InputParameters. Next, we will check if the bucket has used the logging bucket for the access logs configured. When the logging configuration exists the destinationBucketName needs to match the given name.
You can test the scenarios I mentioned earlier using unit tests. Read: This is how you can test your cfn-guard rules for more information on how you could do that.
After you deployed this rule into your accounts. Config will check all your S3 Buckets if they are compliant with this custom config rule.

Limitations

Currently, AWS Config does only support CloudFormation Guard 2.x.x. I am waiting on the support for 3.x. Since that brings even more powerful capabilities like the json_parse method. This allows you to also check JSON structures like for example the bucket policy.

Conclusion

You can create custom config rules using CloudFormation Guard. Using CloudFormation Guard you don’t have to maintain dependencies from your functions. And you don’t need to upgrade your lambda runtime when it gets deprecated.
Photo by Pixabay
 

Comments