diff --git a/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/__init__.py b/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions.metadata.json b/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions.metadata.json new file mode 100644 index 0000000000..80676488bd --- /dev/null +++ b/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "waf_regional_rule_with_conditions", + "CheckTitle": "AWS WAF Classic Regional Rules Should Have at Least One Condition.", + "CheckType": [ + "Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls" + ], + "ServiceName": "waf", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:waf-regional:region:account-id:rule/rule-id", + "Severity": "medium", + "ResourceType": "AwsWafRegionalRule", + "Description": "Ensure that every AWS WAF Classic Regional Rule contains at least one condition.", + "Risk": "An AWS WAF Classic Regional rule without any conditions cannot inspect or filter traffic, potentially allowing malicious requests to pass unchecked.", + "RelatedUrl": "https://docs.aws.amazon.com/config/latest/developerguide/waf-regional-rule-not-empty.html", + "Remediation": { + "Code": { + "CLI": "aws waf-regional update-rule --rule-id --change-token --updates '[{\"Action\":\"INSERT\",\"Predicate\":{\"Negated\":false,\"Type\":\"IPMatch\",\"DataId\":\"\"}}]' --region ", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/waf-controls.html#waf-2", + "Terraform": "" + }, + "Recommendation": { + "Text": "Ensure that every AWS WAF Classic Regional rule has at least one condition to properly inspect and manage web traffic.", + "Url": "https://docs.aws.amazon.com/waf/latest/developerguide/classic-web-acl-rules-editing.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions.py b/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions.py new file mode 100644 index 0000000000..9704dfc986 --- /dev/null +++ b/prowler/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions.py @@ -0,0 +1,27 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.waf.wafregional_client import wafregional_client + + +class waf_regional_rule_with_conditions(Check): + def execute(self): + findings = [] + for rule in wafregional_client.rules.values(): + report = Check_Report_AWS(self.metadata()) + report.region = rule.region + report.resource_id = rule.id + report.resource_arn = rule.arn + report.resource_tags = rule.tags + report.status = "FAIL" + report.status_extended = ( + f"AWS WAF Regional Rule {rule.name} does not have any conditions." + ) + + if rule.predicates: + report.status = "PASS" + report.status_extended = ( + f"AWS WAF Regional Rule {rule.name} has at least one condition." + ) + + findings.append(report) + + return findings diff --git a/tests/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions_test.py b/tests/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions_test.py new file mode 100644 index 0000000000..f9a54e90d3 --- /dev/null +++ b/tests/providers/aws/services/waf/waf_regional_rule_with_conditions/waf_regional_rule_with_conditions_test.py @@ -0,0 +1,167 @@ +from unittest import mock +from unittest.mock import patch + +import botocore +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_US_EAST_1, + set_mocked_aws_provider, +) + +RULE_ID = "test-rule-id" + +# Original botocore _make_api_call function +orig = botocore.client.BaseClient._make_api_call + + +# Mocked botocore _make_api_call function +def mock_make_api_call_compliant_rule(self, operation_name, kwarg): + if operation_name == "ListRules": + return { + "Rules": [ + { + "RuleId": RULE_ID, + "Name": RULE_ID, + }, + ] + } + if operation_name == "GetRule": + return { + "Rule": { + "RuleId": RULE_ID, + "Predicates": [ + { + "Negated": False, + "Type": "IPMatch", + "DataId": "IPSetId", + }, + ], + } + } + return orig(self, operation_name, kwarg) + + +def mock_make_api_call_non_compliant_rule(self, operation_name, kwarg): + if operation_name == "ListRules": + return { + "Rules": [ + { + "RuleId": RULE_ID, + "Name": RULE_ID, + }, + ] + } + if operation_name == "GetRule": + return { + "Rule": { + "RuleId": RULE_ID, + "Predicates": [], + } + } + return orig(self, operation_name, kwarg) + + +class Test_waf_regional_rule_with_conditions: + @mock_aws + def test_no_rules(self): + from prowler.providers.aws.services.waf.waf_service import WAFRegional + + 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.waf.waf_regional_rule_with_conditions.waf_regional_rule_with_conditions.wafregional_client", + new=WAFRegional(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.waf.waf_regional_rule_with_conditions.waf_regional_rule_with_conditions import ( + waf_regional_rule_with_conditions, + ) + + check = waf_regional_rule_with_conditions() + result = check.execute() + + assert len(result) == 0 + + @patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_compliant_rule, + ) + @mock_aws + def test_waf_rules_with_condition(self): + from prowler.providers.aws.services.waf.waf_service import WAFRegional + + 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.waf.waf_regional_rule_with_conditions.waf_regional_rule_with_conditions.wafregional_client", + new=WAFRegional(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.waf.waf_regional_rule_with_conditions.waf_regional_rule_with_conditions import ( + waf_regional_rule_with_conditions, + ) + + check = waf_regional_rule_with_conditions() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == f"AWS WAF Regional Rule {RULE_ID} has at least one condition." + ) + assert result[0].resource_id == RULE_ID + assert ( + result[0].resource_arn + == f"arn:aws:waf-regional:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:rule/{RULE_ID}" + ) + assert result[0].region == AWS_REGION_US_EAST_1 + + @patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_non_compliant_rule, + ) + @mock_aws + def test_waf_rules_without_condition(self): + from prowler.providers.aws.services.waf.waf_service import WAFRegional + + 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.waf.waf_regional_rule_with_conditions.waf_regional_rule_with_conditions.wafregional_client", + new=WAFRegional(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.waf.waf_regional_rule_with_conditions.waf_regional_rule_with_conditions import ( + waf_regional_rule_with_conditions, + ) + + check = waf_regional_rule_with_conditions() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == f"AWS WAF Regional Rule {RULE_ID} does not have any conditions." + ) + assert result[0].resource_id == RULE_ID + assert ( + result[0].resource_arn + == f"arn:aws:waf-regional:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:rule/{RULE_ID}" + ) + assert result[0].region == AWS_REGION_US_EAST_1