In today's data-driven world, ensuring compliance with industry regulations and internal policies has become a top priority for organisations. While many organisations implement standard compliance measures, custom Config Rules offer a more tailored approach to meet specific requirements. In this blog post we will discuss the importance of custom Config Rule for compliance and provide examples of custom Config Rules using AWS CloudFormation Guard 2.0 and Lambda.
Basic security and governance are provided by standard compliance measures, protecting organizations with a minimum level of security. But businesses operate in different environments, each with unique characteristics. One-size-fits-all compliance frameworks may not meet specific requirements, possibly leaving vulnerabilities unattended. This is where personalised Config Rules come into play, offering bespoke solutions that match an organisation's unique requirements.
AWS CloudFormation Guard 2.0 is a powerful tool that helps organizations adhere to compliance requirements with custom Config Rules. This open-source project provides a language that facilitates developers and security teams to establish and enforce compliance rules for infrastructure-as-code. With a user-friendly syntax, CloudFormation Guard 2.0 enables organizations to efficiently and clearly define their compliance requirements.
The following CloudFormation snippet for a custom Config Rule using AWS CloudFormation Guard 2.0, checks whether GuardDuty has S3 protection enabled, Kubernetes protection enabled and Findings are published every 15 minutes.
CustomGuardDutySettings:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: GuardDutySettings
Description: Compliant if GuardDuty has S3 protection enabled, Kubernetes protection enabled AND Findings are published every 15 minutes.
Scope:
ComplianceResourceTypes:
- "AWS::GuardDuty::Detector"
Source:
Owner: CUSTOM_POLICY
CustomPolicyDetails:
EnableDebugLogDelivery: "True"
PolicyRuntime: guard-2.x.x
PolicyText: |
let s3protection = true
let kubernetesprotection = true
let publishfrequency = 'FIFTEEN_MINUTES'
rule compliancecheck when
resourceType == "AWS::GuardDuty::Detector" {
configuration.DataSources.S3Logs.Enable == %s3protection
configuration.DataSources.Kubernetes.AuditLogs.Enable == %kubernetesprotection
configuration.FindingPublishingFrequency == %publishfrequency
}
SourceDetails:
-
EventSource: "aws.config"
MessageType: "ConfigurationItemChangeNotification"
The following CloudFormation snippet for a custom Config Rule using AWS CloudFormation Guard 2.0, creates a Config Rule to check whether Amazon Managed Streaming for Apache Kafka (MSK) data volume is encrypted.
CustomMskBrokerEncryptionAtRest:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: CUSTOM-MSK-BROKER-ENCRYPTION-AT-REST
Description: Checks whether MSK has at the broker volume encryption at rest active
Scope:
ComplianceResourceTypes:
- "AWS::MSK::Cluster"
Source:
Owner: "CUSTOM_POLICY"
CustomPolicyDetails:
EnableDebugLogDelivery: false
PolicyRuntime: guard-2.x.x
PolicyText:
!Sub |
rule check_resource_type {
resourceType == "AWS::MSK::Cluster"
}
rule check_broker_encryption_at_rest when check_resource_type {
let kmsKey = configuration.EncryptionInfo.EncryptionAtRest.DataVolumeKMSKeyId
%kmsKey == /arn:aws:kms:\w+(?:-\w+)+:\d{12}:key\/(?:[-a-z0-9]+)/
}
SourceDetails:
-
EventSource: aws.config
MessageType: ConfigurationItemChangeNotification
The following CloudFormation snippet for a custom Config Rule backed by AWS Lambda, checks whether any resource tag contains an phone number or an email.
DsgvoConfigRuleFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName:
Fn::Sub: DsgvoConfigRuleFunction-${AWS::Region}
Description: Checks for Email and Phone in Ressource Tags
Code:
ZipFile: |-
import json
import boto3
import re
import os
def find_violation(current_tags):
violation = ""
for tag in current_tags:
print(tag)
if current_tags[tag] != "":
phoneregex = r"(^\+49+[0-9]*|^49+[0-9]*|^01+[0-9]*|^\+01+[0-9]*)"
if re.match(phoneregex, current_tags[tag]):
violation += f"- found phone number in Tag: {tag} "
emailregex = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
if re.match(emailregex, current_tags[tag] ):
violation += f" - found E-mail address in Tag: {tag} "
return violation
def evaluate_compliance(configuration_item):
if configuration_item["configurationItemStatus"] == "ResourceDeleted" or os.environ['AWS_DEFAULT_REGION'] != configuration_item["awsRegion"]:
return {
"compliance_type": "NOT_APPLICABLE",
"annotation": "The configurationItem was deleted and therefore cannot be validated."
}
violation = None
current_tags = configuration_item.get("tags")
if current_tags != None or current_tags == "":
violation = find_violation(current_tags)
if violation:
return {
"compliance_type": "NON_COMPLIANT",
"annotation": violation[:255]
}
return {
"compliance_type": "COMPLIANT",
"annotation": "The tags of this resource are DSGVO compliant."
}
def handler(event, context):
invoking_event = json.loads(event["invokingEvent"])
configuration_item = invoking_event["configurationItem"]
result_token = "No token found."
if "resultToken" in event:
result_token = event["resultToken"]
evaluation = evaluate_compliance(configuration_item)
config = boto3.client("config")
config.put_evaluations(
Evaluations=[
{
"ComplianceResourceType":
configuration_item["resourceType"],
"ComplianceResourceId":
configuration_item["resourceId"],
"ComplianceType":
evaluation["compliance_type"],
"Annotation":
evaluation["annotation"],
"OrderingTimestamp":
configuration_item["configurationItemCaptureTime"]
},
],
ResultToken=result_token)
Handler: index.handler
Runtime: python3.11
Role:
Fn::GetAtt:
- DsgvoConfigRuleRole
- Arn
Timeout: 60
CustomDsgvoTags:
Type: AWS::Config::ConfigRule
Properties:
ConfigRuleName: CUSTOM-DSGVO-TAGS
Description: Checks whether no sensitive data from employees are added into Tags are set
Source:
Owner: "CUSTOM_LAMBDA"
SourceDetails:
-
EventSource: aws.config
MessageType: ConfigurationItemChangeNotification
SourceIdentifier: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:DsgvoConfigRuleFunction-${AWS::Region}'
In the time of data-based operations, it's important to have both compliance and customisation working together effectively. Although standard compliance measures are important, it is better for companies to have custom Config Rules that suit their unique needs and mitigate specific risks. AWS CloudFormation Guard 2.0 shines as a tool that empowers organizations to implement and enforce custom compliance rules seamlessly. However if you want to implement more complex checks you need to use Custom Config Rules backed by Lambda. Organizations can confidently move towards a secure and compliant future in the data-driven world by using custom Config Rules.