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_pod_sgs(pod, project_id): sg_list = [] pod_labels = pod['metadata'].get('labels') pod_namespace = pod['metadata']['namespace'] knp_crds = driver_utils.get_kuryrnetpolicy_crds(namespace=pod_namespace) for crd in knp_crds.get('items'): pod_selector = crd['spec'].get('podSelector') if pod_selector: if driver_utils.match_selector(pod_selector, pod_labels): LOG.debug("Appending %s", str(crd['spec']['securityGroupId'])) sg_list.append(str(crd['spec']['securityGroupId'])) else: LOG.debug("Appending %s", str(crd['spec']['securityGroupId'])) sg_list.append(str(crd['spec']['securityGroupId'])) # NOTE(maysams) Pods that are not selected by any Networkpolicy # are fully accessible. Thus, the default security group is associated. if not sg_list: 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 _create_sg_rules_with_container_ports( self, container_ports, allow_all, resource, matched_pods, crd_rules, direction, port, pod_selector=None, policy_namespace=None): cidr, ns = self._get_resource_details(resource) for pod, container_port in container_ports: pod_label = pod['metadata'].get('labels') pod_ip = pod['status'].get('podIP') pod_namespace = pod['metadata']['namespace'] pod_info = {pod_ip: pod_namespace} # NOTE(maysams) Avoid to take into account pods that are also # matched by NetworkPolicySpec's podSelector. This way we do # not allow egress traffic to the actual set of pods the NP # is enforced on. if (direction == 'egress' and (driver_utils.match_selector(pod_selector, pod_label) and policy_namespace == pod_namespace)): continue if container_port in matched_pods: matched_pods[container_port].update(pod_info) else: matched_pods[container_port] = pod_info if not allow_all and matched_pods and cidr: for container_port, pods in matched_pods.items(): sg_rule = driver_utils.create_security_group_rule_body( direction, container_port, protocol=port.get('protocol'), cidr=cidr, pods=pods) if sg_rule not in crd_rules: crd_rules.append(sg_rule) if direction == 'egress': self._create_svc_egress_sg_rule( policy_namespace, crd_rules, resource=resource, port=container_port, protocol=port.get('protocol'))
def _create_sg_rules(crd, pod, pod_selector, rule_block, direction, matched): pod_labels = pod['metadata'].get('labels') pod_ip = driver_utils.get_pod_ip(pod) if not pod_ip: LOG.debug( "Skipping SG rule creation for pod %s due to " "no IP assigned", pod['metadata']['name']) return None # NOTE (maysams) No need to differentiate between podSelector # with empty value or with '{}', as they have same result in here. if pod_selector: if driver_utils.match_selector(pod_selector, pod_labels): 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, [pod], matched, crd) else: matched = True else: matched = True else: # NOTE (maysams) When a policy with namespaceSelector and text port # is applied the port on the pods needs to be retrieved. 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, [pod], matched, crd) return matched
def _get_pod_sgs(pod): sg_list = [] pod_labels = pod['metadata'].get('labels') pod_namespace = pod['metadata']['namespace'] knp_crds = driver_utils.get_kuryrnetworkpolicy_crds( namespace=pod_namespace) for crd in knp_crds: pod_selector = crd['spec'].get('podSelector') if driver_utils.match_selector(pod_selector, pod_labels): sg_id = crd['status'].get('securityGroupId') if not sg_id: # NOTE(dulek): We could just assume KNP handler will apply it, # but it's possible that when it gets this pod it # will have no IP yet and will be skipped. LOG.warning('SG for NP %s not created yet, will retry.', utils.get_res_unique_name(crd)) raise exceptions.ResourceNotReady(pod) LOG.debug("Appending %s", crd['status']['securityGroupId']) sg_list.append(crd['status']['securityGroupId']) # NOTE(maysams) Pods that are not selected by any Networkpolicy # are fully accessible. Thus, the default security group is associated. if not sg_list: 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_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
def _create_sg_rules(crd, pod, pod_selector, rule_block, crd_rules, direction, matched, namespace=None): pod_labels = pod['metadata'].get('labels') # NOTE (maysams) No need to differentiate between podSelector # with empty value or with '{}', as they have same result in here. if (pod_selector and driver_utils.match_selector(pod_selector, pod_labels)): matched = True pod_ip = driver_utils.get_pod_ip(pod) sg_id = crd['spec']['securityGroupId'] if 'ports' in rule_block: for port in rule_block['ports']: sg_rule = _create_sg_rule(sg_id, direction, cidr=pod_ip, port=port, namespace=namespace) crd_rules.append(sg_rule) else: sg_rule = _create_sg_rule(sg_id, direction, cidr=pod_ip, namespace=namespace) crd_rules.append(sg_rule) return matched
def _create_sg_rules(crd, pod, pod_selector, rule_block, crd_rules, direction, matched, namespace=None, allow_all=False): pod_labels = pod['metadata'].get('labels') pod_ip = driver_utils.get_pod_ip(pod) if not pod_ip: LOG.debug( "Skipping SG rule creation for pod %s due to " "no IP assigned", pod['metadata']['name']) return None # NOTE (maysams) No need to differentiate between podSelector # with empty value or with '{}', as they have same result in here. if pod_selector: if driver_utils.match_selector(pod_selector, pod_labels): sg_id = crd['spec']['securityGroupId'] 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, [pod], crd_rules, matched, crd) else: matched = True sg_rule = _create_sg_rule(sg_id, direction, cidr=pod_ip, port=port, namespace=namespace) crd_rules.append(sg_rule) else: matched = True sg_rule = _create_sg_rule(sg_id, direction, cidr=pod_ip, namespace=namespace) crd_rules.append(sg_rule) else: # NOTE (maysams) When a policy with namespaceSelector and text port # is applied the port on the pods needs to be retrieved. sg_id = crd['spec']['securityGroupId'] 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, [pod], crd_rules, matched, crd, allow_all=allow_all, namespace=namespace)) return matched
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
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 _parse_selectors_on_pod(crd, pod, pod_selector, namespace_selector, rule_block, direction, matched): pod_namespace = pod['metadata']['namespace'] pod_namespace_labels = _get_namespace_labels(pod_namespace) policy_namespace = crd['metadata']['namespace'] if namespace_selector == {}: matched = _create_sg_rules(crd, pod, pod_selector, rule_block, direction, matched) elif namespace_selector: if (pod_namespace_labels and driver_utils.match_selector( namespace_selector, pod_namespace_labels)): matched = _create_sg_rules(crd, pod, pod_selector, rule_block, direction, matched) else: if pod_namespace == policy_namespace: matched = _create_sg_rules(crd, pod, pod_selector, rule_block, direction, matched) return matched
def _parse_rules(direction, crd, pod): policy = crd['spec']['networkpolicy_spec'] pod_namespace = pod['metadata']['namespace'] pod_namespace_labels = _get_namespace_labels(pod_namespace) policy_namespace = crd['metadata']['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, []): namespace_selector = rule.get('namespaceSelector') pod_selector = rule.get('podSelector') if namespace_selector == {}: if _create_sg_rules(crd, pod, pod_selector, rule_block, crd_rules, direction, matched): matched = True elif namespace_selector: if (pod_namespace_labels and driver_utils.match_selector( namespace_selector, pod_namespace_labels)): if _create_sg_rules(crd, pod, pod_selector, rule_block, crd_rules, direction, matched, pod_namespace): matched = True else: if pod_namespace == policy_namespace: if _create_sg_rules(crd, pod, pod_selector, rule_block, crd_rules, direction, matched, pod_namespace): matched = True return matched, crd_rules
def test_match_selector(self): self.assertFalse( utils.match_selector({'matchLabels': { 'app': 'demo' }}, None)) self.assertFalse( utils.match_selector({'matchLabels': { 'app': 'demo' }}, {})) self.assertFalse( utils.match_selector({'matchLabels': { 'app': 'demo' }}, {'app': 'foobar'})) self.assertTrue( utils.match_selector({'matchLabels': { 'app': 'demo' }}, {'app': 'demo'})) self.assertTrue( utils.match_selector({'matchLabels': { 'app': 'demo' }}, { 'app': 'demo', 'foo': 'bar' })) self.assertTrue( utils.match_selector( {'matchLabels': { 'app': 'demo', 'foo': 'bar' }}, { 'app': 'demo', 'foo': 'bar' })) self.assertFalse( utils.match_selector( {'matchLabels': { 'app': 'demo', 'foo': 'bar' }}, {'app': 'demo'}))
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 _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