mirror of
https://github.com/ghndrx/prowler.git
synced 2026-02-10 14:55:00 +00:00
fix(security_hub): Handle user facing errors (#3456)
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user