RBAC 操作与实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bc_vnetwork/article/details/52680917

1 RBAC简介

RBAC(Role-Based Access Control)策略框架使得操作者允许一个或多个项目(租户)访问自己的资源。通过创建rbac_policy,指定action{access_as_share,access_as_external}、target_tenant_id、object_type{network, qos_policy}等参数来完成。

    RBAC可指定网络、qos_policy两种资源类型对其他租户共享。若创建的网络或者qos_policy 是shared,则表示已创建rbac_policy,其target_tenant=*。

使用RBAC,其他项目能够在可访问的网络上创建端口(L版已支持);向可访问的网络或端口绑定QoS策略(M版支持);向网络绑定router gateway(M版支持)。

默认policy.json文件允许普通租户与其他指定的project共享objects。若阻止这种行为,可将create_rbac_policy调整为rule:admin_only.

 

2 RBAC操作命令

2.1网络共享

1.     指定demo项目来访问admin创建的网络net1,在demo项目下指定net1创建端口。

Admin租户下创建网络net1:


创建policy entry,使得demo用户能够访问网络net1.


进入demo用户,执行net-list,并在net1上创建端口


阻止demo用户访问admin下的网络net1.只需删除RBAC policy。注:demo租户下创建的端口必须先删除,才可删除demo访问权限。


2.2 qos_policy 共享

Demo项目可访问admin租户下的QoS policy

Admin 租户下创建 QoS policy qos1


创建rbac策略


在demo租户下执行qos-policy-list,qos-policy-show命令能够看到admin创建的qos policy. Demo租户可使用该qos policy绑定自身的端口或网络,其他租户不能看到和使用。

取消demo租户使用secret-policy,需执行rbac-delete命令。如果demo租户将secret-policy与端口进行绑定操作,需要先取消绑定,才能执行rbac-delete操作。


2.3设置外部网络

Admin 租户下创建非外部网络,demo租户有权访问该网络并设置成外部网络。

Admin租户下创建网络net11-ext:


创建RBAC 策略:


Demo租户下,执行net-show net11-ext


Demo 租户下创建路由r11,并选择net11-ext作为外部网关:


Admin租户下,删除rbac策略,需demo租户删除router gateway Port,才可删除。

3 RBAC代码实现

3.1 RBAC 数据模型

neutron.db.rbac_db_models.py

###该文件指出RBAC表中的内容。

class RBACColumns(model_base.HasId,model_base.HasTenant):

###该类对应着RBAC表。描述了RBAC表包含target_tenant,action, ID, tenant_id列。其中networkRBAC表,qosRBAC表都继承该表。

class NetworkRBAC(RBACColumns, model_base.BASEV2):

    """RBAC table for networks."""

 

    object_id = _object_id_column('networks.id')

    object_type = 'network'

 

    def get_valid_actions(self):

        actions = (ACCESS_SHARED,)

        pl = manager.NeutronManager.get_plugin()

        if 'external-net' in pl.supported_extension_aliases:

            actions += (ACCESS_EXTERNAL,)

        return actions

 

class QosPolicyRBAC(RBACColumns, model_base.BASEV2):

    """RBAC table for qos policies."""

 

    object_id = _object_id_column('qos_policies.id')

    object_type = 'qos_policy'

 

    def get_valid_actions(self):

        return (ACCESS_SHARED,)

3.2针对网络共享分析rbac策略如何实现

创建网络,主要是写入数据库。

