fix(security_hub): Handle user facing errors (#3456)

This commit is contained in:
Pepe Fagoaga
2024-02-28 10:03:43 +01:00
committed by GitHub
parent ab437fb459
commit 64aa0435e8
2 changed files with 144 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
from boto3 import session from boto3 import session
from botocore.client import ClientError
from prowler.config.config import timestamp_utc from prowler.config.config import timestamp_utc
from prowler.lib.logger import logger from prowler.lib.logger import logger
@@ -11,7 +12,7 @@ SECURITY_HUB_MAX_BATCH = 100
def prepare_security_hub_findings( def prepare_security_hub_findings(
findings: [], audit_info: AWS_Audit_Info, output_options, enabled_regions: [] findings: list, audit_info: AWS_Audit_Info, output_options, enabled_regions: list
) -> dict: ) -> dict:
security_hub_findings_per_region = {} security_hub_findings_per_region = {}
@@ -72,15 +73,32 @@ def verify_security_hub_integration_enabled_per_region(
if security_hub_prowler_integration_arn not in str( if security_hub_prowler_integration_arn not in str(
security_hub_client.list_enabled_products_for_import() security_hub_client.list_enabled_products_for_import()
): ):
logger.error( logger.warning(
f"Security Hub is enabled in {region} but Prowler integration does not accept findings. More info: https://docs.prowler.cloud/en/latest/tutorials/aws/securityhub/" f"Security Hub is enabled in {region} but Prowler integration does not accept findings. More info: https://docs.prowler.cloud/en/latest/tutorials/aws/securityhub/"
) )
else: else:
prowler_integration_enabled = True prowler_integration_enabled = True
# Handle all the permissions / configuration errors
except ClientError as client_error:
# Check if Account is subscribed to Security Hub
error_code = client_error.response["Error"]["Code"]
error_message = client_error.response["Error"]["Message"]
if (
error_code == "InvalidAccessException"
and f"Account {aws_account_number} is not subscribed to AWS Security Hub in region {region}"
in error_message
):
logger.warning(
f"{client_error.__class__.__name__} -- [{client_error.__traceback__.tb_lineno}]: {client_error}"
)
else:
logger.error(
f"{client_error.__class__.__name__} -- [{client_error.__traceback__.tb_lineno}]: {client_error}"
)
except Exception as error: except Exception as error:
logger.error( logger.error(
f"{error.__class__.__name__} -- [{error.__traceback__.tb_lineno}]:{error} in region {region}" f"{error.__class__.__name__} -- [{error.__traceback__.tb_lineno}]: {error}"
) )
finally: finally:
@@ -169,7 +187,7 @@ def resolve_security_hub_previous_findings(
def __send_findings_to_security_hub__( def __send_findings_to_security_hub__(
findings: [dict], region: str, security_hub_client findings: list[dict], region: str, security_hub_client
): ):
"""Private function send_findings_to_security_hub chunks the findings in groups of 100 findings and send them to AWS Security Hub. It returns the number of sent findings.""" """Private function send_findings_to_security_hub chunks the findings in groups of 100 findings and send them to AWS Security Hub. It returns the number of sent findings."""
success_count = 0 success_count = 0

View File

@@ -1,7 +1,9 @@
from logging import ERROR, WARNING
from os import path from os import path
import botocore import botocore
from boto3 import session from boto3 import session
from botocore.client import ClientError
from mock import MagicMock, patch from mock import MagicMock, patch
from prowler.config.config import prowler_version, timestamp_utc from prowler.config.config import prowler_version, timestamp_utc
@@ -130,6 +132,126 @@ class Test_SecurityHub:
AWS_COMMERCIAL_PARTITION, AWS_REGION_EU_WEST_1, session, AWS_ACCOUNT_NUMBER AWS_COMMERCIAL_PARTITION, AWS_REGION_EU_WEST_1, session, AWS_ACCOUNT_NUMBER
) )
def test_verify_security_hub_integration_enabled_per_region_security_hub_disabled(
self, caplog
):
caplog.set_level(WARNING)
session = self.set_mocked_session(AWS_REGION_EU_WEST_1)
with patch(
"prowler.providers.aws.lib.security_hub.security_hub.session.Session.client",
) as mock_security_hub:
error_message = f"Account {AWS_ACCOUNT_NUMBER} is not subscribed to AWS Security Hub in region {AWS_REGION_EU_WEST_1}"
error_code = "InvalidAccessException"
error_response = {
"Error": {
"Code": error_code,
"Message": error_message,
}
}
operation_name = "DescribeHub"
mock_security_hub.side_effect = ClientError(error_response, operation_name)
assert not verify_security_hub_integration_enabled_per_region(
AWS_COMMERCIAL_PARTITION,
AWS_REGION_EU_WEST_1,
session,
AWS_ACCOUNT_NUMBER,
)
assert caplog.record_tuples == [
(
"root",
WARNING,
f"ClientError -- [68]: An error occurred ({error_code}) when calling the {operation_name} operation: {error_message}",
)
]
def test_verify_security_hub_integration_enabled_per_region_prowler_not_subscribed(
self, caplog
):
caplog.set_level(WARNING)
session = self.set_mocked_session(AWS_REGION_EU_WEST_1)
with patch(
"prowler.providers.aws.lib.security_hub.security_hub.session.Session.client",
) as mock_security_hub:
mock_security_hub.describe_hub.return_value = None
mock_security_hub.list_enabled_products_for_import.return_value = []
assert not verify_security_hub_integration_enabled_per_region(
AWS_COMMERCIAL_PARTITION,
AWS_REGION_EU_WEST_1,
session,
AWS_ACCOUNT_NUMBER,
)
assert caplog.record_tuples == [
(
"root",
WARNING,
f"Security Hub is enabled in {AWS_REGION_EU_WEST_1} but Prowler integration does not accept findings. More info: https://docs.prowler.cloud/en/latest/tutorials/aws/securityhub/",
)
]
def test_verify_security_hub_integration_enabled_per_region_another_ClientError(
self, caplog
):
caplog.set_level(WARNING)
session = self.set_mocked_session(AWS_REGION_EU_WEST_1)
with patch(
"prowler.providers.aws.lib.security_hub.security_hub.session.Session.client",
) as mock_security_hub:
error_message = f"Another exception in region {AWS_REGION_EU_WEST_1}"
error_code = "AnotherException"
error_response = {
"Error": {
"Code": error_code,
"Message": error_message,
}
}
operation_name = "DescribeHub"
mock_security_hub.side_effect = ClientError(error_response, operation_name)
assert not verify_security_hub_integration_enabled_per_region(
AWS_COMMERCIAL_PARTITION,
AWS_REGION_EU_WEST_1,
session,
AWS_ACCOUNT_NUMBER,
)
assert caplog.record_tuples == [
(
"root",
ERROR,
f"ClientError -- [68]: An error occurred ({error_code}) when calling the {operation_name} operation: {error_message}",
)
]
def test_verify_security_hub_integration_enabled_per_region_another_Exception(
self, caplog
):
caplog.set_level(WARNING)
session = self.set_mocked_session(AWS_REGION_EU_WEST_1)
with patch(
"prowler.providers.aws.lib.security_hub.security_hub.session.Session.client",
) as mock_security_hub:
error_message = f"Another exception in region {AWS_REGION_EU_WEST_1}"
mock_security_hub.side_effect = Exception(error_message)
assert not verify_security_hub_integration_enabled_per_region(
AWS_COMMERCIAL_PARTITION,
AWS_REGION_EU_WEST_1,
session,
AWS_ACCOUNT_NUMBER,
)
assert caplog.record_tuples == [
(
"root",
ERROR,
f"Exception -- [68]: {error_message}",
)
]
def test_prepare_security_hub_findings_enabled_region_not_quiet(self): def test_prepare_security_hub_findings_enabled_region_not_quiet(self):
enabled_regions = [AWS_REGION_EU_WEST_1] enabled_regions = [AWS_REGION_EU_WEST_1]
output_options = self.set_mocked_output_options(is_quiet=False) output_options = self.set_mocked_output_options(is_quiet=False)