

# AWS Elastic Beanstalk controls


**Topics**
+ [

## [CT.ELASTICBEANSTALK.PR.1] Require AWS Elastic Beanstalk environments to have enhanced health reporting enabled
](#ct-elasticbeanstalk-pr-1-description)
+ [

## [CT.ELASTICBEANSTALK.PR.2] Require an AWS Elastic Beanstalk environment to have managed platform updates configured
](#ct-elasticbeanstalk-pr-2-description)
+ [

## [CT.ELASTICBEANSTALK.PR.3] Require an AWS Elastic Beanstalk environment to have a logging configuration
](#ct-elasticbeanstalk-pr-3-description)

## [CT.ELASTICBEANSTALK.PR.1] Require AWS Elastic Beanstalk environments to have enhanced health reporting enabled
CT.ELASTICBEANSTALK.PR.1

This control checks whether AWS Elastic Beanstalk environments and configuration templates are configured for `enhanced` health reporting.
+ **Control objective: **Improve resiliency
+ **Implementation: **CloudFormation Guard Rule
+ **Control behavior: **Proactive
+ **Resource types: **`AWS::ElasticBeanstalk::Environment`, `AWS::ElasticBeanstalk::ConfigurationTemplate`
+ **CloudFormation guard rule: ** [CT.ELASTICBEANSTALK.PR.1 rule specification](#ct-elasticbeanstalk-pr-1-rule) 

**Details and examples**
+ For details about the PASS, FAIL, and SKIP behaviors associated with this control, see the: [CT.ELASTICBEANSTALK.PR.1 rule specification](#ct-elasticbeanstalk-pr-1-rule) 
+ For examples of PASS and FAIL CloudFormation Templates related to this control, see: [CT.ELASTICBEANSTALK.PR.1 example templates](#ct-elasticbeanstalk-pr-1-templates) 

**Explanation**

Elastic Beanstalk enhanced health reporting enables a more rapid response to changes in the health of the underlying infrastructure. These changes could result in a lack of availability of the application.

Elastic Beanstalk enhanced health reporting provides a status descriptor to gauge the severity of the identified issues and identify possible causes to investigate. The Elastic Beanstalk health agent, included in supported Amazon Machine Images (AMIs), evaluates logs and metrics of environment EC2 instances.

### Remediation for rule failure


For AWS Elastic Beanstalk environments, configure an `OptionSetting` with `Namespace` set to `aws:elasticbeanstalk:healthreporting:system`, `OptionName` set to `SystemType`, and `Value` set to `enhanced`. For AWS Elastic Beanstalk configuration templates, configure an `OptionSetting` with `Namespace` set to `aws:elasticbeanstalk:healthreporting:system`, `OptionName` set to `SystemType`, and `Value` set to `enhanced`. Omit this setting to adopt the default value of `enhanced`.

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Environment - Example


AWS Elastic Beanstalk environment configured with enhanced health reporting enabled. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkEnvironment": {
        "Type": "AWS::ElasticBeanstalk::Environment",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.0 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:elasticbeanstalk:healthreporting:system",
                    "OptionName": "SystemType",
                    "Value": "enhanced"
                },
                {
                    "Namespace": "aws:autoscaling:launchconfiguration",
                    "OptionName": "IamInstanceProfile",
                    "Value": {
                        "Ref": "InstanceProfile"
                    }
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkEnvironment:
  Type: AWS::ElasticBeanstalk::Environment
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.0 running Python 3.8
    OptionSettings:
      - Namespace: aws:elasticbeanstalk:healthreporting:system
        OptionName: SystemType
        Value: enhanced
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'InstanceProfile'
```

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Configuration Template - Example One


AWS Elastic Beanstalk configuration template configured with enhanced health reporting, enabled by means of CloudFormation defaults. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkConfigurationTemplate": {
        "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.0 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:autoscaling:launchconfiguration",
                    "OptionName": "IamInstanceProfile",
                    "Value": {
                        "Ref": "InstanceProfile"
                    }
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkConfigurationTemplate:
  Type: AWS::ElasticBeanstalk::ConfigurationTemplate
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.0 running Python 3.8
    OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'InstanceProfile'
```

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Configuration Template - Example Two


AWS Elastic Beanstalk configuration template configured with enhanced health reporting, enabled by means of an entry in the `OptionSettings` property. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkConfigurationTemplate": {
        "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.0 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:elasticbeanstalk:healthreporting:system",
                    "OptionName": "SystemType",
                    "Value": "enhanced"
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkConfigurationTemplate:
  Type: AWS::ElasticBeanstalk::ConfigurationTemplate
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.0 running Python 3.8
    OptionSettings:
      - Namespace: aws:elasticbeanstalk:healthreporting:system
        OptionName: SystemType
        Value: enhanced
```

### CT.ELASTICBEANSTALK.PR.1 rule specification


```
# ###################################
##       Rule Specification        ##
#####################################
# 
# Rule Identifier:
#   elastic_beanstalk_enhanced_health_reporting_enabled_check
# 
# Description:
#   This control checks whether AWS Elastic Beanstalk environments and configuration templates are configured for 'enhanced' health reporting.
# 
# Reports on:
#   AWS::ElasticBeanstalk::Environment, AWS::ElasticBeanstalk::ConfigurationTemplate
# 
# Evaluates:
#   CloudFormation, CloudFormation hook
# 
# Rule Parameters:
#   None
# 
# Scenarios:
#   Scenario: 1
#     Given: The input document is an CloudFormation or CloudFormation hook document
#       And: The input document does not contain any Elastic Beanstalk environment resources or
#            Elastic Beanstalk configuration template resources
#      Then: SKIP
#   Scenario: 2
#     Given: The input document is an CloudFormation or CloudFormation hook document
#       And: The input document contains an Elastic Beanstalk 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 CloudFormation or CloudFormation hook document
#       And: The input document contains an Elastic Beanstalk 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:healthreporting:system'
#            and an 'OptionName' property with value of 'SystemType'
#      Then: FAIL
#   Scenario: 4
#     Given: The input document is an CloudFormation or CloudFormation hook document
#       And: The input document contains an Elastic Beanstalk environment resource or an Elastic Beanstalk
#            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:healthreporting:system'
#       And: That same entry has an 'OptionName' property with a value of 'SystemType'
#       And: That same entry has a 'Value' property with a value of anything other than 'enhanced', or the 'Value'
#            property is not provided.
#      Then: FAIL
#   Scenario: 5
#     Given: The input document is an CloudFormation or CloudFormation hook document
#       And: The input document contains an Elastic Beanstalk 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 CloudFormation or CloudFormation hook document
#       And: The input document contains an Elastic Beanstalk 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:healthreporting:system'
#            and an 'OptionName' property with value of 'SystemType'
#      Then: PASS
#   Scenario: 7
#     Given: The input document is an CloudFormation or CloudFormation hook document
#       And: The input document contains an Elastic Beanstalk environment resource or an Elastic Beanstalk
#            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:healthreporting:system'
#            and an 'OptionName' property with a value of 'SystemType' also has a 'Value' property with a value of
#            'enhanced'
#      Then: PASS

#
# Constants
#
let ELASTIC_BEANSTALK_ENVIRONMENT_TYPE = "AWS::ElasticBeanstalk::Environment"
let ELASTIC_BEANSTALK_CONFIGURATION_TEMPLATE_TYPE = "AWS::ElasticBeanstalk::ConfigurationTemplate"
let ELASTIC_BEANSTALK_ENHANCED_HEALTH_REPORTING_NAMESPACE = "aws:elasticbeanstalk:healthreporting:system"
let ELASTIC_BEANSTALK_SYSTEM_TYPE_OPTION_NAME = "SystemType"
let ELASTIC_BEANSTALK_ENHANCED_VALUE = "enhanced"
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_enhanced_health_reporting_enabled_check when is_cfn_template(%INPUT_DOCUMENT)
                                                                    %elastic_beanstalk_environments not empty {
    check_elastic_beanstalk_environments(%elastic_beanstalk_environments.Properties)
        <<
        [CT.ELASTICBEANSTALK.PR.1]: Require AWS Elastic Beanstalk environments to have enhanced health reporting enabled
        [FIX]: For AWS Elastic Beanstalk environments, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. For AWS Elastic Beanstalk configuration templates, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. Omit this setting to adopt the default value of 'enhanced'.
        >>
}

rule elastic_beanstalk_enhanced_health_reporting_enabled_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.1]: Require AWS Elastic Beanstalk environments to have enhanced health reporting enabled
        [FIX]: For AWS Elastic Beanstalk environments, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. For AWS Elastic Beanstalk configuration templates, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. Omit this setting to adopt the default value of 'enhanced'.
        >>
}

rule elastic_beanstalk_enhanced_health_reporting_enabled_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.1]: Require AWS Elastic Beanstalk environments to have enhanced health reporting enabled
        [FIX]: For AWS Elastic Beanstalk environments, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. For AWS Elastic Beanstalk configuration templates, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. Omit this setting to adopt the default value of 'enhanced'.
        >>
}

rule elastic_beanstalk_enhanced_health_reporting_enabled_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.1]: Require AWS Elastic Beanstalk environments to have enhanced health reporting enabled
        [FIX]: For AWS Elastic Beanstalk environments, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. For AWS Elastic Beanstalk configuration templates, configure an 'OptionSetting' with 'Namespace' set to 'aws:elasticbeanstalk:healthreporting:system', 'OptionName' set to 'SystemType', and 'Value' set to 'enhanced'. Omit this setting to adopt the default value of 'enhanced'.
        >>
}

