feat(elasticbeanstalk): add new check elasticbeanstalk_cloudwatch_enabled (#5335)

Co-authored-by: Sergio <sergio@prowler.com>
This commit is contained in:
Mario Rodriguez Lopez
2024-10-10 21:32:31 +02:00
committed by GitHub
parent f8a8266c9d
commit c3e3381c63
4 changed files with 205 additions and 0 deletions
@@ -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 <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": ""
}
@@ -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
@@ -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