66fb9d18df
This patch ensures pods from namespace X cannot access services pointing to pods on namespace Y, and vice versa. The exceptions are: - Pods on default namespace can access all the services - Services on default namespace can be accessed by all the pods Depends-On: I37025bf65b67fe04f2a6d9b14bbe1b7bc387e370 Implements: blueprint openshift-project-isolation-support Change-Id: I7b78e12cdf2bce5d0780e582814ef51ef0c459a7
157 lines
5.6 KiB
Python
157 lines
5.6 KiB
Python
# Copyright (c) 2018 Red Hat, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from kuryr.lib._i18n import _
|
|
from oslo_config import cfg
|
|
from oslo_log import log as logging
|
|
|
|
from kuryr_kubernetes import clients
|
|
from kuryr_kubernetes import config
|
|
from kuryr_kubernetes import constants
|
|
from kuryr_kubernetes.controller.drivers import base
|
|
from kuryr_kubernetes import exceptions
|
|
|
|
from neutronclient.common import exceptions as n_exc
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
namespace_sg_driver_opts = [
|
|
cfg.StrOpt('sg_allow_from_namespaces',
|
|
help=_("Default security group to allow traffic from the "
|
|
"namespaces into the default namespace.")),
|
|
cfg.StrOpt('sg_allow_from_default',
|
|
help=_("Default security group to allow traffic from the "
|
|
"default namespaces into the other namespaces."))
|
|
]
|
|
|
|
cfg.CONF.register_opts(namespace_sg_driver_opts, "namespace_sg")
|
|
|
|
DEFAULT_NAMESPACE = 'default'
|
|
|
|
|
|
def _get_net_crd(namespace):
|
|
kubernetes = clients.get_kubernetes_client()
|
|
|
|
try:
|
|
ns = kubernetes.get('%s/namespaces/%s' % (constants.K8S_API_BASE,
|
|
namespace))
|
|
except exceptions.K8sClientException:
|
|
LOG.exception("Kubernetes Client Exception.")
|
|
raise exceptions.ResourceNotReady(namespace)
|
|
try:
|
|
annotations = ns['metadata']['annotations']
|
|
net_crd_name = annotations[constants.K8S_ANNOTATION_NET_CRD]
|
|
except KeyError:
|
|
LOG.exception("Namespace missing CRD annotations for selecting "
|
|
"the corresponding security group.")
|
|
raise exceptions.ResourceNotReady(namespace)
|
|
try:
|
|
net_crd = kubernetes.get('%s/kuryrnets/%s' % (constants.K8S_API_CRD,
|
|
net_crd_name))
|
|
except exceptions.K8sClientException:
|
|
LOG.exception("Kubernetes Client Exception.")
|
|
raise
|
|
|
|
return net_crd
|
|
|
|
|
|
class NamespacePodSecurityGroupsDriver(base.PodSecurityGroupsDriver):
|
|
"""Provides security groups for Pod based on a configuration option."""
|
|
|
|
def get_security_groups(self, pod, project_id):
|
|
namespace = pod['metadata']['namespace']
|
|
net_crd = _get_net_crd(namespace)
|
|
|
|
sg_list = [str(net_crd['spec']['sgId'])]
|
|
|
|
extra_sgs = self._get_extra_sg(namespace)
|
|
for sg in extra_sgs:
|
|
sg_list.append(str(sg))
|
|
|
|
sg_list.extend(config.CONF.neutron_defaults.pod_security_groups)
|
|
|
|
return sg_list[:]
|
|
|
|
def _get_extra_sg(self, namespace):
|
|
# Differentiates between default namespace and the rest
|
|
if namespace == DEFAULT_NAMESPACE:
|
|
return [cfg.CONF.namespace_sg.sg_allow_from_namespaces]
|
|
else:
|
|
return [cfg.CONF.namespace_sg.sg_allow_from_default]
|
|
|
|
def create_namespace_sg(self, namespace, project_id, crd_spec):
|
|
neutron = clients.get_neutron_client()
|
|
|
|
sg_name = "ns/" + namespace + "-sg"
|
|
# create the associated SG for the namespace
|
|
try:
|
|
# default namespace is different from the rest
|
|
# Default allows traffic from everywhere
|
|
# The rest can be accessed from the default one
|
|
sg = neutron.create_security_group(
|
|
{
|
|
"security_group": {
|
|
"name": sg_name,
|
|
"project_id": project_id
|
|
}
|
|
}).get('security_group')
|
|
neutron.create_security_group_rule(
|
|
{
|
|
"security_group_rule": {
|
|
"direction": "ingress",
|
|
"remote_ip_prefix": crd_spec['subnetCIDR'],
|
|
"security_group_id": sg['id']
|
|
}
|
|
})
|
|
except n_exc.NeutronClientException as ex:
|
|
LOG.error("Error creating security group for the namespace "
|
|
"%s: %s", namespace, ex)
|
|
raise ex
|
|
return {'sgId': sg['id']}
|
|
|
|
def delete_sg(self, sg_id):
|
|
neutron = clients.get_neutron_client()
|
|
try:
|
|
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
|
|
|
|
|
|
class NamespaceServiceSecurityGroupsDriver(base.ServiceSecurityGroupsDriver):
|
|
"""Provides security groups for Service based on a configuration option."""
|
|
|
|
def get_security_groups(self, service, project_id):
|
|
namespace = service['metadata']['namespace']
|
|
net_crd = _get_net_crd(namespace)
|
|
|
|
sg_list = []
|
|
sg_list.append(str(net_crd['spec']['sgId']))
|
|
|
|
extra_sgs = self._get_extra_sg(namespace)
|
|
for sg in extra_sgs:
|
|
sg_list.append(str(sg))
|
|
|
|
return sg_list[:]
|
|
|
|
def _get_extra_sg(self, namespace):
|
|
# Differentiates between default namespace and the rest
|
|
if namespace == DEFAULT_NAMESPACE:
|
|
return [cfg.CONF.namespace_sg.sg_allow_from_default]
|
|
else:
|
|
return [cfg.CONF.namespace_sg.sg_allow_from_namespaces]
|