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_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_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_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="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 create_profilepackage(allowed_group_profile, pan_config): device_groups = ['test_dg'] rules = pan_config.get_devicegroup_policy('SecurityPreRules', 'test_dg') devicegroup_exclusive_objects = { 'test_dg': { 'SecurityPreRules': rules, 'SecurityPostRules': [] } } settings = ConfigurationSettings().get_config() settings['Allowed Group Profiles'] = allowed_group_profile profilepackage = ProfilePackage( api_key='', pan_config=PanConfig('<_/>'), settings=settings, device_group_hierarchy_children={}, device_group_hierarchy_parent={}, device_groups_and_firewalls={}, device_groups=device_groups, devicegroup_objects={}, devicegroup_exclusive_objects=devicegroup_exclusive_objects, rule_limit_enabled=False, no_api=False) return profilepackage
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 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_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 create_profilepackage(rules, addresses): device_groups = ['test_dg'] devicegroup_objects = {'test_dg': collections.defaultdict(list)} devicegroup_objects['test_dg']['Addresses'] = addresses devicegroup_objects['test_dg']['all_active_child_firewalls'] = [ "fake_firewall" ] devicegroup_exclusive_objects = { 'test_dg': collections.defaultdict(list) } devicegroup_exclusive_objects["test_dg"]['SecurityPreRules'] = rules profilepackage = ProfilePackage( api_key='', pan_config=PanConfig('<_/>'), settings=ConfigurationSettings().get_config(), device_group_hierarchy_children={}, device_group_hierarchy_parent={}, device_groups_and_firewalls={}, device_groups=device_groups, devicegroup_objects=devicegroup_objects, devicegroup_exclusive_objects=devicegroup_exclusive_objects, rule_limit_enabled=False, no_api=False) return profilepackage
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 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 create_profilepackage(shared_addresses, shared_addressgroups, shared_securityprerules, shared_natprerules, dg_addresses, dg_securityprerules): device_groups = ["shared"] devicegroup_objects = { "shared": collections.defaultdict(list), "test_dg": collections.defaultdict(list) } devicegroup_objects['shared']['all_child_device_groups'] = [ "shared", "test_dg" ] devicegroup_objects["shared"]['Addresses'] = shared_addresses devicegroup_objects["shared"]['AddressGroups'] = shared_addressgroups devicegroup_objects["shared"][ 'SecurityPreRules'] = shared_securityprerules devicegroup_objects["shared"]['NATPreRules'] = shared_natprerules devicegroup_objects["test_dg"]['SecurityPreRules'] = dg_addresses devicegroup_objects["test_dg"]['NATPreRules'] = dg_securityprerules profilepackage = ProfilePackage( api_key='', pan_config=PanConfig('<_/>'), settings=ConfigurationSettings().get_config(), device_group_hierarchy_children={}, device_group_hierarchy_parent={}, device_groups_and_firewalls={}, device_groups=device_groups, devicegroup_objects=devicegroup_objects, devicegroup_exclusive_objects={}, rule_limit_enabled=False, no_api=False) return profilepackage
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 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_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 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_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_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 test_misleading_addresses(self): test_xml = """\ <response status="success"><result><config><shared><address> <entry name="valid_ip_127.0.0.1"><ip-netmask>127.0.0.1</ip-netmask></entry> <entry name="invalid_ip_127.0.0.2"><ip-netmask>127.0.0.1</ip-netmask></entry> <entry name="valid_range_127.0.0.1"><ip-range>127.0.0.1-127.0.0.255</ip-range></entry> <entry name="invalid_range_128.0.0.1"><ip-range>127.0.0.1-127.0.0.255</ip-range></entry> <entry name="valid_fqdn_valid.tld"><fqdn>valid.tld</fqdn></entry> <entry name="invalid_fqdn_invalid.tld"><fqdn>missing.invalid.tld</fqdn></entry> </address></shared></config></result></response> """ pan_config = PanConfig(test_xml) addresses = pan_config.get_devicegroup_object('Addresses', 'shared') profilepackage = self.create_profilepackage(addresses) _, _, validator_function = get_policy_validators( )['MisleadingAddresses'] results = validator_function(profilepackage) self.assertEqual(len(results), 3) self.assertEqual(results[0].data.get('name'), 'invalid_ip_127.0.0.2') self.assertEqual(results[1].data.get('name'), 'invalid_range_128.0.0.1') self.assertEqual(results[2].data.get('name'), 'invalid_fqdn_invalid.tld')
def test_badhostname(self, mocked_fqdn_lookup): test_xml = """\ <response status="success"><result><config> <shared> <address> <entry name="ignored_missing_fqdn"><fqdn>ignored_missing</fqdn></entry> <entry name="missing_fqdn"><fqdn>missing</fqdn></entry> <entry name="valid_fqdn"><fqdn>valid.tld</fqdn></entry> </address> </shared> </config></result></response> """ pan_config = PanConfig(test_xml) addresses = pan_config.get_devicegroup_object('Addresses', 'shared') ignored_dns_prefixes = ["ignored"] mocked_fqdn_lookup.side_effect = ['missing.tld'] profilepackage = self.create_profilepackage(addresses, ignored_dns_prefixes) _, _, validator_function = get_policy_validators()['UnqualifiedFQDN'] results = validator_function(profilepackage) self.assertEqual(len(results), 1) self.assertEqual(results[0].data[0].get('name'), 'missing_fqdn') self.assertEqual(results[0].data[1], 'missing.tld')
def create_profilepackage(services): device_groups = ["shared"] devicegroup_objects = {"shared": {}} devicegroup_objects["shared"]['Services'] = services profilepackage = ProfilePackage( api_key='', pan_config=PanConfig('<_/>'), settings=ConfigurationSettings().get_config(), device_group_hierarchy_children={}, device_group_hierarchy_parent={}, device_groups_and_firewalls={}, device_groups=device_groups, devicegroup_objects=devicegroup_objects, devicegroup_exclusive_objects=[], rule_limit_enabled=False, no_api=False) return profilepackage
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_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_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 create_profilepackage(addresses, ignored_dns_prefixes): device_groups = ["shared"] devicegroup_objects = {"shared": {}} devicegroup_objects["shared"]['Addresses'] = addresses settings = ConfigurationSettings().get_config() settings['Ignored DNS Prefixes'] = ",".join(ignored_dns_prefixes) profilepackage = ProfilePackage( api_key='', pan_config=PanConfig('<_/>'), settings=settings, device_group_hierarchy_children={}, device_group_hierarchy_parent={}, device_groups_and_firewalls={}, device_groups=device_groups, devicegroup_objects=devicegroup_objects, devicegroup_exclusive_objects={}, rule_limit_enabled=False, no_api=False) return profilepackage
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 create_profilepackage(shared_addresses, dg_addresses, shared_address_groups, dg_address_groups): device_groups = ["shared", "test_dg"] device_group_hierarchy_parent = {"test_dg": "shared"} devicegroup_objects = {"shared": {}, "test_dg": {}} devicegroup_objects["shared"]['Addresses'] = shared_addresses devicegroup_objects["test_dg"]['Addresses'] = dg_addresses devicegroup_objects["shared"]['AddressGroups'] = shared_address_groups devicegroup_objects["test_dg"]['AddressGroups'] = dg_address_groups profilepackage = ProfilePackage( api_key='', pan_config=PanConfig('<_/>'), settings=ConfigurationSettings().get_config(), device_group_hierarchy_children={}, device_group_hierarchy_parent=device_group_hierarchy_parent, device_groups_and_firewalls={}, device_groups=device_groups, devicegroup_objects=devicegroup_objects, devicegroup_exclusive_objects={}, rule_limit_enabled=False, no_api=False) return profilepackage
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')
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