#
# Parameterized Rules
#
rule check_elastic_beanstalk_environments(elastic_beanstalk_environments) {
    %elastic_beanstalk_environments {
        # Scenario 2
        check_option_settings_exists_or_is_non_empty_list(this)

        # Scenario 3, 4, 7
        check_option_settings_enhanced(OptionSettings[*])
    }
}

rule check_elastic_beanstalk_configuration_templates(elastic_beanstalk_configuration_templates) {
    %elastic_beanstalk_configuration_templates {
        # Scenario 7
        check_option_settings_with_enhanced_health_reporting(this) or
        # Scenario 6
        check_option_settings_without_health_reporting(this) or
        # Scenario 5
        check_option_settings_not_exists_or_is_empty_list(this)
    }
}

rule check_option_settings_with_enhanced_health_reporting(elastic_beanstalk_configuration_templates) {
    %elastic_beanstalk_configuration_templates [
        filter_option_settings_with_health_reporting(this)
    ] {
        check_option_settings_enhanced(OptionSettings[*])
    }
}

rule filter_option_settings_with_health_reporting(elastic_beanstalk_configuration_templates) {
    some %elastic_beanstalk_configuration_templates {
        check_option_settings_exists_or_is_non_empty_list(this)

        some OptionSettings[*] {
            Namespace exists
            OptionName exists

            Namespace == %ELASTIC_BEANSTALK_ENHANCED_HEALTH_REPORTING_NAMESPACE
            OptionName == %ELASTIC_BEANSTALK_SYSTEM_TYPE_OPTION_NAME
        }
    }
}

