Browse Source

Kubernetes: disable inter-pods connections

By default pods in Kubernetes can connect to each other. However in
Qinling, each pod should be independent acting as a worker of a function
or running an execution of a function. Disabling the inter-pods traffic
in the namespace used by Qinling would ensure the isolation of each pod.

This commit leverages the NetworkPolicy in Kubernetes[1] to isolate the
pods. So a network solution which supports NetworkPolicy (for example,
cailco) for Kubernetes must be used or there will be no effect.

[1] https://kubernetes.io/docs/concepts/services-networking/network-policies/

Story: 2001585
Task: 6534
Change-Id: I368323410e92cc23c9a7b50e4936c7070cd57ef7
changes/92/584292/3
Hunt Xu 3 years ago
committed by Lingxian Kong
parent
commit
662794bded
4 changed files with 82 additions and 0 deletions
  1. +3
    -0
      example/kubernetes/k8s_qinling_role.yaml
  2. +26
    -0
      qinling/orchestrator/kubernetes/manager.py
  3. +45
    -0
      qinling/tests/unit/orchestrator/kubernetes/test_manager.py
  4. +8
    -0
      releasenotes/notes/isolate-k8s-pods-617fec5dc5fbd2d8.yaml

+ 3
- 0
example/kubernetes/k8s_qinling_role.yaml View File

@ -58,6 +58,9 @@ rules:
- apiGroups: ["extensions"]
resources: ["replicasets"]
verbs: ["deletecollection"]
- apiGroups: ["extensions"]
resources: ["networkpolicies"]
verbs: ["list", "get", "create", "delete"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1


+ 26
- 0
qinling/orchestrator/kubernetes/manager.py View File

@ -49,6 +49,9 @@ class KubernetesManager(base.OrchestratorBase):
# Create namespace if not exists
self._ensure_namespace()
# Create the network policy if not exists
self._ensure_network_policy()
# Get templates.
template_loader = jinja2.FileSystemLoader(
searchpath=os.path.dirname(TEMPLATES_DIR)
@ -87,6 +90,29 @@ class KubernetesManager(base.OrchestratorBase):
LOG.info('Namespace %s created.', self.conf.kubernetes.namespace)
def _ensure_network_policy(self):
policy_name = 'disable-interpods-connections'
namespace = self.conf.kubernetes.namespace
ret = self.v1extension.list_namespaced_network_policy(namespace)
policies = [i.metadata.name for i in ret.items]
if policy_name not in policies:
LOG.info('Creating network policy %s in namespace %s',
policy_name, namespace)
policy_body = {
'apiVersion': 'extensions/v1beta1',
'kind': 'NetworkPolicy',
'metadata': {'name': policy_name},
'spec': {'pod_selector': {}}
}
self.v1extension.create_namespaced_network_policy(
namespace, policy_body)
LOG.info('Network policy %s in namespace %s created.',
policy_name, namespace)
@tenacity.retry(
wait=tenacity.wait_fixed(2),
stop=tenacity.stop_after_delay(600),


+ 45
- 0
qinling/tests/unit/orchestrator/kubernetes/test_manager.py View File

@ -60,6 +60,14 @@ class TestKubernetesManager(base.DbTestCase):
namespaces.items = [namespace]
self.k8s_v1_api.list_namespace.return_value = namespaces
network_policy = mock.Mock()
network_policy.metadata.name = 'disable-interpods-connections'
network_policies = mock.Mock()
network_policies.items = [network_policy]
self.k8s_v1_ext.list_namespaced_network_policy.return_value = (
network_policies
)
self.manager = k8s_manager.KubernetesManager(self.conf,
self.qinling_endpoint)
@ -131,6 +139,43 @@ class TestKubernetesManager(base.DbTestCase):
self.assertEqual(2, self.k8s_v1_api.list_namespace.call_count)
self.k8s_v1_api.create_namespace.assert_not_called()
def test__ensure_network_policy(self):
# self.manager is not used in this test.
network_policies = mock.Mock()
network_policies.items = []
v1ext = self.k8s_v1_ext
v1ext.list_namespaced_network_policy.return_value = network_policies
k8s_manager.KubernetesManager(self.conf, self.qinling_endpoint)
network_policy_body = {
'apiVersion': 'extensions/v1beta1',
'kind': 'NetworkPolicy',
'metadata': {'name': 'disable-interpods-connections'},
'spec': {'pod_selector': {}}
}
v1ext.list_namespaced_network_policy.assert_called_with(
self.fake_namespace
)
v1ext.create_namespaced_network_policy.assert_called_once_with(
self.fake_namespace, network_policy_body)
def test__ensure_network_policy_not_create(self):
# self.manager is not used in this test.
item = mock.Mock()
item.metadata.name = 'disable-interpods-connections'
network_policies = mock.Mock()
network_policies.items = [item]
v1ext = self.k8s_v1_ext
v1ext.list_namespaced_network_policy.return_value = network_policies
k8s_manager.KubernetesManager(self.conf, self.qinling_endpoint)
v1ext.list_namespaced_network_policy.assert_called_with(
self.fake_namespace
)
v1ext.create_namespaced_network_policy.assert_not_called()
def test_create_pool(self):
ret = mock.Mock()
ret.status.replicas = 5


+ 8
- 0
releasenotes/notes/isolate-k8s-pods-617fec5dc5fbd2d8.yaml View File

@ -0,0 +1,8 @@
---
security:
- |
When using Kubernetes as the orchestrator, Qinling will create Kubernetes
pods to run executions of functions. In Kubernetes, pods are non-isolated
unless the NetworkPolicy is configured and enforced. In Qinling, we create
NetworkPolicy to disable the communication between pods and the traffic
from outside the cluster.

Loading…
Cancel
Save