Esempio n. 1
0
def _parse_selectors_on_namespace(crd, direction, pod_selector, ns_selector,
                                  rule_block, crd_rules, namespace, matched):
    ns_name = namespace['metadata'].get('name')
    ns_labels = namespace['metadata'].get('labels')
    sg_id = crd['spec']['securityGroupId']

    if (ns_selector and ns_labels
            and driver_utils.match_selector(ns_selector, ns_labels)):
        if pod_selector:
            pods = driver_utils.get_pods(pod_selector, ns_name).get('items')
            if 'ports' in rule_block:
                for port in rule_block['ports']:
                    if type(port.get('port')) is not int:
                        matched = (_create_sg_rule_on_text_port(
                            sg_id, direction, port, pods, crd_rules, matched,
                            crd))
                    else:
                        matched = True
                        for pod in pods:
                            pod_ip = driver_utils.get_pod_ip(pod)
                            crd_rules.append(
                                _create_sg_rule(sg_id,
                                                direction,
                                                pod_ip,
                                                port=port,
                                                namespace=ns_name))
            else:
                for pod in pods:
                    pod_ip = driver_utils.get_pod_ip(pod)
                    matched = True
                    crd_rules.append(
                        _create_sg_rule(sg_id,
                                        direction,
                                        pod_ip,
                                        namespace=ns_name))
        else:
            ns_pods = driver_utils.get_pods(ns_selector)
            ns_cidr = driver_utils.get_namespace_subnet_cidr(namespace)
            if 'ports' in rule_block:
                for port in rule_block['ports']:
                    if type(port.get('port')) is not int:
                        matched = (_create_sg_rule_on_text_port(
                            sg_id, direction, port, ns_pods, crd_rules,
                            matched, crd))
                    else:
                        matched = True
                        crd_rules.append(
                            _create_sg_rule(sg_id,
                                            direction,
                                            ns_cidr,
                                            port=port,
                                            namespace=ns_name))
            else:
                matched = True
                crd_rules.append(
                    _create_sg_rule(sg_id,
                                    direction,
                                    ns_cidr,
                                    namespace=ns_name))
    return matched, crd_rules
 def _get_pods(self, pod_selector, namespace=None, namespace_selector=None):
     matching_pods = {"items": []}
     if namespace_selector:
         matching_namespaces = driver_utils.get_namespaces(
             namespace_selector)
         for ns in matching_namespaces.get('items'):
             matching_pods = driver_utils.get_pods(pod_selector,
                                                   ns['metadata']['name'])
     else:
         matching_pods = driver_utils.get_pods(pod_selector, namespace)
     return matching_pods.get('items')
Esempio n. 3
0
 def _is_service_affected(self, service, affected_pods):
     svc_namespace = service['metadata']['namespace']
     svc_selector = service['spec'].get('selector')
     svc_pods = driver_utils.get_pods({
         'selector': svc_selector
     }, svc_namespace).get('items')
     return any(pod in svc_pods for pod in affected_pods)
def _parse_rules(direction, crd, namespace):
    policy = crd['spec']['networkpolicy_spec']
    sg_id = crd['spec']['securityGroupId']

    ns_labels = namespace['metadata'].get('labels')
    ns_name = namespace['metadata'].get('name')
    ns_cidr = utils.get_namespace_subnet_cidr(namespace)

    rule_direction = 'from'
    crd_rules = crd['spec'].get('ingressSgRules')
    if direction == 'egress':
        rule_direction = 'to'
        crd_rules = crd['spec'].get('egressSgRules')

    matched = False
    rule_list = policy.get(direction, [])
    for rule_block in rule_list:
        for rule in rule_block.get(rule_direction, []):
            pod_selector = rule.get('podSelector')
            ns_selector = rule.get('namespaceSelector')
            if (ns_selector and ns_labels
                    and utils.match_selector(ns_selector, ns_labels)):
                if pod_selector:
                    pods = utils.get_pods(pod_selector, ns_name)
                    for pod in pods.get('items'):
                        pod_ip = utils.get_pod_ip(pod)
                        if 'ports' in rule_block:
                            for port in rule_block['ports']:
                                matched = True
                                crd_rules.append(
                                    _create_sg_rule(sg_id,
                                                    direction,
                                                    pod_ip,
                                                    port=port,
                                                    namespace=ns_name))
                        else:
                            matched = True
                            crd_rules.append(
                                _create_sg_rule(sg_id,
                                                direction,
                                                pod_ip,
                                                namespace=ns_name))
                else:
                    if 'ports' in rule_block:
                        for port in rule_block['ports']:
                            matched = True
                            crd_rules.append(
                                _create_sg_rule(sg_id,
                                                direction,
                                                ns_cidr,
                                                port=port,
                                                namespace=ns_name))
                    else:
                        matched = True
                        crd_rules.append(
                            _create_sg_rule(sg_id,
                                            direction,
                                            ns_cidr,
                                            namespace=ns_name))
    return matched, crd_rules