rule check_option_settings_enhanced(option_settings) {
    # Scenario 3, 4
    some %option_settings[*] {
        Namespace exists
        OptionName exists
        Value exists

        Namespace == %ELASTIC_BEANSTALK_ENHANCED_HEALTH_REPORTING_NAMESPACE
        OptionName == %ELASTIC_BEANSTALK_SYSTEM_TYPE_OPTION_NAME
        Value == %ELASTIC_BEANSTALK_ENHANCED_VALUE
    }

    # Scenario 7
    let option_setting_duplicates = OptionSettings [
        Namespace exists
        OptionName exists
        Value exists

        Namespace == %ELASTIC_BEANSTALK_ENHANCED_HEALTH_REPORTING_NAMESPACE
        OptionName == %ELASTIC_BEANSTALK_SYSTEM_TYPE_OPTION_NAME
        Value != %ELASTIC_BEANSTALK_ENHANCED_VALUE
    ]
    %option_setting_duplicates empty
}


rule check_option_settings_without_health_reporting(elastic_beanstalk_configuration_templates) {
    some %elastic_beanstalk_configuration_templates {
        check_option_settings_exists_or_is_non_empty_list(this)

        let option_settings_with_health_reporting = OptionSettings [
            Namespace exists
            OptionName exists

            Namespace == %ELASTIC_BEANSTALK_ENHANCED_HEALTH_REPORTING_NAMESPACE
            OptionName == %ELASTIC_BEANSTALK_SYSTEM_TYPE_OPTION_NAME
        ]
        %option_settings_with_health_reporting empty
    }
}

