def test_with_mandated_profile(self): test_xml = """\ <response status="success"><result><config> <devices><entry><device-group><entry name="test_dg"> <pre-rulebase><security><rules> <entry name="first_rule"> <from><member>src_zone</member></from> <to><member>dest_zone</member></to> <source><member>ip-127.0.0.2</member></source> <destination><member>ip-127.0.0.3</member></destination> </entry> <entry name="superseding_rule"> <from><member>src_zone</member></from> <to><member>dest_zone</member></to> <source><member>ip-127.0.0.2</member></source> <destination> <member>ip-127.0.0.3</member> <member>ip-127.0.0.4</member> </destination> </entry> </rules></security></pre-rulebase> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) rules = pan_config.get_devicegroup_policy('SecurityPreRules', 'test_dg') profilepackage = self.create_profilepackage(rules) results = find_superseding_rules(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(results[0].data[0][2], 'first_rule') self.assertEqual(results[0].data[1][2], 'superseding_rule')
def test_badhostname(self, mocked_dns_lookup): test_xml = """\ <response status="success"><result><config> <shared> <pre-rulebase><security><rules> <entry name="test_rule"> <source><member>invalid_fqdn</member></source> <destination><member>ignored_fqdn</member></destination> </entry> </rules></security></pre-rulebase> <address> <entry name="ignored_ip_netmask"><ip-netmask>127.0.0.1</ip-netmask></entry> <entry name="ignored_fqdn"><fqdn>ignored.tld</fqdn></entry> <entry name="valid_fqdn"><fqdn>valid.tld</fqdn></entry> <entry name="invalid_fqdn"><fqdn>invalid.bad.tld</fqdn></entry> </address> <address-group> <entry name="Sample valid AG"><static><member>valid_fqdn</member></static></entry> <entry name="Sample invalid AG"><static><member>invalid_fqdn</member></static></entry> </address-group> </shared> </config></result></response> """ pan_config = PanConfig(test_xml) addresses = pan_config.get_devicegroup_object('Addresses', 'shared') address_groups = pan_config.get_devicegroup_object('AddressGroups', 'shared') rules = pan_config.get_devicegroup_policy('SecurityPreRules', 'shared') ignored_dns_prefixes = ["ignored"] mocked_dns_lookup.side_effect = ['127.0.0.1', None] profilepackage = self.create_profilepackage(addresses, address_groups, rules, ignored_dns_prefixes) _, _, validator_function = get_policy_validators()['BadHostname'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(results[0].data.get('name'), 'invalid_fqdn')
def test_missingzones(self, get_firewall_zone): test_xml = """\ <response status="success"><result><config> <devices><entry><device-group><entry name="test_dg"> <pre-rulebase><security><rules> <entry name="missing_zone_rule"> <from> <member>src_zone</member> </from> <to> <member>dest_zone</member> </to> <source> <member>ip-127.0.0.2</member> </source> <destination> <member>ip-127.0.0.3</member> <member>ip-127.0.0.4</member> </destination> </entry> </rules></security></pre-rulebase> <address> <entry name="ip-127.0.0.2"><ip-netmask>127.0.0.2</ip-netmask></entry> <entry name="ip-127.0.0.3"><ip-netmask>127.0.0.3</ip-netmask></entry> <entry name="ip-127.0.0.4"><ip-netmask>127.0.0.4</ip-netmask></entry> </address> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) rules = pan_config.get_devicegroup_policy('SecurityPreRules', 'test_dg') addresses = pan_config.get_devicegroup_object('Addresses', 'test_dg') profilepackage = self.create_profilepackage(rules, addresses) get_firewall_zone.side_effect = [ 'src_zone', 'dest_zone', "missing_zone" ] _, _, validator_function = get_policy_validators()['MissingZones'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(results[0].data.get('name'), 'missing_zone_rule')
def load_config_package(configuration_settings, api_key, device_group, limit, no_api, xml_file=None): if xml_file: # The list of firewalls are not available from the API, so # these variables will remain empty logger.debug(f"Loading configuration from XML file: {xml_file}") with open(xml_file, encoding='utf-8') as fh: xml_config = fh.read() pan_config = PanConfig(xml_config, True) device_groups_and_firewalls = collections.defaultdict(list) active_firewalls_per_devicegroup = collections.defaultdict(list) else: # Load the XML configuration and list of firewalls via API requests panorama = configuration_settings.get('panorama') xml_config = pan_api.export_configuration2(panorama, api_key) pan_config = PanConfig(xml_config) device_groups_and_firewalls = pan_api.get_device_groups_and_firewalls(panorama, api_key) active_firewalls = pan_api.get_active_firewalls(panorama, api_key) # Build the mapping of active FWs in each device group active_firewalls_per_devicegroup = collections.defaultdict(list) for dg, firewalls in device_groups_and_firewalls.items(): active_firewalls_per_devicegroup[dg] = [fw for fw in firewalls if fw in active_firewalls] device_group_hierarchy_children, device_group_hierarchy_parent = pan_config.get_device_groups_hierarchy() # Build a mapping of device groups to their 'child' device groups all_device_groups = pan_config.get_device_groups() + ['shared'] devicegroups_to_child_devicegroups = squash_all_devicegroups(all_device_groups, device_group_hierarchy_children) all_active_firewalls_per_devicegroup = collections.defaultdict(list) for dg, child_dgs in devicegroups_to_child_devicegroups.items(): all_active_firewalls_per_devicegroup[dg] = [] for child_dg in child_dgs: all_active_firewalls_per_devicegroup[dg] += active_firewalls_per_devicegroup[child_dg] # Create and fill in the devicegroup_objects, which represents all entries, per devicegroup devicegroup_objects = {} if device_group: device_groups = [device_group] else: device_groups = all_device_groups for device_group in all_device_groups: devicegroup_objects[device_group] = {} devicegroup_objects[device_group]['all_child_device_groups'] = devicegroups_to_child_devicegroups[device_group] devicegroup_objects[device_group]['all_active_child_firewalls'] = all_active_firewalls_per_devicegroup[ device_group] for policy_type in pan_config.SUPPORTED_POLICY_TYPES: devicegroup_objects[device_group][policy_type] = pan_config.get_devicegroup_policy(policy_type, device_group)[:limit] for object_type in pan_config.SUPPORTED_OBJECT_TYPES: devicegroup_objects[device_group][object_type] = pan_config.get_devicegroup_object(object_type, device_group) rule_limit_enabled = limit is not None # Build a listing of policy objects that are exclusive to each device group, which won't include policies inherited from the parent device groups devicegroup_exclusive_objects = {} for device_group in all_device_groups: devicegroup_exclusive_objects[device_group] = {} for policy_type in pan_config.SUPPORTED_POLICY_TYPES: if device_group not in device_group_hierarchy_parent: # No parent means no inherited policies devicegroup_exclusive_objects[device_group][policy_type] = devicegroup_objects[device_group][ policy_type] else: parent_dg = device_group_hierarchy_parent[device_group] parent_policy_uuids = set([entry.get('@uuid') for entry in devicegroup_objects[parent_dg][policy_type]]) exclusive_objects = [entry for entry in devicegroup_objects[device_group][policy_type] if entry.get('@uuid') not in parent_policy_uuids] devicegroup_exclusive_objects[device_group][policy_type] = exclusive_objects profilepackage = ProfilePackage( api_key=api_key, pan_config=pan_config, settings=configuration_settings, device_group_hierarchy_children=device_group_hierarchy_children, device_group_hierarchy_parent=device_group_hierarchy_parent, device_groups_and_firewalls=device_groups_and_firewalls, device_groups=device_groups, devicegroup_objects=devicegroup_objects, devicegroup_exclusive_objects=devicegroup_exclusive_objects, rule_limit_enabled=rule_limit_enabled, no_api=no_api ) return profilepackage
def test_unusedaddresses(self): test_xml = """\ <response status="success"><result><config> <shared> <address> <entry name="address_unused"/> <entry name="address_used_addressgroup"/> <entry name="address_used_security"/> <entry name="address_used_in_nat1"/> <entry name="address_used_in_dg"/> </address> <address-group> <entry name="addressgroup1"><static><member>address_used_addressgroup</member></static></entry> </address-group> <pre-rulebase> <security><rules> <entry name="shared_rule1"><source><member>address_used_security</member></source></entry> <entry name="shared_rule2"><destination><member>addressgroup1</member></destination></entry> </rules></security> <nat><rules> <entry name="nat1"><source-translation><translated-address>address_used_in_nat1</translated-address></source-translation></entry> </rules></nat> </pre-rulebase> </shared> <devices><entry><device-group><entry name="test_dg"> <address> <entry name="service_unused_dg"/> </address> <pre-rulebase> <security><rules> <entry name="shared_rule"><source><member>address_used_in_dg</member></source></entry> </rules></security> </pre-rulebase> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) shared_addresses = pan_config.get_devicegroup_object( 'Addresses', 'shared') shared_addressgroups = pan_config.get_devicegroup_object( 'AddressGroups', 'shared') shared_securityprerules = pan_config.get_devicegroup_policy( 'SecurityPreRules', 'shared') shared_natprerules = pan_config.get_devicegroup_policy( 'NATPreRules', 'shared') dg_addresses = pan_config.get_devicegroup_object( 'Addresses', 'test_dg') dg_securityprerules = pan_config.get_devicegroup_policy( 'SecurityPreRules', 'test_dg') profilepackage = self.create_profilepackage( shared_addresses, shared_addressgroups, shared_securityprerules, shared_natprerules, dg_addresses, dg_securityprerules) _, _, validator_function = get_policy_validators()['UnusedAddresses'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 1) self.assertEqual(results[0].data[0].get('name'), 'address_unused') self.assertEqual(results[0].device_group, 'shared')