Implement NP SG create/delete actions

This commit implements NP driver actions for creating/updating SG and SG
rules. It also creates KuryrNetPolicy as a CRD so we don't have to rely
on the slow neutron API for time-costly operations such as listing SG
and so.

Security group rules and label matching will be handled in a follow-up
patch, as well as storing CRD object_id in a network policy annotation.

Unit tests will also be added after some more functionality is added
with the remaining patch series.

Partially-Implements: bp/k8s-network-policies
Change-Id: I6d45a462e812b24073b529144fc0843e8725a06e
This commit is contained in:
Daniel Mellado 2018-07-11 07:21:37 -04:00
parent 95953a6f67
commit 4465c2062a
7 changed files with 222 additions and 2 deletions

View File

@ -902,6 +902,7 @@ if [[ "$1" == "stack" && "$2" == "extra" ]]; then
KURYR_K8S_CONTAINERIZED_DEPLOYMENT=$(trueorfalse False KURYR_K8S_CONTAINERIZED_DEPLOYMENT)
if is_service_enabled kuryr-kubernetes; then
/usr/local/bin/kubectl apply -f ${KURYR_HOME}/kubernetes_crds/kuryrnet.yaml
/usr/local/bin/kubectl apply -f ${KURYR_HOME}/kubernetes_crds/kuryrnetpolicy.yaml
if [ "$KURYR_K8S_CONTAINERIZED_DEPLOYMENT" == "True" ]; then
if is_service_enabled kuryr-daemon; then
build_kuryr_containers $CNI_BIN_DIR $CNI_CONF_DIR True

View File

@ -37,6 +37,7 @@ This section describes how you can install and configure kuryr-kubernetes
default_configuration
trunk_ports
network_namespace
network_policy
testing_connectivity
testing_nested_connectivity
containerized

View File

@ -0,0 +1,98 @@
Enable network policy support functionality
===========================================
Please follow the next steps in order to enable the network policy support
feature:
1. Enable the policy handler to response to network policy events. As this is
not enabled by default you'd have to explicitly add that to the list of
enabled handlers at kuryr.conf (further info on how to do this can be found
at :doc:`./devstack/containerized`)::
[kubernetes]
enabled_handlers=vif,lb,lbaasspec,policy
Note that you need to restart the kuryr controller after applying the above
detailed steps. For devstack non-containerized deployments::
$ sudo systemctl restart devstack@kuryr-kubernetes.service
Same for containerized deployments::
$ kubectl -n kube-system get pod | grep kuryr-controller
$ kubectl -n kube-system delete pod KURYR_CONTROLLER_POD_NAME
For directly enabling the driver when deploying with devstack, you just need
to add the policy handler with::
KURYR_ENABLED_HANDLERS=vif,lb,lbaasspec,policy
Testing the network policy support functionality
------------------------------------------------
1. Given a yaml file with a network policy, such as::
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
2. Apply the network policy::
$ kubectl apply -f network_policy.yml
3. Check that the resources has been created::
$ kubectl get kuryrnetpolicies
NAME AGE
np-test-network-policy 2s
$ kubectl get networkpolicies
NAME POD-SELECTOR AGE
test-network-policy role=db 2s
$ openstack security group list | grep test-network-policy
| dabdf308-7eed-43ef-a058-af84d1954acb | test-network-policy
4. Check that the teardown of the resources once the network policy is removed::
$ kubectl delete -f network_policy.yml
$ kubectl get kuryrnetpolicies
$ kubectl get networkpolicies
$ openstack security group list | grep test-network-policy

View File

@ -0,0 +1,14 @@
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: kuryrnetpolicies.openstack.org
spec:
group: openstack.org
version: v1
scope: Namespaced
names:
plural: kuryrnetpolicies
singular: kuryrnetpolicy
kind: KuryrNetPolicy
shortNames:
- knp

View File

@ -16,6 +16,7 @@
K8S_API_BASE = '/api/v1'
K8S_API_NAMESPACES = K8S_API_BASE + '/namespaces'
K8S_API_CRD = '/apis/openstack.org/v1'
K8S_API_CRD_NAMESPACES = K8S_API_CRD + '/namespaces'
K8S_API_POLICIES = '/apis/networking.k8s.io/v1/networkpolicies'
K8S_API_NPWG_CRD = '/apis/k8s.cni.cncf.io/v1'
@ -27,6 +28,7 @@ K8S_OBJ_ENDPOINTS = 'Endpoints'
K8S_OBJ_POLICY = 'NetworkPolicy'
K8S_OBJ_KURYRNET = 'KuryrNet'
K8S_OBJ_KURYRNETPOLICY = 'KuryrNetPolicy'
K8S_POD_STATUS_PENDING = 'Pending'
@ -35,6 +37,7 @@ K8S_ANNOTATION_VIF = K8S_ANNOTATION_PREFIX + '-vif'
K8S_ANNOTATION_LBAAS_SPEC = K8S_ANNOTATION_PREFIX + '-lbaas-spec'
K8S_ANNOTATION_LBAAS_STATE = K8S_ANNOTATION_PREFIX + '-lbaas-state'
K8S_ANNOTATION_NET_CRD = K8S_ANNOTATION_PREFIX + '-net-crd'
K8S_ANNOTATION_NETPOLICY_CRD = K8S_ANNOTATION_PREFIX + '-netpolicy-crd'
K8S_ANNOTATION_LBAAS_RT_STATE = K8S_ANNOTATION_PREFIX + '-lbaas-route-state'
K8S_ANNOTATION_LBAAS_RT_NOTIF = K8S_ANNOTATION_PREFIX + '-lbaas-route-notif'
K8S_ANNOTATION_ROUTE_STATE = K8S_ANNOTATION_PREFIX + '-route-state'