Esempio n. 5
0
def _create_sg_rule_on_text_port(sg_id,
                                 direction,
                                 port,
                                 rule_selected_pods,
                                 crd_rules,
                                 matched,
                                 crd,
                                 allow_all=False,
                                 namespace=None):
    matched_pods = {}

    spec_pod_selector = crd['spec'].get('podSelector')
    policy_namespace = crd['metadata']['namespace']
    spec_pods = driver_utils.get_pods(spec_pod_selector,
                                      policy_namespace).get('items')
    if direction == 'ingress':
        for spec_pod in spec_pods:
            container_ports = driver_utils.get_ports(spec_pod, port)
            for rule_selected_pod in rule_selected_pods:
                matched = _create_sg_rules_with_container_ports(
                    matched_pods, container_ports, allow_all, namespace,
                    matched, crd_rules, sg_id, direction, port,
                    rule_selected_pod)
    elif direction == 'egress':
        for rule_selected_pod in rule_selected_pods:
            pod_label = rule_selected_pod['metadata'].get('labels')
            pod_ns = rule_selected_pod['metadata'].get('namespace')
            # NOTE(maysams) Do not allow egress traffic to the actual
            # set of pods the NP is enforced on.
            if (driver_utils.match_selector(spec_pod_selector, pod_label)
                    and policy_namespace == pod_ns):
                continue
            container_ports = driver_utils.get_ports(rule_selected_pod, port)
            matched = _create_sg_rules_with_container_ports(
                matched_pods, container_ports, allow_all, namespace, matched,
                crd_rules, sg_id, direction, port, rule_selected_pod)
    for container_port, pods in matched_pods.items():
        if allow_all:
            sg_rule = driver_utils.create_security_group_rule_body(
                sg_id,
                direction,
                container_port,
                protocol=port.get('protocol'),
                pods=pods)
        else:
            namespace_obj = driver_utils.get_namespace(namespace)
            namespace_cidr = driver_utils.get_namespace_subnet_cidr(
                namespace_obj)
            sg_rule = driver_utils.create_security_group_rule_body(
                sg_id,
                direction,
                container_port,
                protocol=port.get('protocol'),
                cidr=namespace_cidr,
                pods=pods)
        sgr_id = driver_utils.create_security_group_rule(sg_rule)
        sg_rule['security_group_rule']['id'] = sgr_id
        crd_rules.append(sg_rule)
    return matched