rule check_option_settings_exists_or_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
}
```

### CT.ELASTICBEANSTALK.PR.1 example templates
Test artifacts

You can view examples of the PASS and FAIL test artifacts for the AWS Control Tower proactive controls.

PASS Example - Use this template to verify a compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - elasticbeanstalk.amazonaws.com
          Action:
          - 'sts:AssumeRole'
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
  ElasticBeanstalkConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: App
      SolutionStackName: "64bit Amazon Linux 2 v3.4.0 running Python 3.8"
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
```

FAIL Example - Use this template to verify that the control prevents non-compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action:
          - 'sts:AssumeRole'
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
  ElasticBeanstalkEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      SolutionStackName: "64bit Amazon Linux 2 v3.4.0 running Python 3.8"
      ApplicationName:
        Ref: App
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
      - Namespace: aws:elasticbeanstalk:healthreporting:system
        OptionName: SystemType
        Value: basic
```

## [CT.ELASTICBEANSTALK.PR.2] Require an AWS Elastic Beanstalk environment to have managed platform updates configured
CT.ELASTICBEANSTALK.PR.2

This control checks whether managed platform updates in AWS Elastic Beanstalk environments and configuration templates are activated.
+ **Control objective: **Manage vulnerabilities
+ **Implementation: **CloudFormation Guard Rule
+ **Control behavior: **Proactive
+ **Resource types: **`AWS::ElasticBeanstalk::Environment`, `AWS::ElasticBeanstalk::ConfigurationTemplate`
+ **CloudFormation guard rule: ** [CT.ELASTICBEANSTALK.PR.2 rule specification](#ct-elasticbeanstalk-pr-2-rule) 

**Details and examples**
+ For details about the PASS, FAIL, and SKIP behaviors associated with this control, see the: [CT.ELASTICBEANSTALK.PR.2 rule specification](#ct-elasticbeanstalk-pr-2-rule) 
+ For examples of PASS and FAIL CloudFormation Templates related to this control, see: [CT.ELASTICBEANSTALK.PR.2 example templates](#ct-elasticbeanstalk-pr-2-templates) 

**Explanation**

Managed platform updates ensure that the most recent platform fixes, updates, and features for the environment are installed. Keeping patch installations up to date is an important step in securing systems.

**Usage considerations**  
When you set up managed actions on AWS Elastic Beanstalk environments and configuration templates, you must provide `PreferredStartTime` and `UpdateLevel` option settings also.
This control allows you to set up managed actions on AWS Elastic Beanstalk environments only, because environment-level settings take precedence over settings that are defined in configuration templates.
This control does not allow you to deactivate managed actions on AWS Elastic Beanstalk configuration templates.

### Remediation for rule failure


For AWS Elastic Beanstalk environments, create an `OptionSetting` with a `Namespace` value set to `aws:elasticbeanstalk:managedactions`, `OptionName` set to `ManagedActionsEnabled`, and `Value` set to `true`. For Elastic Beanstalk configuration templates, create an `OptionSetting` with a `Namespace` value set to `aws:elasticbeanstalk:managedactions`, `OptionName` set to `ManagedActionsEnabled`, and `Value` set to `true`, or omit this setting to adopt the default value of `true`.

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Environment - Example


AWS Elastic Beanstalk environment configured with managed platform updates activated. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkEnvironment": {
        "Type": "AWS::ElasticBeanstalk::Environment",
        "Properties": {
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.0 running Python 3.8",
            "ApplicationName": {
                "Ref": "App"
            },
            "OptionSettings": [
                {
                    "Namespace": "aws:autoscaling:launchconfiguration",
                    "OptionName": "IamInstanceProfile",
                    "Value": {
                        "Ref": "InstanceProfile"
                    }
                },
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions",
                    "OptionName": "ManagedActionsEnabled",
                    "Value": true
                },
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions",
                    "OptionName": "PreferredStartTime",
                    "Value": "Tue:09:00"
                },
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions",
                    "OptionName": "ServiceRoleForManagedUpdates",
                    "Value": "AWSServiceRoleForElasticBeanstalkManagedUpdates"
                },
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions:platformupdate",
                    "OptionName": "UpdateLevel",
                    "Value": "patch"
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkEnvironment:
  Type: AWS::ElasticBeanstalk::Environment
  Properties:
    SolutionStackName: 64bit Amazon Linux 2 v3.4.0 running Python 3.8
    ApplicationName: !Ref 'App'
    OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'InstanceProfile'
      - Namespace: aws:elasticbeanstalk:managedactions
        OptionName: ManagedActionsEnabled
        Value: true
      - Namespace: aws:elasticbeanstalk:managedactions
        OptionName: PreferredStartTime
        Value: Tue:09:00
      - Namespace: aws:elasticbeanstalk:managedactions
        OptionName: ServiceRoleForManagedUpdates
        Value: AWSServiceRoleForElasticBeanstalkManagedUpdates
      - Namespace: aws:elasticbeanstalk:managedactions:platformupdate
        OptionName: UpdateLevel
        Value: patch
```

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Configuration Template - Example One


