Difficulty in Displaying Unused Firewall policies in PA networks using API key

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Difficulty in Displaying Unused Firewall policies in PA networks using API key

L0 Member
Below is the script i have been working on that helps to display all the firewall policies of a device group. Now I'm having trouble in making the script display the Rule usage, as used, partially used, or unused as shown next to a policy. The script keeps on returning N/A every time i run it. Can someone help?


import
requests
import xml.etree.ElementTree as ET
 
PANORAMA_HOST = ''
API_KEY = ''
 
requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning)
 
def get_device_groups():
    url = f"{PANORAMA_HOST}/api/?type=config&action=get&key={API_KEY}&xpath=/config/devices/entry[@name='localhost.localdomain']/device-group"
 
    try:
        response = requests.get(url, verify=False)
        if response.status_code != 200:
            print(f"Error: Received status code {response.status_code}")
            exit()
 
        root = ET.fromstring(response.text)
    except requests.RequestException as e:
        print(f"Network error occurred: {e}")
        exit()
    except ET.ParseError:
        print("Error: Unable to parse XML. Check if the API key or URL is correct.")
        exit()
 
    dg_list = []
    for entry in root.findall(".//device-group/entry"😞
        name = entry.attrib.get('name')
        parent_elem = entry.find("parent")
        parent_name = parent_elem.text if parent_elem is not None else None
        dg_list.append({'name': name, 'parent': parent_name})
    return dg_list
 
def build_hierarchy(device_groups😞
    tree = {}
    for dg in device_groups:
        parent = dg['parent']
        name = dg['name']
        if parent not in tree:
            tree[parent] = []
        tree[parent].append(name)
    return tree
 
def print_tree(tree, parent=None, indent='', numbered_list=None😞
    if numbered_list is None:
        numbered_list = []
 
    children = tree.get(parent, [])
    for child in sorted(children😞
        numbered_list.append(child)
        print(f"{len(numbered_list)}. {indent}{child}")
        print_tree(tree, parent=child, indent=indent + '  ', numbered_list=numbered_list)
 
    return numbered_list
 
def get_text_list(rule_elem, tag😞
    return [e.text for e in rule_elem.findall(f"./{tag}/member")]
 
def get_rule_usage_data(device_group😞
    cmd = f"<show><running><security-policy><usage><type>pre</type><vsys><entry name='{device_group}'/></vsys></usage></security-policy></running></show>"
    url = f"{PANORAMA_HOST}/api/?type=op&cmd={cmd}&key={API_KEY}"
 
    try:
        response = requests.get(url, verify=False)
        if response.status_code != 200:
            print(f"Error fetching rule usage: {response.status_code}")
            return {}
 
        root = ET.fromstring(response.text)
        usage_data = {}
 
        for entry in root.findall(".//entry"😞
            rule_name = entry.findtext("rule-name")
            usage = entry.findtext("rule-usage")
            apps_seen = entry.findtext("apps-seen")
            usage_data[rule_name] = {
                'rule_usage': usage,
                'apps_seen': apps_seen
            }
 
        return usage_data
 
    except Exception as e:
        print(f"Error while fetching rule usage: {e}")
        return {}
 
def check_rule_traffic_logs(rule_name, device_group, time_range='last-30-days'😞
    query = f"(rule eq '{rule_name}')"
    url = (f"{PANORAMA_HOST}/api/?type=log&log-type=traffic&key={API_KEY}"
           f"&query={query}&device-group={device_group}&time-range={time_range}")
    try:
        response = requests.get(url, verify=False)
        if response.status_code != 200:
            print(f"Error checking logs for rule '{rule_name}': {response.status_code}")
            return None
 
        root = ET.fromstring(response.text)
        entries = root.findall(".//entry")
        return len(entries) > 0
 
    except Exception as e:
        print(f"Log check error for rule '{rule_name}': {e}")
        return None
 
def get_security_policies(device_group😞
    print("Fetching rule usage data...")
    rule_usage_data = get_rule_usage_data(device_group)
 
    xpath = f"/config/devices/entry[@name='localhost.localdomain']/device-group/entry[@name='{device_group}']/pre-rulebase/security/rules"
    url = f"{PANORAMA_HOST}/api/?type=config&action=get&key={API_KEY}&xpath={xpath}"
 
    try:
        response = requests.get(url, verify=False)
        if response.status_code != 200:
            print(f"Error fetching policies: {response.status_code}")
            return
 
        root = ET.fromstring(response.text)
        rules = root.findall(".//rules/entry")
 
        if not rules:
            print("\nNo security policies found in this device group.")
            return
 
        print(f"\nSecurity Policies in '{device_group}':\n")
        for rule in rules:
            rule_name = rule.attrib.get('name')
            usage_info = rule_usage_data.get(rule_name, {})
            rule_usage = usage_info.get('rule_usage', 'N/A')
            apps_seen = usage_info.get('apps_seen', 'N/A')
 
            print(f"- Rule Name    : {rule_name}")
            print(f"  From         : {get_text_list(rule, 'from')}")
            print(f"  To           : {get_text_list(rule, 'to')}")
            print(f"  Source       : {get_text_list(rule, 'source')}")
            print(f"  Destination  : {get_text_list(rule, 'destination')}")
            print(f"  Application  : {get_text_list(rule, 'application')}")
            print(f"  Service      : {get_text_list(rule, 'service')}")
            print(f"  Source User  : {get_text_list(rule, 'source-user')}")
            print(f"  Category     : {get_text_list(rule, 'category')}")
            print(f"  HIP Profiles : {get_text_list(rule, 'hip-profiles')}")
            print(f"  Tags         : {get_text_list(rule, 'tag')}")
            print(f"  Description  : {rule.findtext('description')}")
            print(f"  Action       : {rule.findtext('action')}")
            print(f"  Rule Type    : {rule.findtext('rule-type')}")
            print(f"  Disabled     : {rule.findtext('disabled')}")
            print(f"  Target       : {rule.findtext('target')}")
            print(f"  Rule Usage   : {rule_usage}")
            print(f"  Apps Seen    : {apps_seen}")
 
            # === New: Traffic log check ===
            is_used_30d = check_rule_traffic_logs(rule_name, device_group, time_range='last-30-days')
            is_used_90d = check_rule_traffic_logs(rule_name, device_group, time_range='last-90-days')
            print(f"  Used in Last 30 Days : {'Yes' if is_used_30d else 'No'}")
            print(f"  Used in Last 90 Days : {'Yes' if is_used_90d else 'No'}")
 
            print()
 
    except Exception as e:
        print(f"Error while fetching/parsing policies: {e}")
 
# === Main Execution ===
if __name__ == "__main__":
    print("Fetching device groups...")
    device_groups = get_device_groups()
 
    if not device_groups:
        print("No device groups found.")
        exit()
 
    print("\nAvailable Device Groups (Hierarchy):")
    tree = build_hierarchy(device_groups)
    numbered_dgs = print_tree(tree, parent=None)
 
    try:
        selected_index = int(input("\nEnter the number corresponding to the device group: "))
        selected_dg = numbered_dgs[selected_index - 1]
    except (ValueError, IndexError😞
        print("Invalid selection. Please run the script again and enter a valid number.")
        exit()
 
    print(f"\nYou selected device group: {selected_dg}")
    get_security_policies(selected_dg)
0 REPLIES 0
  • 316 Views
  • 0 replies
  • 0 Likes
Like what you see?

Show your appreciation!

Click Like if a post is helpful to you or if you just want to show your support.

Click Accept as Solution to acknowledge that the answer to your question has been provided.

The button appears next to the replies on topics you’ve started. The member who gave the solution and all future visitors to this topic will appreciate it!

These simple actions take just seconds of your time, but go a long way in showing appreciation for community members and the LIVEcommunity as a whole!

The LIVEcommunity thanks you for your participation!