Esempio n. 6
0
    def _create_sg_rule_body_on_text_port(self, sg_id, direction, port,
                                          resources, crd_rules, pod_selector,
                                          policy_namespace, allow_all=False):
        """Create SG rules when named port is used in the NP rule

        In case of ingress, the pods selected by NetworkPolicySpec's
        podSelector have its containers checked for ports with same name as
        the named port. If true, rules are created for the resource matched
        in the NP rule selector with that port. In case of egress, all the pods
        selected by the NetworkPolicyEgressRule's selector have its containers
        checked for containers ports with same name as the ones defined in
        NP rule, and if true the rule is created.

        param sg_id: String with the Security Group ID
        param direction: String with ingress or egress
        param port: dict containing port and protocol
        param resources: list of K8S resources(pod/namespace) or
        a dict with cird
        param crd_rules: list of parsed SG rules
        param pod_selector: dict with NetworkPolicySpec's podSelector
        param policy_namespace: string with policy namespace
        param allow_all: True if should parse a allow from/to all rule,
        False otherwise
        """
        matched_pods = {}
        if direction == "ingress":
            selected_pods = driver_utils.get_pods(
                pod_selector, policy_namespace).get('items')
            for selected_pod in selected_pods:
                container_ports = driver_utils.get_ports(selected_pod, port)
                for resource in resources:
                    self._create_sg_rules_with_container_ports(
                        container_ports, allow_all, resource, matched_pods,
                        crd_rules, sg_id, direction, port)
        elif direction == "egress":
            for resource in resources:
                # NOTE(maysams) Skipping objects that refers to ipblocks
                # and consequently do not contains a spec field
                if not resource.get('spec'):
                    LOG.warning("IPBlock for egress with named ports is "
                                "not supported.")
                    continue
                container_ports = driver_utils.get_ports(resource, port)
                self._create_sg_rules_with_container_ports(
                    container_ports, allow_all, resource, matched_pods,
                    crd_rules, sg_id, direction, port, pod_selector,
                    policy_namespace)
        if allow_all:
            for container_port, pods in matched_pods.items():
                sg_rule = driver_utils.create_security_group_rule_body(
                    sg_id, direction, container_port,
                    protocol=port.get('protocol'),
                    pods=pods)
                crd_rules.append(sg_rule)
            if direction == 'egress':
                rules = self._create_svc_egress_sg_rule(
                    sg_id, policy_namespace, port=container_port,
                    protocol=port.get('protocol'))
                crd_rules.extend(rules)
def _parse_selectors_on_namespace(crd, direction, pod_selector, ns_selector,
                                  rule_block, namespace, matched):
    ns_name = namespace['metadata'].get('name')
    ns_labels = namespace['metadata'].get('labels')

    if (ns_selector and ns_labels
            and driver_utils.match_selector(ns_selector, ns_labels)):
        if pod_selector:
            pods = driver_utils.get_pods(pod_selector, ns_name).get('items')
            if 'ports' in rule_block:
                for port in rule_block['ports']:
                    if type(port.get('port')) is not int:
                        matched = (_create_sg_rule_on_text_port(
                            direction, port, pods, matched, crd))
                    else:
                        for pod in pods:
                            pod_ip = driver_utils.get_pod_ip(pod)
                            if not pod_ip:
                                pod_name = pod['metadata']['name']
                                LOG.debug(
                                    "Skipping SG rule creation for pod "
                                    "%s due to no IP assigned", pod_name)
                                continue
                            matched = True
            else:
                for pod in pods:
                    pod_ip = driver_utils.get_pod_ip(pod)
                    if not pod_ip:
                        pod_name = pod['metadata']['name']
                        LOG.debug(
                            "Skipping SG rule creation for pod %s due"
                            " to no IP assigned", pod_name)
                        continue
                    matched = True
        else:
            ns_pods = driver_utils.get_pods(ns_selector)['items']
            if 'ports' in rule_block:
                for port in rule_block['ports']:
                    if type(port.get('port')) is not int:
                        matched = (_create_sg_rule_on_text_port(
                            direction, port, ns_pods, matched, crd))
                    else:
                        matched = True
            else:
                matched = True
    return matched
    def _create_sg_rule_body_on_text_port(self, direction, port,
                                          resources, crd_rules, pod_selector,
                                          policy_namespace,
                                          allowed_cidrs=None):
        """Create SG rules when named port is used in the NP rule

        In case of ingress, the pods selected by NetworkPolicySpec's
        podSelector have its containers checked for ports with same name as
        the named port. If true, rules are created for the resource matched
        in the NP rule selector with that port. In case of egress, all the pods
        selected by the NetworkPolicyEgressRule's selector have its containers
        checked for containers ports with same name as the ones defined in
        NP rule, and if true the rule is created.

        param sg_id: String with the Security Group ID
        param direction: String with ingress or egress
        param port: dict containing port and protocol
        param resources: list of K8S resources(pod/namespace) or
        a dict with cird
        param crd_rules: list of parsed SG rules
        param pod_selector: dict with NetworkPolicySpec's podSelector
        param policy_namespace: string with policy namespace
        param allowed_cidrs: None, or a list of cidrs, where/from the traffic
                             should be allowed.
        """
        matched_pods = {}
        if direction == "ingress":
            selected_pods = driver_utils.get_pods(
                pod_selector, policy_namespace).get('items')
            for selected_pod in selected_pods:
                container_ports = driver_utils.get_ports(selected_pod, port)
                for resource in resources:
                    self._create_sg_rules_with_container_ports(
                        container_ports, allowed_cidrs, resource, matched_pods,
                        crd_rules, direction, port)
        elif direction == "egress":
            for resource in resources:
                # NOTE(maysams) Skipping objects that refers to ipblocks
                # and consequently do not contains a spec field
                if not resource.get('spec'):
                    LOG.warning("IPBlock for egress with named ports is "
                                "not supported.")
                    continue
                container_ports = driver_utils.get_ports(resource, port)
                self._create_sg_rules_with_container_ports(
                    container_ports, allowed_cidrs, resource, matched_pods,
                    crd_rules, direction, port, pod_selector,
                    policy_namespace)
        if allowed_cidrs:
            for container_port, pods in matched_pods.items():
                for cidr in allowed_cidrs:
                    sg_rule = driver_utils.create_security_group_rule_body(
                        direction, container_port,
                        # Pod's spec.containers[].port.protocol defaults to TCP
                        protocol=port.get('protocol', 'TCP'),
                        cidr=cidr,
                        pods=pods)
                    crd_rules.append(sg_rule)
 def _get_pods_ips(self, pod_selector, namespace=None,
                   namespace_selector=None):
     ips = []
     matching_pods = {"items": []}
     if namespace_selector:
         matching_namespaces = driver_utils.get_namespaces(
             namespace_selector)
         for ns in matching_namespaces.get('items'):
             matching_pods = driver_utils.get_pods(pod_selector,
                                                   ns['metadata']['name'])
     else:
         matching_pods = driver_utils.get_pods(pod_selector, namespace)
     for pod in matching_pods.get('items'):
         if pod['status'].get('podIP'):
             pod_ip = pod['status']['podIP']
             ns = pod['metadata']['namespace']
             ips.append({'cidr': pod_ip, 'namespace': ns})
     return ips
