# ################################### ## Rule Specification ## ##################################### # # Rule Identifier: # elastic_beanstalk_logs_to_cloudwatch_check # # Description: # This control checks whether an AWS Elastic Beanstalk environment is configured to send logs to Amazon CloudWatch Logs. # # Reports on: # AWS::ElasticBeanstalk::Environment, AWS::ElasticBeanstalk::ConfigurationTemplate # # 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 ElasticBeanstalk environment resources or ElasticBeanstalk # configuration template resources # Then: SKIP # Scenario: 2 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ElasticBeanstalk environment resource # And: 'OptionSettings' is not present in the resource properties or is an empty list # Then: FAIL # Scenario: 3 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ElasticBeanstalk environment resource # And: 'OptionSettings' is present in the resource properties as a non-empty list # And: No entry in the 'OptionSettings' list has both a 'Namespace' property with a value of # 'aws:elasticbeanstalk:cloudwatch:logs' and an 'OptionName' property with a value of 'StreamLogs' # Then: FAIL # Scenario: 4 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ElasticBeanstalk environment resource or an ElasticBeanstalk # configuration template resource # And: 'OptionSettings' is present in the resource properties as a non-empty list # And: An entry in the 'OptionSettings' list has a 'Namespace' property with a value of # 'aws:elasticbeanstalk:cloudwatch:logs' # And: That same entry has an 'OptionName' property with a value of 'StreamLogs' # And: That same entry has a 'Value' property with a value of anything other than bool(true), or the 'Value' # property is not provided. # Then: FAIL # Scenario: 5 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ElasticBeanstalk configuration template resource # And: 'OptionSettings' is not present in the resource properties or is an empty list # Then: PASS # Scenario: 6 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ElasticBeanstalk configuration template resource # And: 'OptionSettings' is present in the resource properties as a non-empty list # And: No entry in the 'OptionSettings' list has both a 'Namespace' property with a value of # 'aws:elasticbeanstalk:cloudwatch:logs' and an 'OptionName' property with a value of 'StreamLogs' # Then: PASS # Scenario: 7 # Given: The input document is an AWS CloudFormation or CloudFormation hook document # And: The input document contains an ElasticBeanstalk environment resource or an ElasticBeanstalk # configuration template resource # And: 'OptionSettings' is present in the resource properties as a non-empty list # And: Every entry in the 'OptionSettings' list that has both a 'Namespace' property with a value of # 'aws:elasticbeanstalk:cloudwatch:logs' and an 'OptionName' property with a value of 'StreamLogs' # also has a 'Value' property with a value of bool(true) # Then: PASS # # Constants # let ELASTIC_BEANSTALK_ENVIRONMENT_TYPE = "AWS::ElasticBeanstalk::Environment" let ELASTIC_BEANSTALK_CONFIGURATION_TEMPLATE_TYPE = "AWS::ElasticBeanstalk::ConfigurationTemplate" let ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_NAMESPACE = "aws:elasticbeanstalk:cloudwatch:logs" let ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_OPTION_NAME = "StreamLogs" let ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_ENABLED_VALUE = ["true", true] let INPUT_DOCUMENT = this # # Assignments # let elastic_beanstalk_environments = Resources.*[ Type == %ELASTIC_BEANSTALK_ENVIRONMENT_TYPE ] let elastic_beanstalk_configuration_templates = Resources.*[ Type == %ELASTIC_BEANSTALK_CONFIGURATION_TEMPLATE_TYPE ] # # Primary Rules # rule elastic_beanstalk_logs_to_cloudwatch_check when is_cfn_template(%INPUT_DOCUMENT) %elastic_beanstalk_environments not empty { check_elastic_beanstalk_environments(%elastic_beanstalk_environments.Properties) << [CT.ELASTICBEANSTALK.PR.3]: Require an AWS Elastic Beanstalk environment to have a logging configuration [FIX]: For AWS Elastic Beanstalk environments, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true', or omit this 'OptionSetting'. >> } rule elastic_beanstalk_logs_to_cloudwatch_check when is_cfn_template(%INPUT_DOCUMENT) %elastic_beanstalk_configuration_templates not empty { check_elastic_beanstalk_configuration_templates(%elastic_beanstalk_configuration_templates.Properties) << [CT.ELASTICBEANSTALK.PR.3]: Require an AWS Elastic Beanstalk environment to have a logging configuration [FIX]: For AWS Elastic Beanstalk environments, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true', or omit this 'OptionSetting'. >> } rule elastic_beanstalk_logs_to_cloudwatch_check when is_cfn_hook(%INPUT_DOCUMENT, %ELASTIC_BEANSTALK_ENVIRONMENT_TYPE) { check_elastic_beanstalk_environments(%INPUT_DOCUMENT.%ELASTIC_BEANSTALK_ENVIRONMENT_TYPE.resourceProperties) << [CT.ELASTICBEANSTALK.PR.3]: Require an AWS Elastic Beanstalk environment to have a logging configuration [FIX]: For AWS Elastic Beanstalk environments, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true', or omit this 'OptionSetting'. >> } rule elastic_beanstalk_logs_to_cloudwatch_check when is_cfn_hook(%INPUT_DOCUMENT, %ELASTIC_BEANSTALK_CONFIGURATION_TEMPLATE_TYPE) { check_elastic_beanstalk_configuration_templates(%INPUT_DOCUMENT.%ELASTIC_BEANSTALK_CONFIGURATION_TEMPLATE_TYPE.resourceProperties) << [CT.ELASTICBEANSTALK.PR.3]: Require an AWS Elastic Beanstalk environment to have a logging configuration [FIX]: For AWS Elastic Beanstalk environments, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, establish an 'OptionSetting' with a 'Namespace' set to 'aws:elasticbeanstalk:cloudwatch:logs', 'OptionName' set to 'StreamLogs', and 'Value' set to 'true', or omit this 'OptionSetting'. >> } # # Parameterized Rules # rule check_elastic_beanstalk_environments(elastic_beanstalk_environments) { %elastic_beanstalk_environments { # Scenario 2 check_option_settings_exists_and_is_non_empty_list(this) # Scenario 3, 4, 7 check_option_settings_cloudwatch_logs_enabled(OptionSettings[*]) } } rule check_elastic_beanstalk_configuration_templates(elastic_beanstalk_configuration_templates) { %elastic_beanstalk_configuration_templates { # Scenario 7 check_option_settings_with_cloudwatch_logs_enabled(this) or # Scenario 6 check_option_settings_without_cloudwatch_logs(this) or # Scenario 5 check_option_settings_not_exists_or_is_empty_list(this) } } rule check_option_settings_with_cloudwatch_logs_enabled(elastic_beanstalk_configuration_templates) { %elastic_beanstalk_configuration_templates [ filter_option_settings_with_cloudwatch_logs(this) ] { check_option_settings_cloudwatch_logs_enabled(OptionSettings[*]) } } rule filter_option_settings_with_cloudwatch_logs(elastic_beanstalk_configuration_templates) { some %elastic_beanstalk_configuration_templates { check_option_settings_exists_and_is_non_empty_list(this) some OptionSettings[*] { Namespace exists OptionName exists Namespace == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_NAMESPACE OptionName == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_OPTION_NAME } } } rule check_option_settings_cloudwatch_logs_enabled(option_settings) { # Scenario 3, 4 some %option_settings[*] { Namespace exists OptionName exists Value exists Namespace == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_NAMESPACE OptionName == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_OPTION_NAME Value in %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_ENABLED_VALUE } # Scenario 7 let option_setting_duplicates = OptionSettings [ Namespace exists OptionName exists Value exists Namespace == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_NAMESPACE OptionName == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_OPTION_NAME Value not in %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_ENABLED_VALUE ] %option_setting_duplicates empty } rule check_option_settings_without_cloudwatch_logs(elastic_beanstalk_configuration_templates) { some %elastic_beanstalk_configuration_templates { check_option_settings_exists_and_is_non_empty_list(this) let option_settings_with_cloudwatch_logs = OptionSettings [ Namespace exists OptionName exists Namespace == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_NAMESPACE OptionName == %ELASTIC_BEANSTALK_CLOUDWATCH_LOGS_OPTION_NAME ] %option_settings_with_cloudwatch_logs empty } } rule check_option_settings_exists_and_is_non_empty_list(elastic_beanstalk_resource) { %elastic_beanstalk_resource { OptionSettings exists OptionSettings is_list OptionSettings not empty } } rule check_option_settings_not_exists_or_is_empty_list(configuration_template) { %configuration_template { OptionSettings not exists or check_is_empty_list(OptionSettings) } } rule check_is_empty_list(option_settings) { %option_settings { this is_list this empty } } # # Utility Rules # rule is_cfn_template(doc) { %doc { AWSTemplateFormatVersion exists or Resources exists } } rule is_cfn_hook(doc, RESOURCE_TYPE) { %doc.%RESOURCE_TYPE.resourceProperties exists }