View File

@ -15,7 +15,12 @@
from oslo_log import log as logging
from neutronclient.common import exceptions as n_exc
from kuryr_kubernetes import clients
from kuryr_kubernetes import constants
from kuryr_kubernetes.controller.drivers import base
from kuryr_kubernetes import exceptions
LOG = logging.getLogger(__name__)
@ -24,7 +29,103 @@ class NetworkPolicyDriver(base.NetworkPolicyDriver):
"""Provides security groups actions based on K8s Network Policies"""
def ensure_network_policy(self, policy, project_id):
pass
neutron = clients.get_neutron_client()
LOG.debug("Creating network policy %s" % policy['metadata']['name'])
if self._get_kuryrnetpolicy_crd(policy):
LOG.debug("Already existing CRD")
return
security_group_body = {
"security_group":
{
"name": policy['metadata']['name'],
"project_id": project_id
}
}
try:
sg = neutron.create_security_group(body=security_group_body)
except n_exc.NeutronClientException:
LOG.exception("Error creating security group for network policy. ")
raise
try:
self._add_kuryrnetpolicy_crd(policy, project_id,
sg['security_group']['id'])
except exceptions.K8sClientException:
LOG.exception("Rolling back security groups")
neutron.delete_security_group(sg['security_group']['id'])
raise
def release_network_policy(self, policy, project_id):
pass
neutron = clients.get_neutron_client()
netpolicy_crd = self._get_kuryrnetpolicy_crd(policy)
if netpolicy_crd is not None:
try:
sg_id = netpolicy_crd['spec']['securityGroupId']
neutron.delete_security_group(sg_id)
except n_exc.NotFound:
LOG.debug("Security Group not found: %s", sg_id)
except n_exc.NeutronClientException:
LOG.exception("Error deleting security group %s.", sg_id)
raise
self._del_kuryrnetpolicy_crd(
netpolicy_crd['metadata']['name'],
netpolicy_crd['metadata']['namespace'])
def _get_kuryrnetpolicy_crd(self, policy):
kubernetes = clients.get_kubernetes_client()
netpolicy_crd_name = "np-" + policy['metadata']['name']
netpolicy_crd_namespace = policy['metadata']['namespace']
try:
netpolicy_crd = kubernetes.get('{}/{}/kuryrnetpolicies/{}'.format(
constants.K8S_API_CRD_NAMESPACES, netpolicy_crd_namespace,
netpolicy_crd_name))
except exceptions.K8sResourceNotFound:
return None
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception.")
raise
return netpolicy_crd
def _add_kuryrnetpolicy_crd(self, policy, project_id, sg_id):
kubernetes = clients.get_kubernetes_client()
netpolicy_crd_name = "np-" + policy['metadata']['name']
netpolicy_crd_namespace = policy['metadata']['namespace']
netpolicy_crd = {
'apiVersion': 'openstack.org/v1',
'kind': constants.K8S_OBJ_KURYRNETPOLICY,
'metadata': {
'name': netpolicy_crd_name,
'namespace': netpolicy_crd_namespace,
'annotations': {
'policy': policy
}
},
'spec': {
'securityGroupName': policy['metadata']['name'],
'securityGroupId': sg_id,
},
}
try:
LOG.debug("Creating KuryrNetPolicy CRD %s" % netpolicy_crd)
kubernetes_post = '{}/{}/kuryrnetpolicies'.format(
constants.K8S_API_CRD_NAMESPACES,
netpolicy_crd_namespace)
kubernetes.post(kubernetes_post, netpolicy_crd)
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception creating kuryrnetpolicy"
" CRD. %s" % exceptions.K8sClientException)
raise
return netpolicy_crd
def _del_kuryrnetpolicy_crd(self, netpolicy_crd_name,
netpolicy_crd_namespace):
kubernetes = clients.get_kubernetes_client()
try:
LOG.debug("Deleting KuryrNetPolicy CRD %s" % netpolicy_crd_name)
kubernetes.delete('{}/{}/kuryrnetpolicies/{}'.format(
constants.K8S_API_CRD_NAMESPACES,
netpolicy_crd_namespace,
netpolicy_crd_name))
except exceptions.K8sClientException:
LOG.exception("Kubernetes Client Exception deleting kuryrnetpolicy"
" CRD.")
raise

View File

@ -76,6 +76,8 @@ class K8sClient(object):
response = requests.get(url, cert=self.cert,
verify=self.verify_server,
headers=header)
if response.status_code == requests.codes.not_found:
raise exc.K8sResourceNotFound(response.text)
if not response.ok:
raise exc.K8sClientException(response.text)
result = response.json() if json else response.text