def create_network(self, context, network):

       ###首先是写入数据库

        net_db = self.create_network_db(context, network)

        return self._make_network_dict(net_db, process_extensions=False,

                                       context=context)

 

   def create_network_db(self, context, network):

        n = network['network']

        tenant_id = n['tenant_id']

        with context.session.begin(subtransactions=True):

            args = {'tenant_id': tenant_id,

                    'id': n.get('id') or uuidutils.generate_uuid(),

                    'name': n['name'],

                    'admin_state_up': n['admin_state_up'],

                    'mtu': n.get('mtu', constants.DEFAULT_NETWORK_MTU),

                    'status': n.get('status', constants.NET_STATUS_ACTIVE),

                    'description': n.get('description')}

            network = models_v2.Network(**args)

            if n['shared']:

            ###网络的shared属性,是写入networkrbac数据表中。

                entry = rbac_db.NetworkRBAC(

                    network=network, action='access_as_shared',

                    target_tenant='*', tenant_id=network['tenant_id'])

                context.session.add(entry)

            context.session.add(network)

        return network

下面分析的是network数据模型,通过分析代码可知network表与networkrbac表是关联的。

class Network(model_base.HasStandardAttributes, model_base.BASEV2,

              HasId, HasTenant):

    name = sa.Column(sa.String(attr.NAME_MAX_LEN))

    ports = orm.relationship(Port, backref='networks')

    subnets = orm.relationship(

        Subnet, backref=orm.backref('networks', lazy='joined'),

        lazy="joined")

    status = sa.Column(sa.String(16))

    admin_state_up = sa.Column(sa.Boolean)

    mtu = sa.Column(sa.Integer, nullable=True)

    vlan_transparent = sa.Column(sa.Boolean, nullable=True)

    rbac_entries = orm.relationship(rbac_db_models.NetworkRBAC,

                                    backref='network', lazy='joined',

                                    cascade='all, delete, delete-orphan')

    availability_zone_hints = sa.Column(sa.String(255))

    dhcp_agents = orm.relationship(

        'Agent', lazy='joined', viewonly=True,

        secondary=agt.NetworkDhcpAgentBinding.__table__)

下面截图是数据库中networks表,networkrbacs表:

下面分析的是获取网络的代码。如果租户A将network1共享与租户B,在租户B中可获取到network1.

def get_network(self, context, id, fields=None):

        network = self._get_network(context, id)

        return self._make_network_dict(network, fields, context=context)

def _get_network(self, context, id):

        try:

            network = self._get_by_id(context, models_v2.Network, id)

        except exc.NoResultFound:

            raise n_exc.NetworkNotFound(net_id=id)

        return network

def _get_by_id(self, context, model, id):

        query = self._model_query(context, model)

        return query.filter(model.id == id).one()

在_model_query函数中,会根据rbac_entries来过滤网络。

def _model_query(self, context, model):

        query = context.session.query(model)

        # define basic filter condition for model query

        query_filter = None

        if self.model_query_scope(context, model):

            if hasattr(model, 'rbac_entries'):

                query = query.outerjoin(model.rbac_entries)

                rbac_model = model.rbac_entries.property.mapper.class_

                query_filter = (

                    (model.tenant_id == context.tenant_id) |

                    ((rbac_model.action == 'access_as_shared') &

                     ((rbac_model.target_tenant == context.tenant_id) |

                      (rbac_model.target_tenant == '*'))))

            elif hasattr(model, 'shared'):

                query_filter = ((model.tenant_id == context.tenant_id) |

                                (model.shared == sql.true()))

            else:

                query_filter = (model.tenant_id == context.tenant_id)

        # Execute query hooks registered from mixins and plugins

        for _name, hooks in six.iteritems(self._model_query_hooks.get(model,

                                                                      {})):

            query_hook = hooks.get('query')

            if isinstance(query_hook, six.string_types):

                query_hook = getattr(self, query_hook, None)

            if query_hook:

                query = query_hook(context, model, query)

 

            filter_hook = hooks.get('filter')

            if isinstance(filter_hook, six.string_types):

                filter_hook = getattr(self, filter_hook, None)

            if filter_hook:

                query_filter = filter_hook(context, model, query_filter)

 

        # NOTE(salvatore-orlando): 'if query_filter' will try to evaluate the

        # condition, raising an exception

        if query_filter is not None:

            query = query.filter(query_filter)

        return query

 


展开阅读全文

没有更多推荐了,返回首页