AWS Elastic Beanstalk configuration template configured with managed platform updates enabled, by means of AWS CloudFormation defaults. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkConfigurationTemplate": {
        "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.0 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:autoscaling:launchconfiguration",
                    "OptionName": "IamInstanceProfile",
                    "Value": {
                        "Ref": "InstanceProfile"
                    }
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkConfigurationTemplate:
  Type: AWS::ElasticBeanstalk::ConfigurationTemplate
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.0 running Python 3.8
    OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'InstanceProfile'
```

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Configuration Template - Example Two


AWS Elastic Beanstalk configuration template configured with managed platform updates enabled, by means of an entry in the `OptionSettings` property. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkConfigurationTemplate": {
        "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.0 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions",
                    "OptionName": "ManagedActionsEnabled",
                    "Value": true
                },
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions",
                    "OptionName": "PreferredStartTime",
                    "Value": "Tue:09:00"
                },
                {
                    "Namespace": "aws:elasticbeanstalk:managedactions:platformupdate",
                    "OptionName": "UpdateLevel",
                    "Value": "minor"
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkConfigurationTemplate:
  Type: AWS::ElasticBeanstalk::ConfigurationTemplate
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.0 running Python 3.8
    OptionSettings:
      - Namespace: aws:elasticbeanstalk:managedactions
        OptionName: ManagedActionsEnabled
        Value: true
      - Namespace: aws:elasticbeanstalk:managedactions
        OptionName: PreferredStartTime
        Value: Tue:09:00
      - Namespace: aws:elasticbeanstalk:managedactions:platformupdate
        OptionName: UpdateLevel
        Value: minor
```

### CT.ELASTICBEANSTALK.PR.2 rule specification


