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="same_zone_rule"> <service> <member>tcp-123</member> <member>myservicegroup</member> </service> </entry> </rules></security></pre-rulebase> <service><entry name="tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry></service> <service-group><entry name="myservicegroup"><members><member>tcp-123</member></members></entry></service-group> </entry></device-group></entry></devices> <readonly><devices><entry name="localhost.localdomain"><device-group> <entry name="test_dg"><id>11</id></entry> </device-group></entry></devices></readonly> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(pan_config) _, _, validator_function = get_policy_validators()['RedundantRuleServices'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) ruletype, rule_entry, members_to_remove = results[0].data self.assertEqual(ruletype, 'SecurityPreRules') self.assertEqual(rule_entry.get('name'), 'same_zone_rule') self.assertEqual(members_to_remove, [('tcp-123', 'myservicegroup')])
def consolidate_addressgroups(profilepackage): object_friendly_type = "Address Group" _, _, validator_function = get_policy_validators( )['FindConsolidatableAddressGroups'] return consolidate_service_like_objects(profilepackage, object_friendly_type, validator_function)
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_unusedaddresses(self): test_xml = """\ <response status="success"><result><config> <shared> <profile-group> <entry name="used_group1"></entry> <entry name="used_group2"></entry> <entry name="unused_group3"></entry> </profile-group> <pre-rulebase> <security><rules> <entry name="shared_rule1"><profile-setting><group><member>used_group1</member></group></profile-setting></entry> </rules></security> </pre-rulebase> </shared> <devices><entry><device-group><entry name="test_dg"> <pre-rulebase> <security><rules> <entry name="dg_rule2"><profile-setting><group><member>used_group2</member></group></profile-setting></entry> </rules></security> </pre-rulebase> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(pan_config) _, _, validator_function = get_policy_validators( )['UnusedSecurityProfileGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 1) self.assertEqual(results[0].data[0].get('name'), 'unused_group3') self.assertEqual(results[0].device_group, 'shared')
def delete_disabled_policies(profilepackage): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator_function = get_policy_validators()['DisabledPolicies'] policies_to_delete = validator_function(profilepackage) if policies_to_delete: logger.info( f"Deleting {len(policies_to_delete)} disabled policies now") for policy_entry in policies_to_delete: device_group = policy_entry.device_group policy_name = policy_entry.data[0].get('name') policy_type = policy_entry.entry_type logger.info( f"Deleting Device Group {device_group}'s {policy_type} {policy_name}" ) try: pan_api.delete_policy(panorama, version, api_key, policy_type, policy_name, device_group) except requests.HTTPError as err: logger.info( f"Error deleting {device_group}'s {policy_type} {policy_name}: {err.response.text}" ) pan_api.validate_commit(panorama, api_key) return policies_to_delete
def test_shadowing_addresses_and_groups(self): test_xml = """\ <response status="success"><result><config> <shared> <address> <entry name="dup_shared_address_shared_ag_dg_address"/> </address> <address-group> <entry name="dup_shared_address_shared_ag_dg_address"/> </address-group> </shared> <devices><entry><device-group><entry name="test_dg"> <address> <entry name="dup_shared_address_shared_ag_dg_address"/> </address> <address-group> </address-group> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) shared_addresses = pan_config.get_devicegroup_object( 'Addresses', 'shared') dg_addesses = pan_config.get_devicegroup_object('Addresses', 'test_dg') shared_addressgroups = pan_config.get_devicegroup_object( 'AddressGroups', 'shared') dg_addessgroups = pan_config.get_devicegroup_object( 'AddressGroups', 'test_dg') profilepackage = self.create_profilepackage(shared_addresses, dg_addesses, shared_addressgroups, dg_addessgroups) _, _, validator_function = get_policy_validators( )['ShadowingAddressesAndGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 2) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1], 'AddressGroups') self.assertEqual(results[0].data[0][2].get('name'), 'dup_shared_address_shared_ag_dg_address') self.assertEqual(results[0].data[1][0], 'shared') self.assertEqual(results[0].data[1][1], 'Addresses') self.assertEqual(results[0].data[1][2].get('name'), 'dup_shared_address_shared_ag_dg_address') self.assertEqual(len(results[1].data), 3) self.assertEqual(results[1].data[0][0], 'test_dg') self.assertEqual(results[1].data[0][1], 'Addresses') self.assertEqual(results[1].data[0][2].get('name'), 'dup_shared_address_shared_ag_dg_address') self.assertEqual(results[1].data[1][0], 'shared') self.assertEqual(results[1].data[1][1], 'Addresses') self.assertEqual(results[1].data[1][2].get('name'), 'dup_shared_address_shared_ag_dg_address') self.assertEqual(results[1].data[2][0], 'shared') self.assertEqual(results[1].data[2][1], 'AddressGroups') self.assertEqual(results[1].data[2][2].get('name'), 'dup_shared_address_shared_ag_dg_address')
def test_misleading_services(self): test_xml = """\ <response status="success"><result><config><shared><service> <entry name="valid-tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry> <entry name="valid-tcp-1234"><protocol><tcp><port>123</port></tcp></protocol></entry> <entry name="valid-udp-123"><protocol><udp><port>123</port></udp></protocol></entry> <entry name="valid-udp-1234"><protocol><udp><port>123</port></udp></protocol></entry> <entry name="invalid-protocol-tcp-123"><protocol><udp><port>123</port></udp></protocol></entry> <entry name="invalid-protocol-udp-1234"><protocol><tcp><port>123</port></tcp></protocol></entry> <entry name="invalid-port-1233"><protocol><udp><port>1234</port></udp></protocol></entry> <entry name="invalid-port-and-protocol-tcp-123"><protocol><udp><port>1234</port></udp></protocol></entry> </service></shared></config></result></response> """ pan_config = PanConfig(test_xml) services = pan_config.get_devicegroup_object('Services', 'shared') profilepackage = self.create_profilepackage(services) _, _, validator_function = get_policy_validators( )['MisleadingServices'] results = validator_function(profilepackage) self.assertEqual(len(results), 4) self.assertEqual(results[0].data.get('name'), 'invalid-protocol-tcp-123') self.assertEqual(results[1].data.get('name'), 'invalid-protocol-udp-1234') self.assertEqual(results[2].data.get('name'), 'invalid-port-1233') self.assertEqual(results[3].data.get('name'), 'invalid-port-and-protocol-tcp-123')
def remove_redundant_rule_members(profilepackage): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator_function = get_policy_validators( )['RedundantRuleAddresses'] logger.info("*" * 80) logger.info("Checking for redundant rule addresses") rules_to_update = validator_function(profilepackage) logger.info(f"Replacing the contents of {len(rules_to_update)} Policies") for badentry in rules_to_update: object_policy_dg = badentry.device_group rule_type, rule_entry, members_to_remove = badentry.data rule_dict = xml_object_to_dict(rule_entry)['entry'] for direction, member_and_containing_pairs in members_to_remove.items( ): for member, _ in member_and_containing_pairs: # It's possible a member is contained in two of a rule's address groups if member in rule_dict[direction]['member']: rule_dict[direction]['member'].remove(member) pan_api.update_devicegroup_policy(panorama, version, api_key, rule_dict, rule_type, object_policy_dg) pan_api.validate_commit(panorama, api_key) logger.info("Replacement complete. Please commit in the firewall.") return rules_to_update
def test_equivalent_addressgroups(self): test_xml = """\ <response status="success"><result><config> <shared> <address> <entry name="unique_netmask1"><ip-netmask>127.0.0.2/32</ip-netmask></entry> <entry name="unique_netmask2"><ip-netmask>127.0.0.1/32</ip-netmask></entry> </address> <address-group> <entry name="address_group1"><static><member>unique_netmask1</member><member>unique_netmask2</member></static></entry> <entry name="address_group2"><static><member>unique_netmask2</member><member>unique_netmask1</member></static></entry> </address-group> </shared> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage('AddressGroups', pan_config) _, _, validator_function = get_policy_validators( )['EquivalentAddressGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1].get('name'), 'address_group1') self.assertEqual(results[0].data[1][0], 'shared') self.assertEqual(results[0].data[1][1].get('name'), 'address_group2')
def find_consolidatable_services(profilepackage): object_type = "Services" object_friendly_type = "Service" _, _, validator_function = get_policy_validators()['EquivalentServices'] return consolidate_service_like_objects(profilepackage, object_type, object_friendly_type, validator_function)
def test_equivalent_servicegroups(self): test_xml = """\ <response status="success"><result><config> <shared> <service> <entry name="tcp-1"><protocol><tcp><port>1</port><override><no/></override></tcp></protocol></entry> <entry name="tcp-2"><protocol><tcp><port>2</port><override><no/></override></tcp></protocol></entry> </service> <service-group> <entry name="dup1"><members><member>tcp-1</member><member>tcp-2</member></members></entry> <entry name="dup2"><members><member>tcp-2</member><member>tcp-1</member></members></entry> </service-group> </shared> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage('ServiceGroups', pan_config) _, _, validator_function = get_policy_validators( )['EquivalentServiceGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1].get('name'), 'dup1') self.assertEqual(results[0].data[1][0], 'shared') self.assertEqual(results[0].data[1][1].get('name'), 'dup2')
def test_similar_shared_address_and_dg_addressgroups(self): # SimilarAddressesAndGroups previously detected # duplicates across device groups. This test is # being kept to ensure behavior is as expected. test_xml = """\ <response status="success"><result><config> <shared> <address-group> <entry name="SHARED_address_and_dg_addressgroup"/> </address-group> </shared> <devices><entry><device-group><entry name="test_dg"> <address> <entry name="shared_address_and_DG_addressgroup"/> </address> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) shared_addresses = pan_config.get_devicegroup_object( 'Addresses', 'shared') dg_addesses = pan_config.get_devicegroup_object('Addresses', 'test_dg') shared_addressgroups = pan_config.get_devicegroup_object( 'AddressGroups', 'shared') dg_addessgroups = pan_config.get_devicegroup_object( 'AddressGroups', 'test_dg') profilepackage = self.create_profilepackage(shared_addresses, dg_addesses, shared_addressgroups, dg_addessgroups) _, _, validator_function = get_policy_validators( )['SimilarAddressesAndGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 0)
def test_shadowing_services(self): test_xml = """\ <response status="success"><result><config> <shared> <service> <entry name="tcp-nondup"><protocol><tcp><port>1</port><override><no/></override></tcp></protocol></entry> <entry name="tcp-dup"><protocol><tcp><port>2</port><override><no/></override></tcp></protocol></entry> </service> </shared> <devices><entry><device-group><entry name="test_dg"> <service> <entry name="tcp-dup"><protocol><tcp><port>2</port><override><no/></override></tcp></protocol></entry> </service> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) shared_services = pan_config.get_devicegroup_object('Services', 'shared') dg_services = pan_config.get_devicegroup_object('Services', 'test_dg') profilepackage = self.create_profilepackage(shared_services, dg_services, [], []) _, _, validator_function = get_policy_validators()['ShadowingServices'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1].get('name'), 'tcp-dup') self.assertEqual(results[0].data[1][0], 'test_dg') self.assertEqual(results[0].data[1][1].get('name'), 'tcp-dup')
def test_shadowing_servicegroups(self): test_xml = """\ <response status="success"><result><config> <shared> <service-group> <entry name="uniquegroup1"><members><member>mem1</member><member>mem2</member></members></entry> <entry name="dupgroup1"><members><member>mem1</member><member>mem2</member></members></entry> </service-group> </shared> <devices><entry><device-group><entry name="test_dg"> <service-group> <entry name="dupgroup1"><members><member>mem1</member><member>mem2</member></members></entry> <entry name="uniquegroup2"><members><member>mem1</member><member>mem2</member></members></entry> </service-group> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) shared_service_groups = pan_config.get_devicegroup_object('ServiceGroups', 'shared') dg_service_groups = pan_config.get_devicegroup_object('ServiceGroups', 'test_dg') profilepackage = self.create_profilepackage([], [], shared_service_groups, dg_service_groups) _, _, validator_function = get_policy_validators()['ShadowingServiceGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1].get('name'), 'dupgroup1') self.assertEqual(results[0].data[1][0], 'test_dg') self.assertEqual(results[0].data[1][1].get('name'), 'dupgroup1')
def test_misleading_services(self): test_xml = """\ <response status="success"><result><config><shared><service> <entry name="prefix-tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry> <entry name="prefix-tcp-1234"><protocol><tcp><port>123</port></tcp></protocol></entry> <entry name="prefix-udp-123"><protocol><udp><port>123</port></udp></protocol></entry> <entry name="prefix-udp-1234"><protocol><udp><port>123</port></udp></protocol></entry> <entry name="missing-tcp-123"><protocol><udp><port>1234</port></udp></protocol></entry> </service></shared></config></result></response> """ pan_config = PanConfig(test_xml) service_name_format = 'prefix-{transport}-{port}' profilepackage = self.create_profilepackage(pan_config, service_name_format) _, _, validator_function = get_policy_validators( )['UnconventionallyNamedServices'] results = validator_function(profilepackage) self.assertEqual(len(results), 3) self.assertEqual(results[0].data[0].get('name'), 'prefix-tcp-1234') self.assertEqual(results[0].data[1], 'prefix-tcp-123') self.assertEqual(results[1].data[0].get('name'), 'prefix-udp-1234') self.assertEqual(results[1].data[1], 'prefix-udp-123') self.assertEqual(results[2].data[0].get('name'), 'missing-tcp-123') self.assertEqual(results[2].data[1], 'prefix-udp-1234')
def find_badhostnameusage(profilepackage): device_groups = profilepackage.device_groups devicegroup_objects = profilepackage.devicegroup_objects devicegroup_exclusive_objects = profilepackage.devicegroup_exclusive_objects _, _, validator_function = get_policy_validators()['BadHostname'] bad_hostname_results = validator_function(profilepackage) bad_address_objects = set() for entry in bad_hostname_results: bad_address_objects.add(entry.data.get('name')) badentries = [] for i, device_group in enumerate(device_groups): logger.info( f"({i + 1}/{len(device_groups)}) Checking {device_group}'s Address Groups" ) for entry in devicegroup_objects[device_group]['AddressGroups']: address_group_members = [] for ag_member in entry.findall('./static/member'): address_group_members.append(ag_member.text) bad_members = bad_address_objects & set(address_group_members) if bad_members: text = f"Device Group {device_group}'s Address Group '{entry.get('name')}' uses the following address objects which don't resolve: {sorted(bad_members)}" badentries.append( BadEntry(data=entry, text=text, device_group=device_group, entry_type='AddressGroups')) for i, device_group in enumerate(device_groups): for ruletype in ('SecurityPreRules', 'SecurityPostRules'): rules = devicegroup_exclusive_objects[device_group][ruletype] logger.info( f"({i + 1}/{len(device_groups)}) Checking {device_group}'s {ruletype}" ) for entry in rules: # Disabled rules can be ignored if entry.find("./disabled") is not None and entry.find( "./disabled").text == "yes": continue rule_name = entry.get('name') source_members = set( [sm.text for sm in entry.findall('./source/member')]) dest_members = set( [dm.text for dm in entry.findall('./destination/member')]) for members, direction in [(source_members, 'Source'), (dest_members, 'Dest')]: bad_members = bad_address_objects & members if bad_members: text = f"Device Group {device_group}'s {ruletype} '{rule_name}' {direction} contain the following address objects which don't resolve: {sorted(bad_members)}" badentries.append( BadEntry(data=entry, text=text, device_group=device_group, entry_type=ruletype)) return badentries
def rename_unconventional_object(profilepackage, validator_name, object_type, object_friendly_name): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator_function = get_policy_validators()[validator_name] objects_to_rename = validator_function(profilepackage) if not objects_to_rename: return objects_to_rename logger.info( f"Renaming {len(objects_to_rename)} {object_friendly_name} now") for object_entry in objects_to_rename: device_group = object_entry.device_group old_name = object_entry.data[0].get('name') new_name = object_entry.data[1] logger.info( f"Renaming Device Group {device_group}'s {object_friendly_name} from {old_name} to {new_name}" ) try: pan_api.rename_object(panorama, version, api_key, object_type, old_name, new_name, device_group) except requests.HTTPError as err: logger.info( f"Error Renaming {device_group}'s {object_friendly_name} {old_name}: {err.response.text}" ) pan_api.validate_commit(panorama, api_key) return objects_to_rename
def test_IPWithResolvingFQDN(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="redundant_ip"><ip-netmask>127.0.0.1/32</ip-netmask></entry> <entry name="valid_fqdn"><fqdn>valid.tld</fqdn></entry> <entry name="invalid_fqdn"><fqdn>invalid.bad.tld</fqdn></entry> </address> </shared> </config></result></response> """ pan_config = PanConfig(test_xml) mocked_dns_lookup.side_effect = [('valid.tld', [], ["127.0.0.1"]), (None, [], [])] profilepackage = self.create_profilepackage(pan_config) _, _, validator_function = get_policy_validators( )['IPWithResolvingFQDN'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(results[0].data[0].get('name'), 'redundant_ip') self.assertEqual(results[0].data[1], 'valid.tld')
def remove_redundant_rule_services(profilepackage): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator_function = get_policy_validators()['ShadowingRules'] logger.info("*" * 80) logger.info("Checking for shadowed rules to disable") rules_to_update = validator_function(profilepackage) logger.info(f"Disabling {len(rules_to_update)} Policies") for badentry in rules_to_update: shadowed_tuple = badentry.data[0] device_group, ruletype, rule_name, rule_entry = shadowed_tuple disabled = (rule_entry.find('disabled') is not None and rule_entry.find('disabled').text == 'yes') if not disabled: policy_dict = xml_object_to_dict(rule_entry)['entry'] policy_dict['disabled'] = 'yes' logger.info(f"Disabling {device_group}'s {ruletype} {rule_name}") pan_api.update_devicegroup_policy(panorama, version, api_key, policy_dict, ruletype, device_group) pan_api.validate_commit(panorama, api_key) logger.info("Disabling complete. Please commit in the firewall.") return rules_to_update
def test_consolidatable_addresses(self): test_xml = """\ <response status="success"><result><config> <shared> <address> <entry name="unique_netmask1"><ip-netmask>127.0.0.1/32</ip-netmask></entry> <entry name="unique_netmask2"><ip-netmask>127.0.0.2/32</ip-netmask></entry> <entry name="duplicate_netmask2"><ip-netmask>127.0.0.2/32</ip-netmask></entry> </address> <address-group> <entry name="address_group1"><static><member>unique_netmask1</member><member>unique_netmask2</member></static></entry> <entry name="address_group2"><static><member>unique_netmask2</member><member>unique_netmask1</member></static></entry> <entry name="address_group3"><static><member>duplicate_netmask2</member><member>unique_netmask1</member></static></entry> </address-group> </shared> <devices><entry><device-group><entry name="test_dg"> <pre-rulebase><security><rules> <entry name="rule1"> <from><member>src_zone</member></from> <to><member>dest_zone</member></to> <source><member>unique_netmask1</member></source> <destination><member>unique_netmask2</member></destination> <service><member>tcp2-dup1</member></service> </entry> <entry name="rule2"> <from><member>src_zone</member></from> <to><member>dest_zone</member></to> <source><member>unique_netmask1</member></source> <destination><member>unique_netmask2</member></destination> <service><member>tcp2-dup1</member></service> </entry> <entry name="rule3"> <from><member>src_zone</member></from> <to><member>dest_zone</member></to> <source><member>unique_netmask1</member></source> <destination><member>duplicate_netmask2</member></destination> <service><member>tcp2-dup2</member></service> </entry> </rules></security></pre-rulebase> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(pan_config) _, _, validator_function = get_policy_validators( )['FindConsolidatableAddresses'] results = validator_function(profilepackage) self.assertEqual(len(results), 2) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0].get('name'), 'address_group3') self.assertEqual(results[0].data[1]['static']['member'][0], 'unique_netmask2') self.assertEqual(len(results[1].data), 2) self.assertEqual(results[1].data[0].get('name'), 'rule3') self.assertEqual(results[1].data[1]['destination']['member'], 'unique_netmask2')
def test_similar_servicegroups(self): test_xml = """\ <response status="success"><result><config> <shared> <service-group> <entry name="shared_servicegroup1"/> <entry name="SHARED_servicegroup1"/> </service-group> </shared> <devices><entry><device-group><entry name="test_dg"> <service-group> <entry name="dg_servicegroup1"/> <entry name="DG_servicegroup1"/> </service-group> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) shared_services = pan_config.get_devicegroup_object( 'Services', 'shared') dg_services = pan_config.get_devicegroup_object('Services', 'test_dg') shared_servicegroups = pan_config.get_devicegroup_object( 'ServiceGroups', 'shared') dg_servicegroups = pan_config.get_devicegroup_object( 'ServiceGroups', 'test_dg') profilepackage = self.create_profilepackage(shared_services, dg_services, shared_servicegroups, dg_servicegroups) _, _, validator_function = get_policy_validators( )['SimilarServicesAndGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 2) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1], 'ServiceGroups') self.assertEqual(results[0].data[0][2].get('name'), 'shared_servicegroup1') self.assertEqual(results[0].data[1][0], 'shared') self.assertEqual(results[0].data[1][1], 'ServiceGroups') self.assertEqual(results[0].data[1][2].get('name'), 'SHARED_servicegroup1') self.assertEqual(len(results[1].data), 2) self.assertEqual(results[1].data[0][0], 'test_dg') self.assertEqual(results[1].data[0][1], 'ServiceGroups') self.assertEqual(results[1].data[0][2].get('name'), 'dg_servicegroup1') self.assertEqual(results[1].data[1][0], 'test_dg') self.assertEqual(results[1].data[1][1], 'ServiceGroups') self.assertEqual(results[1].data[1][2].get('name'), 'DG_servicegroup1')
def test_replaceableaddresses(self): test_xml = """\ <response status="success"><result><config> <devices><entry><device-group><entry name="test_dg"> <pre-rulebase><security><rules> <entry name="sservices_can_be_group"> <source> <member>ip-127.0.0.1</member> <member>ip-127.0.0.2</member> </source> <destination> <member>ip-127.0.0.3</member> </destination> <service> <member>tcp-123</member> <member>tcp-456</member> </service> </entry> </rules></security></pre-rulebase> <address> <entry name="ip-127.0.0.1"><ip-netmask>127.0.0.1</ip-netmask></entry> <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> </address> <address-group> <entry name="address_addressgroup1"><static><member>ip-127.0.0.1</member><member>ip-127.0.0.2</member></static></entry> </address-group> <service> <entry name="tcp-123"><protocol><tcp><port>123</port></tcp></protocol></entry> <entry name="tcp-456"><protocol><tcp><port>456</port></tcp></protocol></entry> </service> <service-group><entry name="myservicegroup"><members><member>tcp-123</member><member>tcp-456</member></members></entry></service-group> </entry></device-group></entry></devices> <readonly><devices><entry name="localhost.localdomain"><device-group> <entry name="test_dg"><id>11</id></entry> </device-group></entry></devices></readonly> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(pan_config) _, _, validator_function = get_policy_validators()['ServicesShouldBeGroups'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(len(results[0].data), 3) self.assertEqual(results[0].data[0], 'SecurityPreRules') self.assertEqual(results[0].data[1].get('name'), 'sservices_can_be_group') self.assertEqual(results[0].data[2], "myservicegroup") self.assertEqual(results[0].device_group, 'test_dg')
def fix_bad_log_setting(profilepackage): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator = get_policy_validators()['BadLogSetting'] problems = validator(profilepackage) for problem in problems: entry = xml_object_to_dict(problem.data[0])['entry'] ruletype = problem.entry_type device_group = problem.device_group entry["log-setting"] = problem.data[1] logger.debug(f"Updating {device_group}'s {ruletype} {problem.data[0].get('name')} log-setting to {entry['log-setting']}") pan_api.update_devicegroup_policy(panorama, version, api_key, entry, ruletype, device_group) return problems
def fix_bad_log_setting(profilepackage): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator = get_policy_validators()['UnqualifiedFQDN'] problems = validator(profilepackage) for problem in problems: entry = xml_object_to_dict(problem.data[0])['entry'] object_type = problem.entry_type device_group = problem.device_group entry['fqdn'] = problem.data[1] pan_api.update_devicegroup_object(panorama, version, api_key, entry, object_type, device_group) return problems
def test_equivalent_addresses(self): test_xml = """\ <response status="success"><result><config> <shared> <address> <entry name="unique_netmask"><ip-netmask>ignored.tld</ip-netmask></entry> <entry name="dupe_netmask1"><ip-netmask>127.0.0.1</ip-netmask></entry> <entry name="dupe_netmask2"><ip-netmask>127.0.0.1/32</ip-netmask></entry> <entry name="dup_fqdn1"><fqdn>dupfqdn.tld</fqdn></entry> <entry name="dup_fqdn2"><fqdn>dupfqdn.tld</fqdn></entry> </address> </shared> <devices><entry><device-group><entry name="test_dg"> <address> <entry name="unique_fqdn"><ip-netmask>unique.tld</ip-netmask></entry> <entry name="dup_fqdn3"><fqdn>dupfqdn.tld</fqdn></entry> </address> </entry></device-group></entry></devices> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage('Addresses', pan_config) _, _, validator_function = get_policy_validators( )['EquivalentAddresses'] results = validator_function(profilepackage) self.assertEqual(len(results), 3) self.assertEqual(len(results[0].data), 2) self.assertEqual(results[0].data[0][0], 'shared') self.assertEqual(results[0].data[0][1].get('name'), 'dup_fqdn1') self.assertEqual(results[0].data[1][0], 'shared') self.assertEqual(results[0].data[1][1].get('name'), 'dup_fqdn2') self.assertEqual(len(results[1].data), 2) self.assertEqual(results[1].data[0][0], 'shared') self.assertEqual(results[1].data[0][1].get('name'), 'dupe_netmask1') self.assertEqual(results[1].data[1][0], 'shared') self.assertEqual(results[1].data[1][1].get('name'), 'dupe_netmask2') self.assertEqual(len(results[2].data), 3) self.assertEqual(results[2].data[0][0], 'shared') self.assertEqual(results[2].data[0][1].get('name'), 'dup_fqdn1') self.assertEqual(results[2].data[1][0], 'shared') self.assertEqual(results[2].data[1][1].get('name'), 'dup_fqdn2') self.assertEqual(results[2].data[2][0], 'test_dg') self.assertEqual(results[2].data[2][1].get('name'), 'dup_fqdn3')
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="same_zone_rule"> <source> <member>address_addressgroup1</member> <member>ip-127.0.0.2</member> </source> <destination> <member>ip-127.0.0.3</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> </address> <address-group> <entry name="address_addressgroup1"><static><member>ip-127.0.0.2</member></static></entry> </address-group> </entry></device-group></entry></devices> <readonly><devices><entry name="localhost.localdomain"><device-group> <entry name="test_dg"><id>11</id></entry> </device-group></entry></devices></readonly> </config></result></response> """ pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(pan_config) _, _, validator_function = get_policy_validators()['RedundantRuleAddresses'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) ruletype, rule_entry, members_to_remove = results[0].data self.assertEqual(ruletype, 'SecurityPreRules') self.assertEqual(rule_entry.get('name'), 'same_zone_rule') self.assertEqual(list(members_to_remove.keys()), ['source']) self.assertEqual(len(members_to_remove['source']), 1) member, containing = members_to_remove['source'][0] self.assertEqual(member, 'ip-127.0.0.2') self.assertEqual(containing, 'address_addressgroup1')
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 fix_bad_log_setting(profilepackage): panorama = profilepackage.settings.get("Panorama") api_key = profilepackage.api_key pan_config = profilepackage.pan_config version = pan_config.get_major_version() _, _, validator = get_policy_validators()['IPWithResolvingFQDN'] problems = validator(profilepackage) for problem in problems: object_type = problem.entry_type device_group = problem.device_group address_entry, fqdn = problem.data updated_object = xml_object_to_dict(address_entry)['entry'] logger.debug(f"Updating {device_group} Address {address_entry.get('name')} from {updated_object['ip-netmask']} to {fqdn}") del updated_object['ip-netmask'] updated_object['fqdn'] = fqdn pan_api.update_devicegroup_object(panorama, version, api_key, updated_object, object_type, device_group) return problems
def test_without_mandated_logsetting(self): test_xml = """\ <response status="success"><result><config> <devices><entry><device-group><entry name="test_dg"> <pre-rulebase><security><rules> <entry name="disabled_rule"><disabled>yes</disabled></entry> <entry name="missing_log-setting"><disabled>no</disabled></entry> <entry name="correct_log-setting"><log-setting>correct</log-setting></entry> <entry name="wrong_log-setting"><log-setting>wrong</log-setting></entry> </rules></security></pre-rulebase> </entry></device-group></entry></devices> </config></result></response> """ mandated_log_profile = None pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(pan_config, mandated_log_profile) _, _, validator_function = get_policy_validators()['BadLogSetting'] results = validator_function(profilepackage) self.assertEqual(len(results), 0)
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="disabled_rule"><disabled>yes</disabled></entry> <entry name="missing_gp"></entry> <entry name="correct_gp"><profile-setting><group><member>correct</member></group></profile-setting></entry> <entry name="wrong_gp"><profile-setting><group><member>wrong</member></group></profile-setting></entry> </rules></security></pre-rulebase> </entry></device-group></entry></devices> </config></result></response> """ allowed_group_profile = 'correct' pan_config = PanConfig(test_xml) profilepackage = self.create_profilepackage(allowed_group_profile, pan_config) _, _, validator_function = get_policy_validators()['BadGroupProfile'] results = validator_function(profilepackage) self.assertEqual(len(results), 2) self.assertEqual(results[0].data.get('name'), 'missing_gp') self.assertEqual(results[1].data.get('name'), 'wrong_gp')