Esempio n. 1
0
def invert_generic_cluster_host(host: GenericClusterHost):
    """
    Returns a list of GenericClusterHosts with
    once inverted pod label selectors,
    once inverted namespace label selectors
    and once both
    """
    if host == GenericClusterHost({}, {}):
        raise ValueError(
            "Cannot invert GenericClusterHost matching all hosts in cluster"
        )
    if host.namespace_labels == {}:
        return [GenericClusterHost({}, invert_label_selector(host.pod_labels))]
    inverted_hosts = [
        GenericClusterHost(
            host.namespace_labels, invert_label_selector(host.pod_labels)
        ),
        GenericClusterHost(
            invert_label_selector(host.namespace_labels), host.pod_labels
        ),
        GenericClusterHost(
            invert_label_selector(host.namespace_labels),
            invert_label_selector(host.pod_labels),
        ),
    ]
    return inverted_hosts
Esempio n. 2
0
def invert_generic_cluster_host(host: GenericClusterHost):
    if host == GenericClusterHost({}, {}):
        raise ValueError(
            "Cannot invert GenericClusterHost matching all hosts in cluster")
    elif host.namespace_labels == {}:
        return [GenericClusterHost({}, invert_labels(host.pod_labels))]
    else:
        inverted_hosts = [
            GenericClusterHost(host.namespace_labels,
                               invert_labels(host.pod_labels)),
            GenericClusterHost(invert_labels(host.namespace_labels),
                               host.pod_labels),
            GenericClusterHost(invert_labels(host.namespace_labels),
                               invert_labels(host.pod_labels))
        ]
        return inverted_hosts
Esempio n. 3
0
def _get_other_host_from(connection_targets, rule_namespace):
    namespace_labels = "namespaceLabels"
    pod_labels = "podLabels"
    namespace = "namespace"
    if namespace_labels in connection_targets and pod_labels in connection_targets:
        return GenericClusterHost(connection_targets[namespace_labels],
                                  connection_targets[pod_labels])
    if namespace in connection_targets and pod_labels in connection_targets:
        return ClusterHost(connection_targets[namespace],
                           connection_targets[pod_labels])
    if namespace_labels in connection_targets:  # and no podLabels included
        return GenericClusterHost(connection_targets[namespace_labels], {})
    if pod_labels in connection_targets:
        return ClusterHost(rule_namespace, connection_targets[pod_labels])
    if connection_targets == {}:
        return GenericClusterHost({}, {})
    raise ValueError("Unknown combination of field in connection %s" %
                     connection_targets)
Esempio n. 4
0
def test__generate_test_cases__allow_all__returns_single_positive_case():
    namespaces = [_generate_namespace("default")]
    networkpolicies = [_generate_allow_all_network_policy("default")]
    expected = [
        NetworkTestCase(
            GenericClusterHost({}, {}), ClusterHost("default", {}), "*", True
        )
    ]
    cases, _ = gen.generate_test_cases(networkpolicies, namespaces)
    assert len(cases) == 1
    assert cases == expected