```
# ###################################
##       Rule Specification        ##
#####################################
# 
# Rule Identifier:
#   elastic_beanstalk_managed_updates_enabled_check
# 
# Description:
#   This control checks whether managed platform updates in AWS Elastic Beanstalk environments and configuration templates are activated.
# 
# Reports on:
#   AWS::ElasticBeanstalk::Environment, AWS::ElasticBeanstalk::ConfigurationTemplate
# 
# Evaluates:
#   CloudFormation, CloudFormation hook
# 
# Rule Parameters:
#   None
# 
# Scenarios:
#   Scenario: 1
#     Given: The input document is an 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 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 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:managedactions' and an 'OptionName' property with a value of 'ManagedActionsEnabled'
#      Then: FAIL
#   Scenario: 4
#     Given: The input document is an 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:managedactions'
#       And: That same entry has an 'OptionName' property with a value of 'ManagedActionsEnabled'
#       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 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 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:managedactions' and an 'OptionName' property with a value of 'ManagedActionsEnabled'
#      Then: PASS
#   Scenario: 7
#     Given: The input document is an 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:managedactions' and an 'OptionName' property with a value of 'ManagedActionsEnabled'
#            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_MANAGED_ACTIONS_NAMESPACE = "aws:elasticbeanstalk:managedactions"
let ELASTIC_BEANSTALK_MANAGED_ACTIONS_OPTION_NAME = "ManagedActionsEnabled"
let ELASTIC_BEANSTALK_MANAGED_ACTIONS_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_managed_updates_enabled_check when is_cfn_template(%INPUT_DOCUMENT)
                                                          %elastic_beanstalk_environments not empty {
    check_elastic_beanstalk_environments(%elastic_beanstalk_environments.Properties)
        <<
        [CT.ELASTICBEANSTALK.PR.2]: Require an AWS Elastic Beanstalk environment to have managed platform updates configured
            [FIX]: For AWS Elastic Beanstalk environments, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true', or omit this setting to adopt the default value of 'true'.
        >>
}

rule elastic_beanstalk_managed_updates_enabled_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.2]: Require an AWS Elastic Beanstalk environment to have managed platform updates configured
            [FIX]: For AWS Elastic Beanstalk environments, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true', or omit this setting to adopt the default value of 'true'.
        >>
}

rule elastic_beanstalk_managed_updates_enabled_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.2]: Require an AWS Elastic Beanstalk environment to have managed platform updates configured
            [FIX]: For AWS Elastic Beanstalk environments, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true', or omit this setting to adopt the default value of 'true'.
        >>
}

rule elastic_beanstalk_managed_updates_enabled_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.2]: Require an AWS Elastic Beanstalk environment to have managed platform updates configured
            [FIX]: For AWS Elastic Beanstalk environments, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true'. For Elastic Beanstalk configuration templates, create an 'OptionSetting' with a 'Namespace' value set to  'aws:elasticbeanstalk:managedactions', 'OptionName' set to 'ManagedActionsEnabled', and 'Value' set to 'true', or omit this setting to adopt the default value of 'true'.
        >>
}

#
# 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_managed_actions_enabled(OptionSettings[*])
    }
}

rule check_elastic_beanstalk_configuration_templates(elastic_beanstalk_configuration_templates) {
    %elastic_beanstalk_configuration_templates {
        # Scenario 7
        check_option_settings_with_managed_actions_enabled(this) or
        # Scenario 6
        check_option_settings_without_managed_actions(this) or
        # Scenario 5
        check_option_settings_not_exists_or_is_empty_list(this)
    }
}

rule check_option_settings_with_managed_actions_enabled(elastic_beanstalk_configuration_templates) {
    %elastic_beanstalk_configuration_templates [
        filter_option_settings_with_managed_actions(this)
    ] {
        check_option_settings_managed_actions_enabled(OptionSettings[*])
    }
}

rule filter_option_settings_with_managed_actions(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_MANAGED_ACTIONS_NAMESPACE
            OptionName == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_OPTION_NAME
        }
    }
}

rule check_option_settings_managed_actions_enabled(option_settings) {
    # Scenario 3, 4
    some %option_settings[*] {
        Namespace exists
        OptionName exists
        Value exists

        Namespace == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_NAMESPACE
        OptionName == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_OPTION_NAME
        Value in %ELASTIC_BEANSTALK_MANAGED_ACTIONS_ENABLED_VALUE
    }

    # Scenario 7
    let option_setting_duplicates = OptionSettings [
        Namespace exists
        OptionName exists
        Value exists

        Namespace == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_NAMESPACE
        OptionName == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_OPTION_NAME
        Value not in %ELASTIC_BEANSTALK_MANAGED_ACTIONS_ENABLED_VALUE
    ]
    %option_setting_duplicates empty
}


rule check_option_settings_without_managed_actions(elastic_beanstalk_configuration_templates) {
    some %elastic_beanstalk_configuration_templates {
        check_option_settings_exists_and_is_non_empty_list(this)

        let option_settings_with_managed_actions = OptionSettings [
            Namespace exists
            OptionName exists

            Namespace == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_NAMESPACE
            OptionName == %ELASTIC_BEANSTALK_MANAGED_ACTIONS_OPTION_NAME
        ]
        %option_settings_with_managed_actions 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
}
```

