feat(wafv2): add new check wafv2_webacl_with_rules (#5376)

Co-authored-by: Sergio Garcia <38561120+sergargar@users.noreply.github.com>
This commit is contained in:
Hugo Pereira Brito
2024-10-16 17:44:41 +02:00
committed by GitHub
parent 402e0e3107
commit d07f1e982a
5 changed files with 205 additions and 1 deletions
@@ -9,7 +9,7 @@
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:wafv2:region:account-id:webacl/webacl-id",
"Severity": "medium",
"ResourceType": "AwsWafv2WebAcl",
"ResourceType": "AwsWafv2RuleGroup",
"Description": "This control checks whether an AWS WAF rule or rule group has Amazon CloudWatch metrics enabled. The control fails if the rule or rule group doesn't have CloudWatch metrics enabled.",
"Risk": "Without CloudWatch Metrics enabled on AWS WAF rules or rule groups, it's challenging to monitor traffic flow effectively. This reduces visibility into potential security threats, such as malicious activities or unusual traffic patterns.",
"RelatedUrl": "https://docs.aws.amazon.com/waf/latest/APIReference/API_UpdateRuleGroup.html",
@@ -0,0 +1,32 @@
{
"Provider": "aws",
"CheckID": "wafv2_webacl_with_rules",
"CheckTitle": "Check if AWS WAFv2 WebACL has at least one rule or rule group.",
"CheckType": [
"Software and Configuration Checks/Industry and Regulatory Standards/NIST 800-53 Controls"
],
"ServiceName": "wafv2",
"SubServiceName": "",
"ResourceIdTemplate": "arn:partition:wafv2:region:account-id:webacl/webacl-id",
"Severity": "medium",
"ResourceType": "AwsWafv2WebAcl",
"Description": "Check if AWS WAFv2 WebACL has at least one rule or rule group associated with it.",
"Risk": "An empty AWS WAF web ACL allows all web traffic to pass without inspection or control, exposing resources to potential security threats and attacks.",
"RelatedUrl": "https://docs.aws.amazon.com/waf/latest/APIReference/API_Rule.html",
"Remediation": {
"Code": {
"CLI": "aws wafv2 update-web-acl --id <web-acl-id> --scope <scope> --default-action <default-action> --rules <rules>",
"NativeIaC": "https://docs.prowler.com/checks/aws/networking-policies/bc_aws_networking_64/",
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/waf-controls.html#waf-10",
"Terraform": ""
},
"Recommendation": {
"Text": "Ensure that each AWS WAF web ACL contains at least one rule or rule group to effectively manage and inspect incoming HTTP(S) web requests.",
"Url": "https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-editing.html"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,23 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.wafv2.wafv2_client import wafv2_client
class wafv2_webacl_with_rules(Check):
def execute(self):
findings = []
for web_acl in wafv2_client.web_acls.values():
report = Check_Report_AWS(self.metadata())
report.region = web_acl.region
report.resource_id = web_acl.id
report.resource_arn = web_acl.arn
report.resource_tags = web_acl.tags
report.status = "FAIL"
report.status_extended = f"AWS WAFv2 Web ACL {web_acl.name} does not have any rules or rule groups attached."
if web_acl.rules or web_acl.rule_groups:
report.status = "PASS"
report.status_extended = f"AWS WAFv2 Web ACL {web_acl.name} does have rules or rule groups attached."
findings.append(report)
return findings
@@ -0,0 +1,149 @@
from unittest import mock
from uuid import uuid4
from prowler.providers.aws.services.wafv2.wafv2_service import Rule, WebAclv2
from tests.providers.aws.utils import AWS_ACCOUNT_NUMBER, AWS_REGION_EU_WEST_1
waf_id = str(uuid4())
waf_name = "waf-example"
waf_arn = f"arn:aws:wafv2:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:regional/webacl/{waf_name}/{waf_id}"
class Test_wafv2_webacl_with_rules:
def test_no_web_acls(self):
wafv2_client = mock.MagicMock
wafv2_client.web_acls = {}
with mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_service.WAFv2",
new=wafv2_client,
), mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_client.wafv2_client",
new=wafv2_client,
):
from prowler.providers.aws.services.wafv2.wafv2_webacl_with_rules.wafv2_webacl_with_rules import (
wafv2_webacl_with_rules,
)
check = wafv2_webacl_with_rules()
result = check.execute()
assert len(result) == 0
def test_wafv2_wb_acl_with_rule(self):
wafv2_client = mock.MagicMock
wafv2_client.enabled = True
wafv2_client.web_acls = {
waf_arn: WebAclv2(
arn=waf_arn,
name=waf_name,
id=waf_id,
albs=[],
user_pools=[],
region=AWS_REGION_EU_WEST_1,
logging_enabled=True,
tags=[{"Key": "Name", "Value": waf_name}],
rules=[Rule(name="rule1", cloudwatch_metrics_enabled=True)],
)
}
with mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_service.WAFv2",
new=wafv2_client,
), mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_client.wafv2_client",
new=wafv2_client,
):
from prowler.providers.aws.services.wafv2.wafv2_webacl_with_rules.wafv2_webacl_with_rules import (
wafv2_webacl_with_rules,
)
check = wafv2_webacl_with_rules()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"AWS WAFv2 Web ACL {waf_name} does have rules or rule groups attached."
)
assert result[0].resource_id == waf_id
assert result[0].resource_arn == waf_arn
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_tags == [{"Key": "Name", "Value": waf_name}]
def test_wafv2_wb_acl_with_rule_group(self):
wafv2_client = mock.MagicMock
wafv2_client.enabled = True
wafv2_client.web_acls = {
waf_arn: WebAclv2(
arn=waf_arn,
name=waf_name,
id=waf_id,
albs=[],
user_pools=[],
region=AWS_REGION_EU_WEST_1,
logging_enabled=True,
tags=[{"Key": "Name", "Value": waf_name}],
rule_groups=[Rule(name="rule_group1", cloudwatch_metrics_enabled=True)],
)
}
with mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_service.WAFv2",
new=wafv2_client,
), mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_client.wafv2_client",
new=wafv2_client,
):
from prowler.providers.aws.services.wafv2.wafv2_webacl_with_rules.wafv2_webacl_with_rules import (
wafv2_webacl_with_rules,
)
check = wafv2_webacl_with_rules()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"AWS WAFv2 Web ACL {waf_name} does have rules or rule groups attached."
)
assert result[0].resource_id == waf_id
assert result[0].resource_arn == waf_arn
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_tags == [{"Key": "Name", "Value": waf_name}]
def test_wafv2_wb_acl_without_rule_or_rule_group(self):
wafv2_client = mock.MagicMock
wafv2_client.web_acls = {}
wafv2_client.enabled = True
wafv2_client.web_acls = {
waf_arn: WebAclv2(
arn=waf_arn,
name=waf_name,
id=waf_id,
albs=[],
user_pools=[],
region=AWS_REGION_EU_WEST_1,
logging_enabled=False,
tags=[{"Key": "Name", "Value": waf_name}],
)
}
with mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_service.WAFv2",
new=wafv2_client,
), mock.patch(
"prowler.providers.aws.services.wafv2.wafv2_client.wafv2_client",
new=wafv2_client,
):
from prowler.providers.aws.services.wafv2.wafv2_webacl_with_rules.wafv2_webacl_with_rules import (
wafv2_webacl_with_rules,
)
check = wafv2_webacl_with_rules()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"AWS WAFv2 Web ACL {waf_name} does not have any rules or rule groups attached."
)
assert result[0].resource_id == waf_id
assert result[0].resource_arn == waf_arn
assert result[0].region == AWS_REGION_EU_WEST_1
assert result[0].resource_tags == [{"Key": "Name", "Value": waf_name}]