AnalysisType: policy
Filename: aws_waf_rule_ordering.py
PolicyID: "AWS.WAF.RuleOrdering"
DisplayName: "AWS WAF Rule Ordering"
Enabled: false
ResourceTypes:
- AWS.WAF.Regional.WebACL
- AWS.WAF.WebACL
Tags:
- AWS
- Configuration Required
- Security Control
Severity: High
Description: >
This policy validates that all WAF's have the correct rule ordering. Incorrect rule ordering could lead to less restrictive rules being matched and allowing traffic through before more restrictive rules that should have blocked the traffic.
Runbook: >
https://docs.runpanther.io/alert-runbooks/built-in-policies/aws-waf-has-correct-rule-ordering
Reference: https://docs.aws.amazon.com/waf/latest/developerguide/web-acl-rules.html
Tests:
- Name: Web ACL Configured Properly
ExpectedResult: true
Resource:
{
"DefaultAction": { "Type": "ALLOW" },
"MetricName": "examplewebacl",
"Name": "example-web-acl",
"Rules":
[
{
"Action": { "Type": "BLOCK" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 2,
"RuleId": "EXAMPLE_RULE_2_ID",
"Type": "REGULAR",
},
{
"Action": { "Type": "COUNT" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 1,
"RuleId": "EXAMPLE_RULE_1_ID",
"Type": "REGULAR",
},
],
"WebACLArn": "arn:aws:waf-regional:us-west-2:123456789012:webacl/11112222-3333-4444",
"WebACLId": "EXAMPLE_WEB_ACL_ID",
}
- Name: Web ACL Has Incorrect Rules
ExpectedResult: false
Resource:
{
"DefaultAction": { "Type": "ALLOW" },
"MetricName": "examplewebacl",
"Name": "example-web-acl",
"Rules":
[
{
"Action": { "Type": "BLOCK" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 2,
"RuleId": "111222-1111-2222-3333-111222333444",
"Type": "REGULAR",
},
{
"Action": { "Type": "COUNT" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 1,
"RuleId": "111222-1111-1111-2222-111222333444",
"Type": "REGULAR",
},
],
"WebACLArn": "arn:aws:waf-regional:us-west-2:123456789012:webacl/11112222-3333-4444",
"WebACLId": "EXAMPLE_WEB_ACL_ID",
}
- Name: Web ACL Has Rules In Incorrect Order
ExpectedResult: false
Resource:
{
"DefaultAction": { "Type": "ALLOW" },
"MetricName": "examplewebacl",
"Name": "example-web-acl",
"Rules":
[
{
"Action": { "Type": "BLOCK" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 2,
"RuleId": "EXAMPLE_RULE_1_ID",
"Type": "REGULAR",
},
{
"Action": { "Type": "COUNT" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 1,
"RuleId": "EXAMPLE_RULE_2_ID",
"Type": "REGULAR",
},
],
"WebACLArn": "arn:aws:waf-regional:us-west-2:123456789012:webacl/11112222-3333-4444",
"WebACLId": "EXAMPLE_WEB_ACL_ID",
}
- Name: Web ACL Has No Ordering Configured
ExpectedResult: true
Resource:
{
"DefaultAction": { "Type": "ALLOW" },
"MetricName": "examplewebacl",
"Name": "example-web-acl",
"Rules":
[
{
"Action": { "Type": "BLOCK" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 2,
"RuleId": "111222-1111-2222-3333-111222333444",
"Type": "REGULAR",
},
{
"Action": { "Type": "COUNT" },
"ExcludedRules": null,
"OverrideAction": null,
"Priority": 1,
"RuleId": "111222-1111-1111-2222-111222333444",
"Type": "REGULAR",
},
],
"WebACLArn": "arn:aws:waf-regional:us-west-2:123456789012:webacl/11112222-3333-4444",
"WebACLId": "11112222-3333-4444",
}
# ------ paired body: aws_waf_rule_ordering.py ------
# ORDERING is a dictionary that describes the required ordering of Web ACL rules for a
# given web acl ID. Map the Web ACL ID to an ordered tuple of Web ACL rule IDs
# Example usage:
# ORDERING{
# 'WebAclId-123': ('FirstRuleId', 'SecondRuleId', 'ThirdRuleId'),
# }
ORDERING = {
"EXAMPLE_WEB_ACL_ID": ("EXAMPLE_RULE_1_ID", "EXAMPLE_RULE_2_ID"),
}
def policy(resource):
# Check if Web ACL rule ordering is being enforced
if resource["WebACLId"] not in ORDERING:
return True
web_acl_rules = resource["Rules"]
# Check that the Web ACL has the correct number of rules
if len(ORDERING[resource["WebACLId"]]) != len(web_acl_rules):
return False
# Confirm that each rule is ordered correctly
for web_acl_rule in web_acl_rules:
# Rules are not necessarily listed in their priority order in the rules list.
# This determines their priority order, and offsets by one to be indexed starting at 0.
priority_order = web_acl_rule["Priority"] - 1
if web_acl_rule["RuleId"] != ORDERING[resource["WebACLId"]][priority_order]:
return False
# The rules all matched correctly, return True
return True