From 778edd5fec7d0cf8ebae6d1471d54fbb18db81ea Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Thu, 17 Oct 2024 20:33:42 +0200 Subject: [PATCH] feat(mq): add new check `mq_broker_auto_minor_version_upgrades` (#5431) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rubén De la Torre Vico --- .../__init__.py | 0 ..._auto_minor_version_upgrades.metadata.json | 32 ++++ .../mq_broker_auto_minor_version_upgrades.py | 23 +++ .../providers/aws/services/mq/mq_service.py | 19 +++ ...broker_auto_minor_version_upgrades_test.py | 139 ++++++++++++++++++ .../aws/services/mq/mq_service_test.py | 42 +++++- 6 files changed, 253 insertions(+), 2 deletions(-) create mode 100644 prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/__init__.py create mode 100644 prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.metadata.json create mode 100644 prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.py create mode 100644 tests/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades_test.py diff --git a/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/__init__.py b/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.metadata.json b/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.metadata.json new file mode 100644 index 0000000000..5d1bae069e --- /dev/null +++ b/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "mq_broker_auto_minor_version_upgrades", + "CheckTitle": "MQ Broker Auto Minor Version Upgrades should be enabled.", + "CheckType": [ + "Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls" + ], + "ServiceName": "mq", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:mq:region:account-id:broker:broker-id", + "Severity": "low", + "ResourceType": "AwsAmazonMQBroker", + "Description": "Ensure that automatic minor version upgrades are enabled on Amazon MQ brokers.", + "Risk": "Amazon MQ brokers without automatic minor version upgrades may miss critical updates, leaving them vulnerable to security risks, bugs, and performance issues.", + "RelatedUrl": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/upgrading-brokers.html#upgrading-brokers-automatic-upgrades", + "Remediation": { + "Code": { + "CLI": "aws mq update-broker --broker-id --auto-minor-version-upgrade", + "NativeIaC": "https://docs.prowler.com/checks/aws/general-policies/ensure-aws-mqbrokers-minor-version-updates-are-enabled/", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/mq-controls.html#mq-3", + "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/MQ/auto-minor-version-upgrade.html" + }, + "Recommendation": { + "Text": "Ensure that automatic minor version upgrades are enabled on Amazon MQ brokers to receive the latest security patches and improvements automatically.", + "Url": "https://docs.aws.amazon.com/amazon-mq/latest/developer-guide/upgrading-brokers.html#upgrading-brokers-automatic-upgrades.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.py b/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.py new file mode 100644 index 0000000000..c1cccd8e69 --- /dev/null +++ b/prowler/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades.py @@ -0,0 +1,23 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.mq.mq_client import mq_client + + +class mq_broker_auto_minor_version_upgrades(Check): + def execute(self): + findings = [] + for broker in mq_client.brokers.values(): + report = Check_Report_AWS(self.metadata()) + report.region = broker.region + report.resource_id = broker.id + report.resource_arn = broker.arn + report.resource_tags = broker.tags + report.status = "PASS" + report.status_extended = f"MQ Broker {broker.name} does have automated minor version upgrades enabled." + + if not broker.auto_minor_version_upgrade: + report.status = "FAIL" + report.status_extended = f"MQ Broker {broker.name} does not have automated minor version upgrades enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/mq/mq_service.py b/prowler/providers/aws/services/mq/mq_service.py index efc9fcbe92..7de9265347 100644 --- a/prowler/providers/aws/services/mq/mq_service.py +++ b/prowler/providers/aws/services/mq/mq_service.py @@ -1,3 +1,5 @@ +from typing import Dict, List, Optional + from pydantic import BaseModel from prowler.lib.logger import logger @@ -11,6 +13,7 @@ class MQ(AWSService): super().__init__("mq", provider) self.brokers = {} self.__threading_call__(self._list_brokers) + self.__threading_call__(self._describe_broker, self.brokers.values()) def _list_brokers(self, regional_client): logger.info("MQ - Listing brokers...") @@ -31,6 +34,20 @@ class MQ(AWSService): f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) + def _describe_broker(self, broker): + try: + describe_broker = self.regional_clients[broker.region].describe_broker( + BrokerId=broker.id + ) + broker.auto_minor_version_upgrade = describe_broker.get( + "AutoMinorVersionUpgrade", False + ) + broker.tags = [describe_broker.get("Tags", {})] + except Exception as error: + logger.error( + f"{broker.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + class Broker(BaseModel): """Broker model for MQ""" @@ -39,3 +56,5 @@ class Broker(BaseModel): name: str id: str region: str + auto_minor_version_upgrade: bool = False + tags: Optional[List[Dict[str, str]]] diff --git a/tests/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades_test.py b/tests/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades_test.py new file mode 100644 index 0000000000..352a2ec5b5 --- /dev/null +++ b/tests/providers/aws/services/mq/mq_broker_auto_minor_version_upgrades/mq_broker_auto_minor_version_upgrades_test.py @@ -0,0 +1,139 @@ +from unittest import mock + +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_US_EAST_1, + set_mocked_aws_provider, +) + + +class Test_mq_broker_auto_minor_version_upgrades: + @mock_aws + def test_no_brokers(self): + from prowler.providers.aws.services.mq.mq_service import MQ + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.mq.mq_broker_auto_minor_version_upgrades.mq_broker_auto_minor_version_upgrades.mq_client", + new=MQ(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.mq.mq_broker_auto_minor_version_upgrades.mq_broker_auto_minor_version_upgrades import ( + mq_broker_auto_minor_version_upgrades, + ) + + check = mq_broker_auto_minor_version_upgrades() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_broker_auto_minor_version_upgrades_enabled(self): + mq_client = client("mq", region_name=AWS_REGION_US_EAST_1) + broker_name = "test-broker" + broker_id = mq_client.create_broker( + BrokerName=broker_name, + EngineType="ACTIVEMQ", + EngineVersion="5.15.0", + HostInstanceType="mq.t2.micro", + Users=[ + { + "Username": "admin", + "Password": "admin", + }, + ], + DeploymentMode="SINGLE_INSTANCE", + PubliclyAccessible=False, + AutoMinorVersionUpgrade=True, + )["BrokerId"] + + from prowler.providers.aws.services.mq.mq_service import MQ + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.mq.mq_broker_auto_minor_version_upgrades.mq_broker_auto_minor_version_upgrades.mq_client", + new=MQ(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.mq.mq_broker_auto_minor_version_upgrades.mq_broker_auto_minor_version_upgrades import ( + mq_broker_auto_minor_version_upgrades, + ) + + check = mq_broker_auto_minor_version_upgrades() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"MQ Broker {broker_name} does have automated minor version upgrades enabled." + ) + assert result[0].resource_id == broker_id + assert ( + result[0].resource_arn + == f"arn:{aws_provider.identity.partition}:mq:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:broker:{broker_id}" + ) + assert result[0].region == AWS_REGION_US_EAST_1 + + @mock_aws + def test_broker_auto_minor_version_upgrades_disabled(self): + mq_client = client("mq", region_name=AWS_REGION_US_EAST_1) + broker_name = "test-broker" + broker_id = mq_client.create_broker( + BrokerName=broker_name, + EngineType="ACTIVEMQ", + EngineVersion="5.15.0", + HostInstanceType="mq.t2.micro", + Users=[ + { + "Username": "admin", + "Password": "admin", + }, + ], + DeploymentMode="SINGLE_INSTANCE", + PubliclyAccessible=False, + AutoMinorVersionUpgrade=False, + )["BrokerId"] + + from prowler.providers.aws.services.mq.mq_service import MQ + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.mq.mq_broker_auto_minor_version_upgrades.mq_broker_auto_minor_version_upgrades.mq_client", + new=MQ(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.mq.mq_broker_auto_minor_version_upgrades.mq_broker_auto_minor_version_upgrades import ( + mq_broker_auto_minor_version_upgrades, + ) + + check = mq_broker_auto_minor_version_upgrades() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"MQ Broker {broker_name} does not have automated minor version upgrades enabled." + ) + assert result[0].resource_id == broker_id + assert ( + result[0].resource_arn + == f"arn:{aws_provider.identity.partition}:mq:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:broker:{broker_id}" + ) + assert result[0].region == AWS_REGION_US_EAST_1 diff --git a/tests/providers/aws/services/mq/mq_service_test.py b/tests/providers/aws/services/mq/mq_service_test.py index 4771026a6b..3c25f38b9a 100644 --- a/tests/providers/aws/services/mq/mq_service_test.py +++ b/tests/providers/aws/services/mq/mq_service_test.py @@ -34,7 +34,7 @@ class Test_MQ_Service: # Test MQ List Brokers @mock_aws def test_list_brokers(self): - # Generate MQ client + # Generate moto MQ client mq_client = client("mq", region_name=AWS_REGION_EU_WEST_1) broker = mq_client.create_broker( AutoMinorVersionUpgrade=True, @@ -55,7 +55,7 @@ class Test_MQ_Service: ) broker_arn = broker["BrokerArn"] - # MQ Client for this test class + # MQ client for this test class aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) mq = MQ(aws_provider) @@ -64,3 +64,41 @@ class Test_MQ_Service: assert mq.brokers[broker_arn].name == "my-broker" assert mq.brokers[broker_arn].region == AWS_REGION_EU_WEST_1 assert mq.brokers[broker_arn].id == broker["BrokerId"] + + # Test MQ Describe Broker + @mock_aws + def test_describe_broker(self): + # Generate moto MQ client + mq_client = client("mq", region_name=AWS_REGION_EU_WEST_1) + broker = mq_client.create_broker( + AutoMinorVersionUpgrade=True, + BrokerName="my-broker", + DeploymentMode="SINGLE_INSTANCE", + EngineType="ActiveMQ", + EngineVersion="5.15.0", + HostInstanceType="mq.t2.micro", + PubliclyAccessible=True, + Users=[ + { + "ConsoleAccess": False, + "Groups": [], + "Password": "password", + "Username": "user", + } + ], + Tags={"key": "value"}, + ) + broker_arn = broker["BrokerArn"] + broker["BrokerId"] + + # MQ client for this test class + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + mq = MQ(aws_provider) + + assert len(mq.brokers) == 1 + assert mq.brokers[broker_arn].arn == broker_arn + assert mq.brokers[broker_arn].name == "my-broker" + assert mq.brokers[broker_arn].region == AWS_REGION_EU_WEST_1 + assert mq.brokers[broker_arn].id == broker["BrokerId"] + assert mq.brokers[broker_arn].auto_minor_version_upgrade + assert mq.brokers[broker_arn].tags == [{"key": "value"}]