Add WafPolicies

This commit is contained in:
Dan Milne
2025-11-10 14:10:37 +11:00
parent af7413c899
commit 772fae7e8b
22 changed files with 1784 additions and 147 deletions

View File

@@ -35,6 +35,23 @@ class ProcessWafEventJob < ApplicationJob
end
end
# Ensure network range exists for this IP and process policies
if event.ip_address.present?
begin
existing_range = NetworkRange.contains_ip(event.ip_address.to_s).first
network_range = existing_range || NetworkRangeGenerator.find_or_create_for_ip(event.ip_address)
if network_range
Rails.logger.debug "Network range #{network_range.cidr} for event IP #{event.ip_address}"
# Process WAF policies for this network range
ProcessWafPoliciesJob.perform_later(network_range_id: network_range.id, event_id: event.id)
end
rescue => e
Rails.logger.warn "Failed to create network range for event #{event.id}: #{e.message}"
end
end
# Trigger analytics processing
ProcessWafAnalyticsJob.perform_later(event_id: event.id)

View File

@@ -0,0 +1,101 @@
# frozen_string_literal: true
# ProcessWafPoliciesJob - Process firewall policies for a network range
#
# This job checks network ranges against active WAF policies and generates
# specific rules when matches are found.
class ProcessWafPoliciesJob < ApplicationJob
queue_as :waf_policies
retry_on StandardError, wait: :exponentially_longer, attempts: 3
def perform(network_range_id:, event_id: nil)
# Find the network range
network_range = NetworkRange.find_by(id: network_range_id)
return if network_range.nil?
Rails.logger.debug "Processing WAF policies for network range #{network_range.cidr}"
# Use WafPolicyMatcher to find and generate rules
matcher = WafPolicyMatcher.new(network_range: network_range)
result = matcher.match_and_generate_rules
# Log results
if result[:matching_policies].any?
Rails.logger.info "Network range #{network_range.cidr} matched #{result[:matching_policies].length} policies"
result[:matching_policies].each do |policy|
Rails.logger.info " - Matched policy: #{policy.name} (#{policy.policy_type}: #{policy.action})"
end
end
if result[:generated_rules].any?
Rails.logger.info "Generated #{result[:generated_rules].length} rules for network range #{network_range.cidr}"
result[:generated_rules].each do |rule|
Rails.logger.info " - Rule: #{rule.rule_type} #{rule.action} for #{rule.network_range&.cidr} (ID: #{rule.id})"
# Log if this is a redirect or challenge rule
if rule.redirect_action?
Rails.logger.info " Redirect to: #{rule.redirect_url} (#{rule.redirect_status})"
elsif rule.challenge_action?
Rails.logger.info " Challenge type: #{rule.challenge_type}"
end
end
# Trigger agent sync for new rules if there are any
if result[:generated_rules].any?
RulesSyncJob.perform_later
end
else
Rails.logger.debug "No matching policies found for network range #{network_range.cidr}"
end
# Update event record if provided
if event_id.present?
event = Event.find_by(id: event_id)
if event.present?
# Add policy match information to event metadata
event.update!(payload: event.payload.merge({
policy_matches: {
matching_policies_count: result[:matching_policies].length,
generated_rules_count: result[:generated_rules].length,
processed_at: Time.current.iso8601
}
}))
end
end
end
# Class method for batch processing multiple network ranges
def self.process_network_ranges(network_range_ids)
network_range_ids.each do |network_range_id|
perform_later(network_range_id: network_range_id)
end
end
# Class method to reprocess all network ranges for a specific policy
def self.reprocess_for_policy(waf_policy)
waf_policy_id = waf_policy.is_a?(WafPolicy) ? waf_policy.id : waf_policy
# Find all network ranges that could match this policy type
network_ranges = case waf_policy.policy_type
when 'country'
NetworkRange.where.not(country: nil)
when 'asn'
NetworkRange.where.not(asn: nil)
when 'company'
NetworkRange.where.not(company: nil)
when 'network_type'
NetworkRange.where("is_datacenter = ? OR is_proxy = ? OR is_vpn = ?", true, true, true)
else
NetworkRange.none
end
Rails.logger.info "Reprocessing #{network_ranges.count} network ranges for policy #{waf_policy_id}"
network_ranges.find_each do |network_range|
perform_later(network_range_id: network_range.id)
end
end
end