### CT.ELASTICBEANSTALK.PR.2 example templates
Test artifacts

You can view examples of the PASS and FAIL test artifacts for the AWS Control Tower proactive controls.

PASS Example - Use this template to verify a compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - elasticbeanstalk.amazonaws.com
          Action:
          - 'sts:AssumeRole'
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
  ElasticBeanstalkConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: App
      SolutionStackName: "64bit Amazon Linux 2 v3.4.0 running Python 3.8"
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
```

FAIL Example - Use this template to verify that the control prevents non-compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"		 	 	 
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - ec2.amazonaws.com
          Action:
          - 'sts:AssumeRole'
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
  ElasticBeanstalkEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      SolutionStackName: "64bit Amazon Linux 2 v3.4.0 running Python 3.8"
      ApplicationName:
        Ref: App
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
      - Namespace: aws:elasticbeanstalk:managedactions
        OptionName: ManagedActionsEnabled
        Value: false
```

## [CT.ELASTICBEANSTALK.PR.3] Require an AWS Elastic Beanstalk environment to have a logging configuration
CT.ELASTICBEANSTALK.PR.3

This control checks whether an AWS Elastic Beanstalk environment is configured to send logs to Amazon CloudWatch Logs.
+ **Control objective: **Establish logging and monitoring
+ **Implementation: **CloudFormation guard rule
+ **Control behavior: **Proactive
+ **Resource types: **`AWS::ElasticBeanstalk::Environment`, `AWS::ElasticBeanstalk::ConfigurationTemplate`
+ **CloudFormation guard rule: ** [CT.ELASTICBEANSTALK.PR.3 rule specification](#ct-elasticbeanstalk-pr-3-rule) 

**Details and examples**
+ For details about the PASS, FAIL, and SKIP behaviors associated with this control, see the: [CT.ELASTICBEANSTALK.PR.3 rule specification](#ct-elasticbeanstalk-pr-3-rule) 
+ For examples of PASS and FAIL CloudFormation templates related to this control, see: [CT.ELASTICBEANSTALK.PR.3 example templates](#ct-elasticbeanstalk-pr-3-templates) 

**Explanation**

Monitoring is an important part of maintaining the reliability, availability, and performance of your AWS solutions. We recommend that you collect monitoring data from all of the parts of your AWS solution, so that you can debug a multi-point failure, if one occurs. From a security perspective, logging is an important feature to enable for future forensics efforts in the case of a security incident.

**Usage considerations**  
This control requires only enabling logging to Amazon CloudWatch Logs on AWS Elastic Beanstalk environments, because environment level settings take precedence over settings defined in configuration templates.
This control does not allow explicitly disabling logging to Amazon CloudWatch Logs on AWS Elastic Beanstalk configuration templates.

### Remediation for rule failure


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`.

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Environment - Example


An AWS Elastic Beanstalk environment configured to stream logs to Amazon CloudWatch Logs by means of an entry in the `OptionSettings` property. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkEnvironment": {
        "Type": "AWS::ElasticBeanstalk::Environment",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.1 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:autoscaling:launchconfiguration",
                    "OptionName": "IamInstanceProfile",
                    "Value": {
                        "Ref": "InstanceProfile"
                    }
                },
                {
                    "Namespace": "aws:elasticbeanstalk:cloudwatch:logs",
                    "OptionName": "StreamLogs",
                    "Value": true
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkEnvironment:
  Type: AWS::ElasticBeanstalk::Environment
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.1 running Python 3.8
    OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'InstanceProfile'
      - Namespace: aws:elasticbeanstalk:cloudwatch:logs
        OptionName: StreamLogs
        Value: true
```

The examples that follow show how to implement this remediation.

#### AWS Elastic Beanstalk Configuration Template - Example


AWS Elastic Beanstalk configuration template configured to stream logs to Amazon CloudWatch Logs by means of an entry in the `OptionSettings` property. The example is shown in JSON and in YAML.

**JSON example**

```
{
    "ElasticBeanstalkConfigurationTemplate": {
        "Type": "AWS::ElasticBeanstalk::ConfigurationTemplate",
        "Properties": {
            "ApplicationName": {
                "Ref": "App"
            },
            "SolutionStackName": "64bit Amazon Linux 2 v3.4.1 running Python 3.8",
            "OptionSettings": [
                {
                    "Namespace": "aws:autoscaling:launchconfiguration",
                    "OptionName": "IamInstanceProfile",
                    "Value": {
                        "Ref": "InstanceProfile"
                    }
                },
                {
                    "Namespace": "aws:elasticbeanstalk:cloudwatch:logs",
                    "OptionName": "StreamLogs",
                    "Value": true
                }
            ]
        }
    }
}
```

**YAML example**

```
ElasticBeanstalkConfigurationTemplate:
  Type: AWS::ElasticBeanstalk::ConfigurationTemplate
  Properties:
    ApplicationName: !Ref 'App'
    SolutionStackName: 64bit Amazon Linux 2 v3.4.1 running Python 3.8
    OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value: !Ref 'InstanceProfile'
      - Namespace: aws:elasticbeanstalk:cloudwatch:logs
        OptionName: StreamLogs
        Value: true
```

### CT.ELASTICBEANSTALK.PR.3 rule specification


```
# ###################################
##       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:
#   CloudFormation, CloudFormation hook
# 
# Rule Parameters:
#   None
# 
# Scenarios:
#   Scenario: 1
#     Given: The input document is an 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 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 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 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 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 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 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
}
```

### CT.ELASTICBEANSTALK.PR.3 example templates
Test artifacts

You can view examples of the PASS and FAIL test artifacts for the AWS Control Tower proactive controls.

PASS Example - Use this template to verify a compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - elasticbeanstalk.amazonaws.com
          Action:
          - sts:AssumeRole
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
    Properties: {}
  ElasticBeanstalkEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName:
        Ref: App
      SolutionStackName: 64bit Amazon Linux 2 v3.4.1 running Python 3.8
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
      - Namespace: aws:elasticbeanstalk:cloudwatch:logs
        OptionName: StreamLogs
        Value: true
```

PASS Example - Use this template to verify a compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - elasticbeanstalk.amazonaws.com
          Action:
          - sts:AssumeRole
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
    Properties: {}
  ElasticBeanstalkConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: App
      SolutionStackName: 64bit Amazon Linux 2 v3.4.1 running Python 3.8
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
      - Namespace: aws:elasticbeanstalk:cloudwatch:logs
        OptionName: StreamLogs
        Value: true
```

FAIL Example - Use this template to verify that the control prevents non-compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - elasticbeanstalk.amazonaws.com
          Action:
          - sts:AssumeRole
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
    Properties: {}
  ElasticBeanstalkEnvironment:
    Type: AWS::ElasticBeanstalk::Environment
    Properties:
      ApplicationName:
        Ref: App
      SolutionStackName: 64bit Amazon Linux 2 v3.4.1 running Python 3.8
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
```

FAIL Example - Use this template to verify that the control prevents non-compliant resource creation.

```
Resources:
  InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17		 	 	 '
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - elasticbeanstalk.amazonaws.com
          Action:
          - sts:AssumeRole
  InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
      - Ref: InstanceRole
  App:
    Type: AWS::ElasticBeanstalk::Application
    Properties: {}
  ElasticBeanstalkConfigurationTemplate:
    Type: AWS::ElasticBeanstalk::ConfigurationTemplate
    Properties:
      ApplicationName:
        Ref: App
      SolutionStackName: 64bit Amazon Linux 2 v3.4.1 running Python 3.8
      OptionSettings:
      - Namespace: aws:autoscaling:launchconfiguration
        OptionName: IamInstanceProfile
        Value:
          Ref: InstanceProfile
      - Namespace: aws:elasticbeanstalk:cloudwatch:logs
        OptionName: StreamLogs
        Value: false
```