From c3e3381c6344207f6f379bef4f0c8ee00090fef6 Mon Sep 17 00:00:00 2001 From: Mario Rodriguez Lopez <101330800+MarioRgzLpz@users.noreply.github.com> Date: Thu, 10 Oct 2024 21:32:31 +0200 Subject: [PATCH] feat(elasticbeanstalk): add new check `elasticbeanstalk_cloudwatch_enabled` (#5335) Co-authored-by: Sergio --- .../__init__.py | 0 ...t_cloudwatch_logging_enabled.metadata.json | 34 ++++ ..._environment_cloudwatch_logging_enabled.py | 25 +++ ...ronment_cloudwatch_logging_enabled_test.py | 146 ++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/__init__.py create mode 100644 prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.metadata.json create mode 100644 prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.py create mode 100644 tests/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled_test.py diff --git a/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/__init__.py b/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.metadata.json b/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.metadata.json new file mode 100644 index 0000000000..914b361488 --- /dev/null +++ b/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.metadata.json @@ -0,0 +1,34 @@ +{ + "Provider": "aws", + "CheckID": "elasticbeanstalk_environment_cloudwatch_logging_enabled", + "CheckTitle": "Elastic Beanstalk environment should stream logs to CloudWatch", + "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "ServiceName": "elasticbeanstalk", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:elasticbeanstalk:{region}:{account-id}:environment/{environment-id}", + "Severity": "high", + "ResourceType": "AwsElasticBeanstalkEnvironment", + "Description": "This control checks whether an Elastic Beanstalk environment is configured to send logs to CloudWatch Logs. The control fails if an Elastic Beanstalk environment isn't configured to send logs to CloudWatch Logs.", + "Risk": "Without log streaming to CloudWatch, it becomes difficult to monitor and troubleshoot your Elastic Beanstalk environments, which can lead to missed events or security incidents.", + "RelatedUrl": "https://docs.aws.amazon.com/config/latest/developerguide/elastic-beanstalk-logs-to-cloudwatch.html", + "Remediation": { + "Code": { + "CLI": "aws elasticbeanstalk update-environment --environment-id --option-settings Namespace=aws:elasticbeanstalk:environment:proxy:logging,OptionName=StreamLogs,Value=true", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/elasticbeanstalk-controls.html#elasticbeanstalk-3", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable log streaming to CloudWatch for your Elastic Beanstalk environment to monitor and retain logs.", + "Url": "https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.cloudwatchlogs.html#AWSHowTo.cloudwatchlogs.streaming" + } + }, + "Categories": [ + "logging" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.py b/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.py new file mode 100644 index 0000000000..ce9b8711e6 --- /dev/null +++ b/prowler/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled.py @@ -0,0 +1,25 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_client import ( + elasticbeanstalk_client, +) + + +class elasticbeanstalk_environment_cloudwatch_logging_enabled(Check): + def execute(self): + findings = [] + for environment in elasticbeanstalk_client.environments.values(): + report = Check_Report_AWS(self.metadata()) + report.region = environment.region + report.resource_id = environment.name + report.resource_arn = environment.arn + report.resource_tags = environment.tags + report.status = "PASS" + report.status_extended = f"Elastic Beanstalk environment {environment.name} is sending logs to CloudWatch Logs." + + if environment.cloudwatch_stream_logs != "true": + report.status = "FAIL" + report.status_extended = f"Elastic Beanstalk environment {environment.name} is not sending logs to CloudWatch Logs." + + findings.append(report) + + return findings diff --git a/tests/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled_test.py b/tests/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled_test.py new file mode 100644 index 0000000000..58c6484acc --- /dev/null +++ b/tests/providers/aws/services/elasticbeanstalk/elasticbeanstalk_environment_cloudwatch_logging_enabled/elasticbeanstalk_environment_cloudwatch_logging_enabled_test.py @@ -0,0 +1,146 @@ +from unittest import mock + +import botocore +from boto3 import client +from moto import mock_aws + +from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_service import ( + ElasticBeanstalk, +) +from tests.providers.aws.utils import AWS_REGION_EU_WEST_1, set_mocked_aws_provider + +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeConfigurationSettings": + if kwarg["EnvironmentName"] == "test-env-not-using-cloudwatch": + return { + "ConfigurationSettings": [ + { + "OptionSettings": [ + { + "Namespace": "aws:elasticbeanstalk:cloudwatch:logs", + "OptionName": "StreamLogs", + "Value": "false", + }, + ], + } + ] + } + if kwarg["EnvironmentName"] == "test-env-using-cloudwatch": + return { + "ConfigurationSettings": [ + { + "OptionSettings": [ + { + "Namespace": "aws:elasticbeanstalk:cloudwatch:logs", + "OptionName": "StreamLogs", + "Value": "true", + }, + ], + } + ] + } + + return make_api_call(self, operation_name, kwarg) + + +class Test_elasticbeanstalk_environment_cloudwatch_logging_enabled: + @mock_aws + def test_elasticbeanstalk_no_environments(self): + elasticbeanstalk_client = client( + "elasticbeanstalk", region_name=AWS_REGION_EU_WEST_1 + ) + elasticbeanstalk_client.create_application(ApplicationName="test-app") + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_client", + new=ElasticBeanstalk(aws_provider), + ): + from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_environment_cloudwatch_logging_enabled import ( + elasticbeanstalk_environment_cloudwatch_logging_enabled, + ) + + check = elasticbeanstalk_environment_cloudwatch_logging_enabled() + result = check.execute() + assert len(result) == 0 + + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_elasticbeanstalk_environment_cloudwatch_not_enabled(self): + elasticbeanstalk_client = client( + "elasticbeanstalk", region_name=AWS_REGION_EU_WEST_1 + ) + elasticbeanstalk_client.create_application(ApplicationName="test-app") + environment = elasticbeanstalk_client.create_environment( + ApplicationName="test-app", + EnvironmentName="test-env-using-cloudwatch", + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_client", + new=ElasticBeanstalk(aws_provider), + ): + from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_environment_cloudwatch_logging_enabled import ( + elasticbeanstalk_environment_cloudwatch_logging_enabled, + ) + + check = elasticbeanstalk_environment_cloudwatch_logging_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Elastic Beanstalk environment test-env-using-cloudwatch is sending logs to CloudWatch Logs." + ) + assert result[0].resource_id == environment["EnvironmentName"] + assert result[0].resource_arn == environment["EnvironmentArn"] + assert result[0].region == AWS_REGION_EU_WEST_1 + + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_elasticbeanstalk_environment_cloudwatch_enabled(self): + elasticbeanstalk_client = client( + "elasticbeanstalk", region_name=AWS_REGION_EU_WEST_1 + ) + elasticbeanstalk_client.create_application(ApplicationName="test-app") + environment = elasticbeanstalk_client.create_environment( + ApplicationName="test-app", + EnvironmentName="test-env-not-using-cloudwatch", + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_client", + new=ElasticBeanstalk(aws_provider), + ): + from prowler.providers.aws.services.elasticbeanstalk.elasticbeanstalk_environment_cloudwatch_logging_enabled.elasticbeanstalk_environment_cloudwatch_logging_enabled import ( + elasticbeanstalk_environment_cloudwatch_logging_enabled, + ) + + check = elasticbeanstalk_environment_cloudwatch_logging_enabled() + result = check.execute() + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Elastic Beanstalk environment test-env-not-using-cloudwatch is not sending logs to CloudWatch Logs." + ) + assert result[0].resource_id == environment["EnvironmentName"] + assert result[0].resource_arn == environment["EnvironmentArn"] + assert result[0].region == AWS_REGION_EU_WEST_1