Ensure egress NP works with Service without selectors
This commit ensures egress Network policy can also work with services without selectors. Change-Id: I26e1dce0b6e363f027ee6d4dfea99053ffe80bbe
This commit is contained in:
parent
4ce01a7908
commit
525dc1521d
@ -296,7 +296,7 @@ restriction was enforced.
|
||||
Allow traffic from namespace
|
||||
++++++++++++++++++++++++++++
|
||||
|
||||
The following network policy only allows allowing ingress traffic
|
||||
The following network policy only allows ingress traffic
|
||||
from namespace with the label ``purpose=test``:
|
||||
|
||||
.. code-block:: yaml
|
||||
@ -363,9 +363,94 @@ egress rule allowing traffic to everywhere.
|
||||
|
||||
.. note::
|
||||
|
||||
The Service security groups need to be rechecked when a network policy
|
||||
that affects ingress traffic is created, and also everytime
|
||||
a pod or namespace is created.
|
||||
Only when using Amphora Octavia provider and Services with selector,
|
||||
the Load Balancer security groups need to be rechecked when a
|
||||
network policy that affects ingress traffic is created, and
|
||||
also everytime a pod or namespace is created. Network Policy
|
||||
is not enforced on Services without Selectors.
|
||||
|
||||
Allow traffic to a Pod in a Namespace
|
||||
+++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The following network policy only allows egress traffic from Pods
|
||||
with the label ``app=demo`` at Namespace with label ``app=demo``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: block-egress
|
||||
namespace: client
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: client
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
app: demo
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: demo
|
||||
|
||||
The resulting CRD has an ingress rules allowing traffic
|
||||
from everywhere and egress rules to the selected Pod
|
||||
and the Service that points to it.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
apiVersion: openstack.org/v1
|
||||
kind: KuryrNetworkPolicy
|
||||
metadata: ...
|
||||
spec:
|
||||
egressSgRules:
|
||||
- namespace: demo
|
||||
sgRule:
|
||||
description: Kuryr-Kubernetes NetPolicy SG rule
|
||||
direction: egress
|
||||
ethertype: IPv4
|
||||
port_range_max: 65535
|
||||
port_range_min: 1
|
||||
protocol: tcp
|
||||
remote_ip_prefix: 10.0.2.120
|
||||
- sgRule:
|
||||
description: Kuryr-Kubernetes NetPolicy SG rule
|
||||
direction: egress
|
||||
ethertype: IPv4
|
||||
port_range_max: 65535
|
||||
port_range_min: 1
|
||||
protocol: tcp
|
||||
remote_ip_prefix: 10.0.0.144
|
||||
ingressSgRules:
|
||||
- sgRule:
|
||||
description: Kuryr-Kubernetes NetPolicy SG rule
|
||||
direction: ingress
|
||||
ethertype: IPv4
|
||||
- sgRule:
|
||||
description: Kuryr-Kubernetes NetPolicy SG rule
|
||||
direction: ingress
|
||||
ethertype: IPv6
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: client
|
||||
policyTypes:
|
||||
- Egress
|
||||
status:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: client
|
||||
securityGroupId: 322a347b-0684-4aea-945a-5f204361a64e
|
||||
securityGroupRules: ...
|
||||
|
||||
.. note::
|
||||
|
||||
A Network Policy egress rule creates a Security Group rule
|
||||
corresponding to a Service(with or without selectors) that
|
||||
points to the selected Pod.
|
||||
|
||||
|
||||
Create network policy flow
|
||||
|
@ -542,26 +542,39 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
|
||||
return
|
||||
|
||||
for service in services.get('items'):
|
||||
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 or not pod_labels:
|
||||
continue
|
||||
else:
|
||||
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_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
|
||||
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']:
|
||||
@ -583,6 +596,13 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _targets_in_ip_block(self, targets, resource):
|
||||
for target in targets:
|
||||
if (ipaddress.ip_address(target)
|
||||
not in ipaddress.ip_network(resource.get('cidr'))):
|
||||
return False
|
||||
return True
|
||||
|
||||
def parse_network_policy_rules(self, policy):
|
||||
"""Create security group rule bodies out of network policies.
|
||||
|
||||
|
@ -433,7 +433,6 @@ class NetworkPolicyServiceSecurityGroupsDriver(
|
||||
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},
|
||||
@ -444,4 +443,11 @@ class NetworkPolicyServiceSecurityGroupsDriver(
|
||||
# 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[:]
|
||||
|
@ -586,3 +586,24 @@ def get_port_annot_pci_info(nodename, neutron_port):
|
||||
LOG.exception('Exception when reading annotations '
|
||||
'%s and converting from json', annot_name)
|
||||
return pci_info
|
||||
|
||||
|
||||
def get_endpoints_targets(name, namespace):
|
||||
kubernetes = clients.get_kubernetes_client()
|
||||
target_ips = []
|
||||
try:
|
||||
klb_crd = kubernetes.get(
|
||||
f'{constants.K8S_API_CRD_NAMESPACES}/{namespace}/'
|
||||
f'kuryrloadbalancers/{name}')
|
||||
except k_exc.K8sResourceNotFound:
|
||||
LOG.debug("KuryrLoadBalancer %s not found on Namespace %s.",
|
||||
name, namespace)
|
||||
return target_ips
|
||||
except k_exc.K8sClientException:
|
||||
LOG.exception('Exception when getting K8s Endpoints.')
|
||||
raise
|
||||
|
||||
for ep_slice in klb_crd['spec'].get('endpointSlices', []):
|
||||
for endpoint in ep_slice.get('endpoints', []):
|
||||
target_ips.extend(endpoint.get('addresses', []))
|
||||
return target_ips
|
||||
|
@ -217,8 +217,8 @@ class KuryrNetworkPolicyHandler(k8s_base.ResourceEventHandler):
|
||||
for service in services.get('items', []):
|
||||
# TODO(ltomasbo): Skip other services that are not affected
|
||||
# by the policy
|
||||
# FIXME(dulek): Make sure to include svcs without selector when
|
||||
# we start supporting them.
|
||||
# NOTE(maysams): Network Policy is not enforced on Services
|
||||
# without selectors for Amphora Octavia provider.
|
||||
if (not service['spec'].get('selector') or not
|
||||
self._is_service_affected(service, pods_to_update)):
|
||||
continue
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
fixes:
|
||||
- |
|
||||
Kuryr can now handle egress Network Policy that allows
|
||||
traffic to Pods being Pointed by a Service without Selector.
|
||||
Also, ingress Network Policy is not enforced on Services
|
||||
without Selectors when the Octavia provider is Amphora.
|
Loading…
x
Reference in New Issue
Block a user