Esempio n. 5
0
 def generate_negative_cases_for_incoming_cases(self, isolated_hosts,
                                                incoming_test_cases,
                                                other_hosts, namespaces):
     runtimes = {}
     start_time = time.time()
     namespace_labels = [
         h.namespace_labels for h in other_hosts
         if isinstance(h, GenericClusterHost)
     ]
     namespaces_per_label_strings = {
         labels_to_string(k): [
             n.metadata.name for n in namespaces
             if n.metadata.labels is not None
             and k.items() <= n.metadata.labels.items()
         ]
         for k in namespace_labels
     }
     namespace_label_resolve_time = time.time()
     runtimes["nsLabelResolve"] = namespace_label_resolve_time - start_time
     labels_per_namespace = {
         n.metadata.name: n.metadata.labels
         for n in namespaces
     }
     overlaps_per_host = {
         host: get_overlapping_hosts(host, namespaces_per_label_strings,
                                     labels_per_namespace,
                                     isolated_hosts + other_hosts)
         for host in isolated_hosts
     }
     overlap_calc_time = time.time()
     runtimes[
         "overlapCalc"] = overlap_calc_time - namespace_label_resolve_time
     cases = []
     for host in isolated_hosts:
         host_string = str(host)
         host_start_time = time.time()
         runtimes[host_string] = {}
         # Check for hosts that can target these to construct negative cases from
         logger.debug(overlaps_per_host[host])
         reaching_hosts_with_ports = [
             (t.from_host, t.port_string) for t in incoming_test_cases
             if t.to_host in overlaps_per_host[host]
         ]
         logger.debug(reaching_hosts_with_ports)
         reaching_host_find_time = time.time()
         runtimes[host_string][
             "findReachingHosts"] = reaching_host_find_time - host_start_time
         if reaching_hosts_with_ports:
             reaching_hosts, _ = zip(*reaching_hosts_with_ports)
             ports_per_host = {
                 host:
                 [p for h, p in reaching_hosts_with_ports if h == host]
                 for host in reaching_hosts
             }
             match_all_host = GenericClusterHost({}, {})
             if match_all_host in reaching_hosts:
                 # All hosts are allowed to reach (on some ports or all) => results from ALLOW all
                 if "*" in ports_per_host[match_all_host]:
                     logger.info("Not generating negative tests for host " +
                                 str(host) +
                                 " as all connections to it are allowed")
                 else:
                     case = NetworkTestCase(
                         match_all_host, host,
                         rand_port(ports_per_host[match_all_host]), False)
                     cases.append(case)
                 runtimes[host_string]["matchAllCase"] = time.time(
                 ) - reaching_host_find_time
             else:
                 inverted_hosts = set([
                     h for l in
                     [invert_host(host) for host in reaching_hosts]
                     for h in l
                 ])
                 hosts_on_inverted = {
                     h: originalHost
                     for l, originalHost in [(invert_host(host), host)
                                             for host in reaching_hosts]
                     for h in l
                 }
                 host_inversion_time = time.time()
                 runtimes[host_string][
                     "hostInversion"] = host_inversion_time - reaching_host_find_time
                 overlaps_for_inverted_hosts = {
                     h:
                     get_overlapping_hosts(h, namespaces_per_label_strings,
                                           labels_per_namespace,
                                           reaching_hosts)
                     for h in inverted_hosts
                 }
                 overlap_calc_time = time.time()
                 runtimes[host_string][
                     "overlapCalc"] = overlap_calc_time - host_inversion_time
                 logger.debug("InvertedHosts: " + str(inverted_hosts))
                 negative_test_targets = [
                     h for h in inverted_hosts
                     if len(overlaps_for_inverted_hosts[h]) <= 1
                 ]
                 logger.debug("NegativeTestTargets: " +
                              str(negative_test_targets))
                 # now remove the inverted hosts that are reachable
                 for target in negative_test_targets:
                     ports_for_inverted_hosts_original_host = ports_per_host[
                         hosts_on_inverted[target]]
                     if ports_for_inverted_hosts_original_host:
                         cases.append(
                             NetworkTestCase(
                                 target, host,
                                 ports_for_inverted_hosts_original_host[0],
                                 False))
                     else:
                         cases.append(
                             NetworkTestCase(target, host, "*", False))
                 runtimes[host_string]["casesGen"] = time.time(
                 ) - overlap_calc_time
         else:
             # No hosts are allowed to reach host -> it should be totally isolated
             # => results from default deny policy
             cases.append(NetworkTestCase(host, host, "*", False))
         runtimes["all"] = time.time() - start_time