Esempio n. 10
0
 def affected_pods(self, policy, selector=None):
     if selector is not None:
         pod_selector = selector
     else:
         pod_selector = policy['spec'].get('podSelector')
     if pod_selector:
         policy_namespace = policy['metadata']['namespace']
         pods = driver_utils.get_pods(pod_selector, policy_namespace)
         return pods.get('items')
     else:
         # NOTE(ltomasbo): It affects all the pods on the namespace
         return self.namespaced_pods(policy)
Esempio n. 11
0
    def _create_svc_egress_sg_rule(self,
                                   policy_namespace,
                                   sg_rule_body_list,
                                   resource=None,
                                   port=None,
                                   protocol=None):
        services = driver_utils.get_services()
        if not resource:
            svc_subnet = utils.get_subnet_cidr(
                CONF.neutron_defaults.service_subnet)
            rule = driver_utils.create_security_group_rule_body(
                'egress', port, protocol=protocol, cidr=svc_subnet)
            if rule not in sg_rule_body_list:
                sg_rule_body_list.append(rule)
            return

        for service in services.get('items'):
            if self._is_pod(resource):
                pod_labels = resource['metadata'].get('labels')
                svc_selector = service['spec'].get('selector')
                if not svc_selector or not pod_labels:
                    continue
                else:
                    if not driver_utils.match_labels(svc_selector, pod_labels):
                        continue
            elif resource.get('cidr'):
                # NOTE(maysams) Accounts for traffic to pods under
                # a service matching an IPBlock rule.
                svc_namespace = service['metadata']['namespace']
                if svc_namespace != policy_namespace:
                    continue
                svc_selector = service['spec'].get('selector')
                pods = driver_utils.get_pods({
                    'selector': svc_selector
                }, svc_namespace).get('items')
                if not self._pods_in_ip_block(pods, resource):
                    continue
            else:
                ns_name = service['metadata']['namespace']
                if ns_name != resource['metadata']['name']:
                    continue
            cluster_ip = service['spec'].get('clusterIP')
            if not cluster_ip:
                continue
            rule = driver_utils.create_security_group_rule_body(
                'egress', port, protocol=protocol, cidr=cluster_ip)
            if rule not in sg_rule_body_list:
                sg_rule_body_list.append(rule)
    def get_security_groups(self, service, project_id):
        sg_list = []
        svc_namespace = service['metadata']['namespace']
        svc_selector = service['spec'].get('selector')

        # skip is no selector
        if svc_selector:
            # get affected pods by svc selector
            pods = driver_utils.get_pods({'selector': svc_selector},
                                         svc_namespace).get('items')
            # NOTE(ltomasbo): We assume all the pods pointed by a service
            # have the same labels, and the same policy will be applied to
            # all of them. Hence only considering the security groups applied
            # to the first one.
            if pods:
                return _get_pod_sgs(pods[0], project_id)
        return sg_list[:]
