From f2301d5ed624882da394e3733e0fae59ea14e053 Mon Sep 17 00:00:00 2001 From: Hugo Pereira Brito <101209179+HugoPBrito@users.noreply.github.com> Date: Fri, 4 Oct 2024 17:41:26 +0200 Subject: [PATCH] feat(networkfirewall): add new check `networkfirewall_policy_default_action_fragmented_packets ` (#5244) Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com> --- .../__init__.py | 0 ...lt_action_fragmented_packets.metadata.json | 32 +++ ...olicy_default_action_fragmented_packets.py | 28 +++ .../networkfirewall_service.py | 9 +- ..._default_action_fragmented_packets_test.py | 188 ++++++++++++++++++ 5 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/__init__.py create mode 100644 prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.metadata.json create mode 100644 prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.py create mode 100644 tests/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets_test.py diff --git a/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/__init__.py b/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.metadata.json b/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.metadata.json new file mode 100644 index 0000000000..983201b0c5 --- /dev/null +++ b/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "networkfirewall_policy_default_action_fragmented_packets", + "CheckTitle": "Default action for fragmented packets is set to drop or forward.", + "CheckType": [ + "Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls" + ], + "ServiceName": "network-firewall", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:network-firewall::account-id:firewall/firewall-name", + "Severity": "medium", + "ResourceType": "AwsNetworkFirewallFirewall", + "Description": "NetorwFirewall firewall policy default action for fragmented packets is set to drop or forward.", + "Risk": "If the default action for fragmented packets is set to 'Pass', unintended or potentially malicious traffic may bypass filtering, exposing the network to security threats.", + "RelatedUrl": "https://docs.aws.amazon.com/network-firewall/latest/developerguide/stateless-default-actions.html", + "Remediation": { + "Code": { + "CLI": "aws network-firewall update-firewall-policy --firewall-policy-arn --stateless-default-actions aws:drop", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/networkfirewall-controls.html#networkfirewall-5", + "Terraform": "" + }, + "Recommendation": { + "Text": "Update the firewall policy to ensure fragmented packets are either dropped or forwarded to stateful rule groups for additional filtering, reducing the risk of unwanted traffic entering the network.", + "Url": "https://docs.aws.amazon.com/network-firewall/latest/developerguide/firewall-policy-updating.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.py b/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.py new file mode 100644 index 0000000000..5b7884a969 --- /dev/null +++ b/prowler/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets.py @@ -0,0 +1,28 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.networkfirewall.networkfirewall_client import ( + networkfirewall_client, +) + + +class networkfirewall_policy_default_action_fragmented_packets(Check): + def execute(self): + findings = [] + for arn, firewall in networkfirewall_client.network_firewalls.items(): + report = Check_Report_AWS(self.metadata()) + report.region = firewall.region + report.resource_id = firewall.name + report.resource_arn = arn + report.resource_tags = firewall.tags + report.status = "FAIL" + report.status_extended = f"Network Firewall {firewall.name} policy does not drop or forward fragmented packets by default." + + if ( + "aws:drop" in firewall.default_stateless_frag_actions + or "aws:forward_to_sfe" in firewall.default_stateless_frag_actions + ): + report.status = "PASS" + report.status_extended = f"Network Firewall {firewall.name} policy does drop or forward fragmented packets by default." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/networkfirewall/networkfirewall_service.py b/prowler/providers/aws/services/networkfirewall/networkfirewall_service.py index 97413a8033..47b278dd98 100644 --- a/prowler/providers/aws/services/networkfirewall/networkfirewall_service.py +++ b/prowler/providers/aws/services/networkfirewall/networkfirewall_service.py @@ -37,9 +37,8 @@ class NetworkFirewall(AWSService): network_firewall["FirewallArn"], self.audit_resources ) ): - self.network_firewalls[ - network_firewall.get("FirewallArn", "") - ] = Firewall( + arn = network_firewall.get("FirewallArn", "") + self.network_firewalls[arn] = Firewall( arn=network_firewall.get("FirewallArn"), region=regional_client.region, name=network_firewall.get("FirewallName"), @@ -95,6 +94,9 @@ class NetworkFirewall(AWSService): group.get("ResourceArn", "") for group in firewall_policy.get("StatefulRuleGroupReferences", []) ] + network_firewall.default_stateless_frag_actions = firewall_policy.get( + "StatelessFragmentDefaultActions", [] + ) except Exception as error: logger.error( f"{error.__class__.__name__}:{error.__traceback__.tb_lineno} -- {error}" @@ -184,6 +186,7 @@ class Firewall(BaseModel): tags: list = [] encryption_type: str = None deletion_protection: bool = False + default_stateless_frag_actions: list = [] subnet_mappings: list[Subnet] = [] logging_configuration: Optional[list[LoggingConfiguration]] stateless_rule_groups: list[str] = [] diff --git a/tests/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets_test.py b/tests/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets_test.py new file mode 100644 index 0000000000..cc7c8a17b1 --- /dev/null +++ b/tests/providers/aws/services/networkfirewall/networkfirewall_policy_default_action_fragmented_packets/networkfirewall_policy_default_action_fragmented_packets_test.py @@ -0,0 +1,188 @@ +from unittest import mock + +from prowler.providers.aws.services.networkfirewall.networkfirewall_service import ( + Firewall, +) +from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider + +FIREWALL_ARN = "arn:aws:network-firewall:us-east-1:123456789012:firewall/my-firewall" +FIREWALL_NAME = "my-firewall" +VPC_ID_PROTECTED = "vpc-12345678901234567" +VPC_ID_UNPROTECTED = "vpc-12345678901234568" +POLICY_ARN = "arn:aws:network-firewall:us-east-1:123456789012:firewall-policy/my-policy" + + +class Test_networkfirewall_policy_default_action_fragmented_packets: + def test_no_networkfirewall(self): + networkfirewall_client = mock.MagicMock + networkfirewall_client.provider = set_mocked_aws_provider( + [AWS_REGION_US_EAST_1] + ) + networkfirewall_client.region = AWS_REGION_US_EAST_1 + networkfirewall_client.network_firewalls = {} + + 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, + ): + with mock.patch( + "prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_client", + new=networkfirewall_client, + ): + # Test Check + from prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets import ( + networkfirewall_policy_default_action_fragmented_packets, + ) + + check = networkfirewall_policy_default_action_fragmented_packets() + result = check.execute() + + assert len(result) == 0 + + def test_networkfirewall_default_stateless_action_drop(self): + networkfirewall_client = mock.MagicMock + networkfirewall_client.provider = set_mocked_aws_provider( + [AWS_REGION_US_EAST_1] + ) + networkfirewall_client.region = AWS_REGION_US_EAST_1 + networkfirewall_client.network_firewalls = { + FIREWALL_ARN: Firewall( + arn=FIREWALL_ARN, + name=FIREWALL_NAME, + region=AWS_REGION_US_EAST_1, + policy_arn=POLICY_ARN, + vpc_id=VPC_ID_PROTECTED, + tags=[], + encryption_type="CUSTOMER_KMS", + deletion_protection=False, + default_stateless_frag_actions=["aws:drop"], + ) + } + 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, + ): + with mock.patch( + "prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_client", + new=networkfirewall_client, + ): + # Test Check + from prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets import ( + networkfirewall_policy_default_action_fragmented_packets, + ) + + check = networkfirewall_policy_default_action_fragmented_packets() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Network Firewall {FIREWALL_NAME} policy does drop or forward fragmented packets by default." + ) + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == FIREWALL_NAME + assert result[0].resource_tags == [] + assert result[0].resource_arn == FIREWALL_ARN + + def test_networkfirewall_default_stateless_action_forward(self): + networkfirewall_client = mock.MagicMock + networkfirewall_client.provider = set_mocked_aws_provider( + [AWS_REGION_US_EAST_1] + ) + networkfirewall_client.region = AWS_REGION_US_EAST_1 + networkfirewall_client.network_firewalls = { + FIREWALL_ARN: Firewall( + arn=FIREWALL_ARN, + name=FIREWALL_NAME, + region=AWS_REGION_US_EAST_1, + policy_arn=POLICY_ARN, + vpc_id=VPC_ID_PROTECTED, + tags=[], + encryption_type="CUSTOMER_KMS", + deletion_protection=True, + default_stateless_frag_actions=["aws:forward_to_sfe"], + ) + } + + 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, + ): + with mock.patch( + "prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_client", + new=networkfirewall_client, + ): + # Test Check + from prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets import ( + networkfirewall_policy_default_action_fragmented_packets, + ) + + check = networkfirewall_policy_default_action_fragmented_packets() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"Network Firewall {FIREWALL_NAME} policy does drop or forward fragmented packets by default." + ) + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == FIREWALL_NAME + assert result[0].resource_tags == [] + assert result[0].resource_arn == FIREWALL_ARN + + def test_networkfirewall_default_stateless_action_pass(self): + networkfirewall_client = mock.MagicMock + networkfirewall_client.provider = set_mocked_aws_provider( + [AWS_REGION_US_EAST_1] + ) + networkfirewall_client.region = AWS_REGION_US_EAST_1 + networkfirewall_client.network_firewalls = { + FIREWALL_ARN: Firewall( + arn=FIREWALL_ARN, + name=FIREWALL_NAME, + region=AWS_REGION_US_EAST_1, + policy_arn=POLICY_ARN, + vpc_id=VPC_ID_PROTECTED, + tags=[], + encryption_type="CUSTOMER_KMS", + deletion_protection=True, + default_stateless_frag_actions=["aws:pass"], + ) + } + + 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, + ): + with mock.patch( + "prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_client", + new=networkfirewall_client, + ): + # Test Check + from prowler.providers.aws.services.networkfirewall.networkfirewall_policy_default_action_fragmented_packets.networkfirewall_policy_default_action_fragmented_packets import ( + networkfirewall_policy_default_action_fragmented_packets, + ) + + check = networkfirewall_policy_default_action_fragmented_packets() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"Network Firewall {FIREWALL_NAME} policy does not drop or forward fragmented packets by default." + ) + assert result[0].region == AWS_REGION_US_EAST_1 + assert result[0].resource_id == FIREWALL_NAME + assert result[0].resource_tags == [] + assert result[0].resource_arn == FIREWALL_ARN