Esempio n. 6
0
 def generate_negative_cases_for_incoming_cases(
     self, isolated_hosts, incoming_test_cases, other_hosts, namespaces
 ):
     """
     Generates negative test cases based on desired positive test cases
     """
     runtimes = {}
     start_time = time.time()
     # list of all namespace labels set on other hosts
     namespace_labels = [
         h.namespace_labels for h in other_hosts if isinstance(h, GenericClusterHost)
     ]
     namespaces_per_label_strings = get_namespace_label_strings(
         namespace_labels, namespaces
     )
     namespace_label_resolve_time = time.time()
     runtimes["nsLabelResolve"] = namespace_label_resolve_time - start_time
     labels_per_namespace = {n.metadata.name: n.metadata.labels for n in namespaces}
     overlaps_per_host = {
         host: self.get_overlapping_hosts(
             host,
             namespaces_per_label_strings,
             labels_per_namespace,
             isolated_hosts + other_hosts,
         )
         for host in isolated_hosts
     }
     overlap_calc_time = time.time()
     runtimes["overlapCalc"] = overlap_calc_time - namespace_label_resolve_time
     cases = []
     for host in isolated_hosts:
         host_string = str(host)
         host_start_time = time.time()
         runtimes[host_string] = {}
         # Check for hosts that can target these to construct negative cases from
         self.logger.debug(overlaps_per_host[host])
         allowed_hosts_with_ports = [
             (test_case.from_host, test_case.port_string)
             for test_case in incoming_test_cases
             if test_case.to_host in overlaps_per_host[host]
         ]
         self.logger.debug("allowed_hosts_with_ports=%s", allowed_hosts_with_ports)
         reaching_host_find_time = time.time()
         runtimes[host_string]["findReachingHosts"] = (
             reaching_host_find_time - host_start_time
         )
         if allowed_hosts_with_ports:
             allowed_hosts, _ = zip(*allowed_hosts_with_ports)
             ports_per_host = {
                 host: [
                     port
                     for _host, port in allowed_hosts_with_ports
                     if _host == host
                 ]
                 for host in allowed_hosts
             }
             match_all_host = GenericClusterHost({}, {})
             if match_all_host in allowed_hosts:
                 # All hosts are allowed to reach (on some ports or all) => results from ALLOW all
                 if "*" in ports_per_host[match_all_host]:
                     self.logger.info(
                         "Not generating negative tests for host %s"
                         "as all connections to it are allowed",
                         host,
                     )
                 else:
                     cases.append(
                         NetworkTestCase(
                             match_all_host,
                             host,
                             rand_port(ports_per_host[match_all_host]),
                             False,
                         )
                     )
                 runtimes[host_string]["matchAllCase"] = (
                     time.time() - reaching_host_find_time
                 )
             else:
                 inverted_hosts = set(
                     [
                         h
                         for l in [invert_host(host) for host in allowed_hosts]
                         for h in l
                     ]
                 )
                 hosts_on_inverted = {
                     h: originalHost
                     for l, originalHost in [
                         (invert_host(host), host) for host in allowed_hosts
                     ]
                     for h in l
                 }
                 host_inversion_time = time.time()
                 runtimes[host_string]["hostInversion"] = (
                     host_inversion_time - reaching_host_find_time
                 )
                 overlaps_for_inverted_hosts = {
                     h: self.get_overlapping_hosts(
                         h,
                         namespaces_per_label_strings,
                         labels_per_namespace,
                         allowed_hosts,
                     )
                     for h in inverted_hosts
                 }
                 overlap_calc_time = time.time()
                 runtimes[host_string]["overlapCalc"] = (
                     overlap_calc_time - host_inversion_time
                 )
                 self.logger.debug("InvertedHosts: %s", inverted_hosts)
                 negative_test_targets = [
                     h
                     for h in inverted_hosts
                     if len(overlaps_for_inverted_hosts[h]) <= 1
                 ]
                 self.logger.debug("NegativeTestTargets: %s", negative_test_targets)
                 # now remove the inverted hosts that are reachable
                 for target in negative_test_targets:
                     ports_for_inverted_hosts_original_host = ports_per_host[
                         hosts_on_inverted[target]
                     ]
                     if ports_for_inverted_hosts_original_host:
                         cases.append(
                             NetworkTestCase(
                                 target,
                                 host,
                                 ports_for_inverted_hosts_original_host[0],
                                 False,
                             )
                         )
                     else:
                         cases.append(NetworkTestCase(target, host, "*", False))
                 runtimes[host_string]["casesGen"] = time.time() - overlap_calc_time
         else:
             # No hosts are allowed to reach host -> it should be totally isolated
             # => results from default deny policy
             cases.append(NetworkTestCase(host, host, "*", False))
         runtimes["all"] = time.time() - start_time
     return cases, runtimes
     ],
     [
         k8s.client.V1NetworkPolicy(
             metadata=k8s.client.V1ObjectMeta(name="allow-all",
                                              namespace="default"),
             spec=k8s.client.V1NetworkPolicySpec(
                 pod_selector=k8s.client.V1LabelSelector(
                     match_labels=None),
                 ingress=[
                     k8s.client.V1NetworkPolicyIngressRule(_from=None)
                 ],
             ),
         )
     ],
     [
         NetworkTestCase(GenericClusterHost({}, {}),
                         ClusterHost("default", {}), "*", True)
     ],
     id="Allow all traffic in namespace",
 ),
 pytest.param(
     [
         k8s.client.V1Namespace(metadata=k8s.client.V1ObjectMeta(
             name="default"))
     ],
     [
         k8s.client.V1NetworkPolicy(
             metadata=k8s.client.V1ObjectMeta(name="deny-all",
                                              namespace="default"),
             spec=k8s.client.V1NetworkPolicySpec(
                 pod_selector=k8s.client.V1LabelSelector(
Esempio n. 8
0
     id="Simple ClusterHost",
 ),
 pytest.param(
     "illuminatio-inverted-default:illuminatio-inverted-test.io/test-123_XYZ=test_456-123.ABC",
     ClusterHost(
         "illuminatio-inverted-default",
         {
             "illuminatio-inverted-test.io/test-123_XYZ":
             "test_456-123.ABC"
         },
     ),
     id="ClusterHost containing all allowed label characters",
 ),
 pytest.param(
     "test=test:test=test",
     GenericClusterHost({"test": "test"}, {"test": "test"}),
     id="Simple GenericClusterHost",
 ),
 pytest.param(
     "illuminatio-inverted-test.io/test-123_XYZ=test_456-123.ABC:" +
     "illuminatio-inverted-test.io/test-123_XYZ=test_456-123.ABC",
     GenericClusterHost(
         {
             "illuminatio-inverted-test.io/test-123_XYZ":
             "test_456-123.ABC"
         },
         {
             "illuminatio-inverted-test.io/test-123_XYZ":
             "test_456-123.ABC"
         },
     ),