aws-solutions / aws-waf-security-automations

This solution automatically deploys a single web access control list (web ACL) with a set of AWS WAF rules designed to filter common web-based attacks.
https://aws.amazon.com/solutions/aws-waf-security-automations
Apache License 2.0
845 stars 361 forks source link

Web ACL rule action change support #107

Closed kogitant closed 1 year ago

kogitant commented 4 years ago

The configure_web_acl method in custom-resource.py does not handle changing the action of an associated rule. One might want to use COUNT action first for some rule to learn what effect it would have and then later switch it to BLOCK.

To support this, a method like this is needed:

def process_rule_action_change(new_action, protection_tag_name, rule_name, resource_properties, old_resource_properties, current_rules):
    logging.getLogger().info("[process_rule_action_change] Start")
    updates = []
    rule_id = old_resource_properties[rule_name] if rule_name in old_resource_properties else None
    rule_data = current_rules[rule_id] if rule_id in current_rules else None
    old_action = rule_data['Action']['Type'] if rule_data is not None else None

    is_activated = resource_properties[protection_tag_name] == "yes"
    was_activated = old_resource_properties[protection_tag_name] == "yes"

    if was_activated and is_activated and rule_id in current_rules and (old_action != new_action):
        delete = {
            'Action': 'DELETE',
            'ActivatedRule': {
                'Priority': rule_data['Priority'],
                'RuleId': rule_id,
                'Action': rule_data['Action'],
                'Type': rule_data['Type']
            }
        }
        insert = {
            'Action': 'INSERT',
            'ActivatedRule': {
                'Priority': rule_data['Priority'],
                'RuleId': rule_id,
                'Action': {'Type': new_action},
                'Type': rule_data['Type']
            }
        }

        # We need to first delete the rule with the old action
        updates.append(delete)
        # And immediately insert it with the new action
        updates.append(insert)

        logging.getLogger().info(
            "rule action changed".format(json.dumps(updates)))

    logging.getLogger().info("[process_rule_action_change] End")
    return updates

This kind of new code block needs to be added to configure_web_acl right before the existing update_web_acl call:

    if old_resource_properties:
        updates.extend(process_rule_action_change(resource_properties['ActionWAFSqlInjectionRule'], 'ProtectionActivatedSqlInjection', 'WAFSqlInjectionRule', resource_properties, old_resource_properties, current_rules))
        updates.extend(process_rule_action_change(resource_properties['ActionWAFXssRule'], 'ProtectionActivatedCrossSiteScripting', 'WAFXssRule', resource_properties, old_resource_properties, current_rules))
        updates.extend(process_rule_action_change(resource_properties['ActionWAFHttpFloodRateBasedRule'], 'ProtectionActivatedHttpFloodRateBased', 'WAFHttpFloodRateBasedRule', resource_properties, old_resource_properties, current_rules))
        updates.extend(process_rule_action_change(resource_properties['ActionWAFHttpFloodRegularRule'], 'ProtectionActivatedHttpFloodRegular', 'WAFHttpFloodRegularRule', resource_properties, old_resource_properties, current_rules))
        updates.extend(process_rule_action_change(resource_properties['ActionWAFScannersProbesRule'], 'ProtectionActivatedScannersProbes', 'WAFScannersProbesRule', resource_properties, old_resource_properties, current_rules))
        updates.extend(process_rule_action_change(resource_properties['ActionWAFIPReputationListsRule'], 'ProtectionActivatedReputationLists', 'WAFIPReputationListsRule', resource_properties, old_resource_properties, current_rules))
        updates.extend(process_rule_action_change(resource_properties['ActionWAFBadBotRule'], 'ProtectionActivatedBadBot', 'WAFBadBotRule', resource_properties, old_resource_properties, current_rules))

    updates = [u for u in updates if u is not None]
    logging.getLogger().info("updates: {}".format(json.dumps(updates)))

    #------------------------------------------------------------------------------------------------------------------
    # Update WebACL
    #------------------------------------------------------------------------------------------------------------------
    update_web_acl(resource_properties['WAFWebACL'], updates)
aijunpeng commented 1 year ago

Thanks for sharing the code. The out-of-box solution currently doesn't support change of action. Closing this old ticket. Feel free to open a new one if needed.