def _create_sg_rule_on_text_port(direction, port, rule_selected_pods, matched,
                                 crd):
    spec_pod_selector = crd['spec'].get('podSelector')
    policy_namespace = crd['metadata']['namespace']
    spec_pods = driver_utils.get_pods(spec_pod_selector,
                                      policy_namespace).get('items')
    if direction == 'ingress':
        for spec_pod in spec_pods:
            container_ports = driver_utils.get_ports(spec_pod, port)
            matched = _create_sg_rules_with_container_ports(
                container_ports, matched)
    elif direction == 'egress':
        for rule_selected_pod in rule_selected_pods:
            pod_label = rule_selected_pod['metadata'].get('labels')
            pod_ns = rule_selected_pod['metadata'].get('namespace')
            # NOTE(maysams) Do not allow egress traffic to the actual
            # set of pods the NP is enforced on.
            if (driver_utils.match_selector(spec_pod_selector, pod_label)
                    and policy_namespace == pod_ns):
                continue
            container_ports = driver_utils.get_ports(rule_selected_pod, port)
            matched = _create_sg_rules_with_container_ports(
                container_ports, matched)
    return matched
    def get_security_groups(self, service, project_id):
        sg_list = []
        svc_namespace = service['metadata']['namespace']
        svc_selector = service['spec'].get('selector')

        if svc_selector:
            # get affected pods by svc selector
            pods = driver_utils.get_pods({
                'selector': svc_selector
            }, svc_namespace).get('items')
            # NOTE(ltomasbo): We assume all the pods pointed by a service
            # have the same labels, and the same policy will be applied to
            # all of them. Hence only considering the security groups applied
            # to the first one.
            if pods:
                return _get_pod_sgs(pods[0])
        else:
            # NOTE(maysams): Network Policy is not enforced on Services
            # without selectors.
            sg_list = config.CONF.neutron_defaults.pod_security_groups
            if not sg_list:
                raise cfg.RequiredOptError('pod_security_groups',
                                           cfg.OptGroup('neutron_defaults'))
        return sg_list[:]
