Skip to content

Commit

Permalink
feat: added full service structure
Browse files Browse the repository at this point in the history
Resolved comments and added total structure for WAFRegional
  • Loading branch information
HugoPBrito committed Oct 16, 2024
1 parent c1b51c6 commit 077efa8
Show file tree
Hide file tree
Showing 5 changed files with 239 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"Provider": "aws",
"CheckID": "waf_rule_has_conditions",
"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"
Expand All @@ -15,7 +15,7 @@
"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 <rule-id> --change-token <change-token> --updates <updates>",
"CLI": "aws waf-regional update-rule --rule-id <your-rule-id> --change-token <your-change-token> --updates '[{\"Action\":\"INSERT\",\"Predicate\":{\"Negated\":false,\"Type\":\"IPMatch\",\"DataId\":\"<your-ipset-id>\"}}]' --region <your-region>",
"NativeIaC": "",
"Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/waf-controls.html#waf-2",
"Terraform": ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ def execute(self):
report.resource_arn = rule.arn
report.resource_tags = rule.tags
report.status = "FAIL"
report.status_extended = f"AWS WAFRegional Classic Regional Rule {rule.id} does not have any conditions."
report.status_extended = (
f"AWS WAF Regional Rule {rule.id} does not have any conditions."
)

if rule.predicates:
report.status = "PASS"
report.status_extended = f"AWS WAFRegional Classic Regional Rule {rule.id} has at least one condition."
report.status_extended = (
f"AWS WAF Regional Rule {rule.id} has at least one condition."
)

findings.append(report)

Expand Down
153 changes: 103 additions & 50 deletions prowler/providers/aws/services/waf/waf_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,84 @@ class WAFRegional(AWSService):
def __init__(self, provider):
# Call AWSService's __init__
super().__init__("waf-regional", provider)
self.web_acls = {}
self.rules = {}
self.__threading_call__(self._list_web_acls)
self.__threading_call__(self._list_resources_for_web_acl)
self.__threading_call__(self._get_web_acl, self.web_acls.values())
self.rule_groups = {}
self.web_acls = {}
self.__threading_call__(self._list_rules)
self.__threading_call__(self._get_rule, self.rules.values())
self.__threading_call__(self._list_rule_groups)
self.__threading_call__(
self._list_activated_rules_in_rule_group, self.rule_groups.values()
)
self.__threading_call__(self._list_web_acls)
self.__threading_call__(self._get_web_acl, self.web_acls.values())
self.__threading_call__(self._list_resources_for_web_acl)

def _list_rules(self, regional_client):
logger.info("WAFRegional - Listing Regional Rules...")
try:
for rule in regional_client.list_rules().get("Rules", []):
arn = f"arn:aws:waf-regional:{regional_client.region}:{self.audited_account}:rule/{rule['RuleId']}"
self.rules[arn] = Rule(
arn=arn,
id=rule.get("RuleId", ""),
region=regional_client.region,
name=rule.get("Name", ""),
)
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _get_rule(self, rule):
logger.info(f"WAFRegional - Getting Rule {rule.name}...")
try:
get_rule = self.regional_clients[rule.region].get_rule(RuleId=rule.id)
for predicate in get_rule.get("Rule", {}).get("Predicates", []):
rule.predicates.append(
Predicate(
negated=predicate.get("Negated", False),
type=predicate.get("Type", "IPMatch"),
data_id=predicate.get("DataId", ""),
)
)
except KeyError:
logger.error(f"Rule {rule.name} not found in {rule.region}.")

def _list_rule_groups(self, regional_client):
logger.info("WAFRegional - Listing Regional Rule Groups...")
try:
for rule_group in regional_client.list_rule_groups().get("RuleGroups", []):
arn = f"arn:aws:waf-regional:{regional_client.region}:{self.audited_account}:rulegroup/{rule_group['RuleGroupId']}"
self.rule_groups[arn] = RuleGroup(
arn=arn,
region=regional_client.region,
id=rule_group.get("RuleGroupId", ""),
name=rule_group.get("Name", ""),
)

except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _list_activated_rules_in_rule_group(self, rule_group):
logger.info(
f"WAFRegional - Listing activated rules in Rule Group {rule_group.name}..."
)
try:
for rule in (
self.regional_clients[rule_group.region]
.list_activated_rules_in_rule_group(RuleGroupId=rule_group.id)
.get("ActivatedRules", [])
):
rule_arn = f"arn:aws:waf-regional:{rule_group.region}:{self.audited_account}:rule/{rule.get('RuleId', '')}"
rule_group.rules.append(self.rules[rule_arn])

