#!/usr/bin/env python3 """Firewall Zone Segmentation Agent - audits zone-based firewall rules and inter-zone traffic policies.""" import json import argparse import logging import subprocess from collections import defaultdict from datetime import datetime logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") logger = logging.getLogger(__name__) def parse_firewall_config(config_file): with open(config_file) as f: return json.load(f) def get_iptables_zones(): cmd = ["iptables", "-L", "-n", "-v", "--line-numbers"] result = subprocess.run(cmd, capture_output=True, text=True, timeout=120) chains = defaultdict(list) current_chain = "" for line in result.stdout.split("\n"): if line.startswith("Chain"): current_chain = line.split()[1] elif line.strip() and not line.startswith("num"): chains[current_chain].append(line.strip()) return dict(chains) def audit_zone_rules(config): findings = [] rules = config.get("rules", []) for rule in rules: src_zone = rule.get("source_zone", "") dst_zone = rule.get("destination_zone", "") action = rule.get("action", "") service = rule.get("service", "any") if action == "allow" and service == "any": findings.append({"rule_id": rule.get("id", ""), "source_zone": src_zone, "dest_zone": dst_zone, "issue": "Allows all services between zones", "severity": "high"}) if action == "allow" and src_zone == "untrust" and dst_zone == "trust": findings.append({"rule_id": rule.get("id", ""), "issue": "Inbound from untrust to trust zone", "severity": "critical"}) if rule.get("log") is False and action == "allow": findings.append({"rule_id": rule.get("id", ""), "issue": "Allow rule without logging", "severity": "medium"}) return findings def check_default_zone_policies(config): issues = [] for zone in config.get("zones", []): if zone.get("default_action", "deny") != "deny": issues.append({"zone": zone.get("name"), "default_action": zone.get("default_action"), "issue": "Default zone policy is not deny", "severity": "critical"}) return issues def analyze_rule_shadowing(rules): shadowed = [] for i, rule in enumerate(rules): for j in range(i): prev = rules[j] if (prev.get("source_zone") == rule.get("source_zone") and prev.get("destination_zone") == rule.get("destination_zone") and prev.get("service") == "any" and prev.get("action") == "allow"): shadowed.append({"rule_id": rule.get("id"), "shadowed_by": prev.get("id"), "severity": "low"}) break return shadowed def generate_report(config, zone_findings, default_issues, shadowed): all_findings = zone_findings + default_issues + shadowed report = { "timestamp": datetime.utcnow().isoformat(), "total_zones": len(config.get("zones", [])), "total_rules": len(config.get("rules", [])), "zone_rule_findings": zone_findings, "default_policy_issues": default_issues, "shadowed_rules": shadowed, "total_findings": len(all_findings), "critical_findings": sum(1 for f in all_findings if f.get("severity") == "critical"), } return report def main(): parser = argparse.ArgumentParser(description="Firewall Zone Segmentation Audit Agent") parser.add_argument("--config", required=True, help="Firewall zone config JSON file") parser.add_argument("--output", default="zone_segmentation_report.json") args = parser.parse_args() config = parse_firewall_config(args.config) zone_findings = audit_zone_rules(config) default_issues = check_default_zone_policies(config) shadowed = analyze_rule_shadowing(config.get("rules", [])) report = generate_report(config, zone_findings, default_issues, shadowed) with open(args.output, "w") as f: json.dump(report, f, indent=2, default=str) logger.info("Zone audit: %d zones, %d rules, %d findings", report["total_zones"], report["total_rules"], report["total_findings"]) print(json.dumps(report, indent=2, default=str)) if __name__ == "__main__": main()