def _parse_selectors_on_namespace(crd, direction, pod_selector, ns_selector,
                                  rule_block, crd_rules, namespace, matched):
    ns_name = namespace['metadata'].get('name')
    ns_labels = namespace['metadata'].get('labels')
    sg_id = crd['spec']['securityGroupId']

    if (ns_selector and ns_labels
            and driver_utils.match_selector(ns_selector, ns_labels)):
        if pod_selector:
            pods = driver_utils.get_pods(pod_selector, ns_name).get('items')
            if 'ports' in rule_block:
                for port in rule_block['ports']:
                    if type(port.get('port')) is not int:
                        matched = (_create_sg_rule_on_text_port(
                            sg_id, direction, port, pods, crd_rules, matched,
                            crd))
                    else:
                        matched = True
                        for pod in pods:
                            pod_ip = driver_utils.get_pod_ip(pod)
                            if not pod_ip:
                                pod_name = pod['metadata']['name']
                                LOG.debug(
                                    "Skipping SG rule creation for pod "
                                    "%s due to no IP assigned", pod_name)
                                continue
                            sg_rule = _create_sg_rule(sg_id,
                                                      direction,
                                                      pod_ip,
                                                      port=port,
                                                      namespace=ns_name)
                            if sg_rule not in crd_rules:
                                crd_rules.append(sg_rule)
            else:
                for pod in pods:
                    pod_ip = driver_utils.get_pod_ip(pod)
                    if not pod_ip:
                        pod_name = pod['metadata']['name']
                        LOG.debug(
                            "Skipping SG rule creation for pod %s due"
                            " to no IP assigned", pod_name)
                        continue
                    matched = True
                    sg_rule = _create_sg_rule(sg_id,
                                              direction,
                                              pod_ip,
                                              namespace=ns_name)
                    if sg_rule not in crd_rules:
                        crd_rules.append(sg_rule)
        else:
            ns_pods = driver_utils.get_pods(ns_selector)['items']
            ns_cidr = driver_utils.get_namespace_subnet_cidr(namespace)
            if 'ports' in rule_block:
                for port in rule_block['ports']:
                    if type(port.get('port')) is not int:
                        matched = (_create_sg_rule_on_text_port(
                            sg_id, direction, port, ns_pods, crd_rules,
                            matched, crd))
                    else:
                        matched = True
                        sg_rule = _create_sg_rule(sg_id,
                                                  direction,
                                                  ns_cidr,
                                                  port=port,
                                                  namespace=ns_name)
                        if sg_rule not in crd_rules:
                            crd_rules.append(sg_rule)
            else:
                matched = True
                sg_rule = _create_sg_rule(sg_id,
                                          direction,
                                          ns_cidr,
                                          namespace=ns_name)
                if sg_rule not in crd_rules:
                    crd_rules.append(sg_rule)
    return matched, crd_rules
Esempio n. 16
0
    def _create_svc_egress_sg_rule(self,
                                   policy_namespace,
                                   sg_rule_body_list,
                                   resource=None,
                                   port=None,
                                   protocol=None):
        # FIXME(dulek): We could probably filter by namespace here for pods
        #               and namespace resources?
        services = driver_utils.get_services()
        if not resource:
            svc_subnet = utils.get_subnet_cidr(
                CONF.neutron_defaults.service_subnet)
            rule = driver_utils.create_security_group_rule_body(
                'egress', port, protocol=protocol, cidr=svc_subnet)
            if rule not in sg_rule_body_list:
                sg_rule_body_list.append(rule)
            return

        for service in services.get('items'):
            if service['metadata'].get('deletionTimestamp'):
                # Ignore services being deleted
                continue

            cluster_ip = service['spec'].get('clusterIP')
            if not cluster_ip or cluster_ip == 'None':
                # Headless services has 'None' as clusterIP, ignore.
                continue

            svc_name = service['metadata']['name']
            svc_namespace = service['metadata']['namespace']
            if self._is_pod(resource):
                pod_labels = resource['metadata'].get('labels')
                svc_selector = service['spec'].get('selector')
                if not svc_selector:
                    targets = driver_utils.get_endpoints_targets(
                        svc_name, svc_namespace)
                    pod_ip = resource['status'].get('podIP')
                    if pod_ip and pod_ip not in targets:
                        continue
                elif pod_labels:
                    if not driver_utils.match_labels(svc_selector, pod_labels):
                        continue
            elif resource.get('cidr'):
                # NOTE(maysams) Accounts for traffic to pods under
                # a service matching an IPBlock rule.
                svc_selector = service['spec'].get('selector')
                if not svc_selector:
                    # Retrieving targets of services on any Namespace
                    targets = driver_utils.get_endpoints_targets(
                        svc_name, svc_namespace)
                    if (not targets or
                            not self._targets_in_ip_block(targets, resource)):
                        continue
                else:
                    if svc_namespace != policy_namespace:
                        continue
                    pods = driver_utils.get_pods({
                        'selector': svc_selector
                    }, svc_namespace).get('items')
                    if not self._pods_in_ip_block(pods, resource):
                        continue
            else:
                ns_name = service['metadata']['namespace']
                if ns_name != resource['metadata']['name']:
                    continue
            rule = driver_utils.create_security_group_rule_body(
                'egress', port, protocol=protocol, cidr=cluster_ip)
            if rule not in sg_rule_body_list:
                sg_rule_body_list.append(rule)