# ################################### ## Rule Specification ## ##################################### # # Rule Identifier: # s3_bucket_logging_enabled_check # # Description: # This control checks whether server access logging is enabled for your Amazon S3 bucket. # # Reports on: # AWS::S3::Bucket # # Evaluates: # AWS CloudFormation, AWS CloudFormation hook # # Rule Parameters: # None # # Scenarios: # Scenario: 1 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document does not contain any Amazon S3 bucket resources # Then: SKIP # Scenario: 2 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an Amazon S3 bucket resource # And: 'LoggingConfiguration' has not been provided # Then: FAIL # Scenario: 3 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an Amazon S3 bucket resource # And: 'LoggingConfiguration' has been provided # And: 'LoggingConfiguration.DestinationBucketName' has been provided with an empty string or non-valid local # reference # Then: FAIL # Scenario: 4 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an Amazon S3 bucket resource # And: 'LoggingConfiguration' has been provided # Then: PASS # Scenario: 5 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an Amazon S3 bucket resource # And: 'LoggingConfiguration' has been provided # And: 'LoggingConfiguration.DestinationBucketName' has been provided with a non-empty string or valid local # reference # Then: PASS # # Constants # let S3_BUCKET_TYPE = "AWS::S3::Bucket" let INPUT_DOCUMENT = this # # Assignments # let s3_buckets = Resources.*[ Type == %S3_BUCKET_TYPE ] # # Primary Rules # rule s3_bucket_logging_enabled_check when is_cfn_template(%INPUT_DOCUMENT) %s3_buckets not empty { check(%s3_buckets.Properties) << [CT.S3.PR.2]: Require an Amazon S3 bucket to have server access logging configured [FIX]: Set a 'LoggingConfiguration' on the S3 Bucket and optionally set 'DestinationBucketName' to an S3 bucket configured to receive S3 Access Logs. >> } rule s3_bucket_logging_enabled_check when is_cfn_hook(%INPUT_DOCUMENT, %S3_BUCKET_TYPE) { check(%INPUT_DOCUMENT.%S3_BUCKET_TYPE.resourceProperties) << [CT.S3.PR.2]: Require an Amazon S3 bucket to have server access logging configured [FIX]: Set a 'LoggingConfiguration' on the S3 Bucket and optionally set 'DestinationBucketName' to an S3 bucket configured to receive S3 Access Logs. >> } # # Parameterized Rules # rule check(s3_bucket) { %s3_bucket { # Scenario 2 and 4 LoggingConfiguration exists LoggingConfiguration is_struct LoggingConfiguration { when DestinationBucketName exists { # Scenario 3, 4 and 5 check_is_string_and_not_empty(DestinationBucketName) or check_local_references(%INPUT_DOCUMENT, DestinationBucketName, %S3_BUCKET_TYPE) } } } } # # Utility Rules # rule check_is_string_and_not_empty(value) { %value { this is_string this != /\A\s*\z/ } } rule is_cfn_template(doc) { %doc { AWSTemplateFormatVersion exists or Resources exists } } rule is_cfn_hook(doc, RESOURCE_TYPE) { %doc.%RESOURCE_TYPE.resourceProperties exists } rule check_local_references(doc, reference_properties, referenced_resource_type) { %reference_properties { 'Fn::GetAtt' { query_for_resource(%doc, this[0], %referenced_resource_type) <> } or Ref { query_for_resource(%doc, this, %referenced_resource_type) <> } } } rule query_for_resource(doc, resource_key, referenced_resource_type) { let referenced_resource = %doc.Resources[ keys == %resource_key ] %referenced_resource not empty %referenced_resource { Type == %referenced_resource_type } }