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 botocore.client import ClientError
from prowler.config.config import timestamp_utc
from prowler.lib.logger import logger
@@ -11,7 +12,7 @@ SECURITY_HUB_MAX_BATCH = 100
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:
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(
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/"
)
else:
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:
logger.error(
f"{error.__class__.__name__} -- [{error.__traceback__.tb_lineno}]:{error} in region {region}"
f"{error.__class__.__name__} -- [{error.__traceback__.tb_lineno}]: {error}"
)
finally:
@@ -169,7 +187,7 @@ def resolve_security_hub_previous_findings(
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."""
success_count = 0

View File

@@ -1,7 +1,9 @@
from logging import ERROR, WARNING
from os import path
import botocore
from boto3 import session
from botocore.client import ClientError
from mock import MagicMock, patch
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
)
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):
enabled_regions = [AWS_REGION_EU_WEST_1]
output_options = self.set_mocked_output_options(is_quiet=False)