except Exception as error:
logger.error(
f"{rule_group.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _list_web_acls(self, regional_client):
logger.info("WAFRegional - Listing Regional Web ACLs...")
Expand All @@ -80,20 +151,6 @@ def _list_web_acls(self, regional_client):
albs=[],
region=regional_client.region,
)
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _list_resources_for_web_acl(self, regional_client):
logger.info("WAFRegional - Describing resources...")
try:
for acl in self.web_acls.values():
if acl.region == regional_client.region:
for resource in regional_client.list_resources_for_web_acl(
WebACLId=acl.id, ResourceType="APPLICATION_LOAD_BALANCER"
)["ResourceArns"]:
acl.albs.append(resource)

except Exception as error:
logger.error(
Expand All @@ -105,57 +162,42 @@ def _get_web_acl(self, acl):
try:
get_web_acl = self.regional_clients[acl.region].get_web_acl(WebACLId=acl.id)
for rule in get_web_acl.get("WebACL", {}).get("Rules", []):
rule_id = rule.get("RuleId", "")
if rule.get("Type", "") == "GROUP":
acl.rule_groups.append(ACLRule(id=rule_id))
rule_group_arn = f"arn:aws:waf-regional:{acl.region}:{self.audited_account}:rulegroup/{rule.get("RuleId", "")}"
acl.rule_groups.append(self.rule_groups[rule_group_arn])
else:
acl.rules.append(ACLRule(id=rule_id))
rule_arn = f"arn:aws:waf-regional:{acl.region}:{self.audited_account}:rule/{rule.get("RuleId", "")}"
acl.rules.append(self.rules[rule_arn])

except Exception as error:
logger.error(
f"{acl.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _list_rules(self, regional_client):
logger.info("WAFRegional - Listing Regional Rules...")
def _list_resources_for_web_acl(self, regional_client):
logger.info("WAFRegional - Describing resources...")
try:
for rule in regional_client.list_rules().get("Rules", []):
arn = f"arn:aws:waf-regional:{regional_client.region}:{self.audited_account}:rule/{rule['RuleId']}"
self.rules[arn] = Rule(
arn=arn,
id=rule.get("RuleId", ""),
region=regional_client.region,
name=rule.get("Name", ""),
)
for acl in self.web_acls.values():
if acl.region == regional_client.region:
for resource in regional_client.list_resources_for_web_acl(
WebACLId=acl.id, ResourceType="APPLICATION_LOAD_BALANCER"
)["ResourceArns"]:
acl.albs.append(resource)

except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _get_rule(self, rule):
logger.info(f"WAFRegional - Getting Rule {rule.name}...")
try:
get_rule = self.regional_clients[rule.region].get_rule(RuleId=rule.id)
for predicate in get_rule.get("Rule", {}).get("Predicates", []):
rule.predicates.append(
Predicate(
negated=predicate.get("Negated", False),
data_id=predicate.get("DataId", ""),
)
)
except KeyError:
logger.error(f"Rule {rule.name} not found in {rule.region}.")


class Predicate(BaseModel):
"""Conditions for WAF and WAFRegional Rules"""

negated: bool
type: str
data_id: str


class ACLRule(BaseModel):
id: str


class Rule(BaseModel):
"""Rule Model for WAF and WAFRegional"""

Expand All @@ -167,6 +209,17 @@ class Rule(BaseModel):
tags: Optional[list] = []


class RuleGroup(BaseModel):
"""RuleGroup Model for WAF and WAFRegional"""

arn: str
id: str
region: str
name: str
rules: list[Rule] = []
tags: Optional[list] = []


class WebAcl(BaseModel):
"""Web ACL Model for WAF and WAFRegional"""

Expand All @@ -176,5 +229,5 @@ class WebAcl(BaseModel):
albs: list[str]
region: str
rules: list[Rule] = []
rule_groups: list[Rule] = []
rule_groups: list[RuleGroup] = []
tags: Optional[list] = []
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def test_waf_rules_with_condition(self):
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"AWS WAFRegional Classic Regional Rule {RULE_ID} has at least one condition."
== f"AWS WAF Regional Rule {RULE_ID} has at least one condition."
)
assert result[0].resource_id == RULE_ID
assert (
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_waf_rules_without_condition(self):
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"AWS WAFRegional Classic Regional Rule {RULE_ID} does not have any conditions."
== f"AWS WAF Regional Rule {RULE_ID} does not have any conditions."
)
assert result[0].resource_id == RULE_ID
assert (
Expand Down
Loading

0 comments on commit 077efa8

Please sign in to comment.