Neutron RBAC-network 介绍
RBAC-network 的引入背景
RBAC,即 Role Base Access Control。而 RBAC-network 主要针对 Neutron 中的网络资源增加了访问控制。RBAC-network 这一功能是在 Neutron 的 Liberty 版本中被引入的。
我们这里所说的访问是指,用户可以在通过 API/CLI 来查询网络,在网络上创建 Port 这一资源。
在 Neutron 引入 RBAC-network 之前,在 Neutron 中创建的网络(包括其子网)对于访问控制,只具有 shared 属性,并且我们只可以将 shared 属性设置为 True 或者 False。True,即为面向所有租户,来自任意租户的用户都可以访问 shared 属性为 True 的网络,而 False,即为只面向所属租户,只有来自网络所属于的租户的用户可以访问网络。
显然这样对于网络所属租户是不安全的,网络所属的租户应该有权利来决定来自其他哪些租户的用户可以访问本租户的网络,而哪些不能。即租户下面的网络所具有的 shared 属性,应该是可以由租户自己决定如何对第三方租户开启访问共享的。而不是原来的全开或者全关的简单二元属性。
在 RBAC-network 引入后,对于 shared 属性,其拥有了一个中间状态。租户可以在网络的 shared 为 False 的情况下,通过添加针对网络的访问权限,来支持指定的第三方租户访问自己所拥有的网络。需要说明的有以下几点:1)作为终极用户,admin 并不受 RBAC-network 的影响,即使没有被租户添加访问权限,admin 用户仍然可以访问租户的网络;2)在引入 RBAC-network 后,网络的 shared 属性的原有特性仍然被保留了,即当 shared 被设置为 True 时,网络仍是面向所有租户的,因此为了使 RBAC-network 生效,以及达到访问控制的目的,租户网络的 shared 属性不建议更新为 True;3)网络所属租户对于网络持有最终话语权,网络所属的租户对于网络上的由第三方租户创建的 Port 拥有删除的权利。
在经过访问权限的支持,使得网络联通性被构建后,在网络数据层面的控制则由安全组来管理,将不属于本文的范畴。
在 Neutron 中被引入 RBAC 支持的,除了网络这一资源外,还有 QoS。而 RBAC 支持开启的权限,目前主要有两种,一种为 access_as_shared,另一种为 access_as_external。本文将只对网络这一资源的访问控制,即 RBAC-network,以及 access_as_shared 这一权限进行解读。
RBAC-network 在设计上的考量
首先,我们需要理解的是对 Neutron 提供的网络联通性,其工作的最基本单元为 Port。Port 可以是一个 IP 设备的抽象,也可以是一个 OVS port 的抽象以及其他类型情况。对于一个想使用 Neutron 提供的网络服务的用户而言,其最终想要的是在 Neutron 网络上创建一个 Port,并在这个 Port 的基础上构建网络联通性。
既然 Port 是 Neutron 提供网络服务的最小单元,那么在 Port 的集合上添加访问控制就变得显而易见。如果我们没有权限在 Port 资源的集合中创建出一个被我们使用,那么我们的数据就无法通过 Port 在对应的资源集合中传输,即无法使用网络。
在 Neutron 中,Subnet 这一资源应该被考虑为 CIDR 的集合,而 Network 才是 Port 的集合(在 Neutron 的数据库中,我们可以看到对于 Port 表,其有一列的名字为 network_id,即指向 Port 所属的 Network,而没有其他属性来指向 Subnet),因此当需要添加访问控制时,需要被考虑添加这一特性的应该是 Network。
在理解 Neutron 的二层网络模型后,对于 Neutron 的三层网络模型为什么不需要添加访问控制的原因也将显而易见。由于 Neutron Router 所接的外网,一般为 admin 用户创建和管理,因此略过不论,我们将仅讨论内网的情况。
当 Router 的所有者尝试为 Router 添加子网接口时(例如通过 CLI 方式,neutron router-interface-add ROUTER SUBNET),在 Neutron Server 端实际上将有两个与权限有关的工作进行处理,一个是查询 Subnet,另一个是在 Subnet 上创建 Port 作为接口。在理解前述的内容的基础上,这里只需要知道 Subnet 是 Network 下面的另一个资源,就可以看出在 Network 上添加的访问控制仍然可以在这里发挥作用。
而对于 Router 本身所提供的资源,我们需要考虑的是静态路由。如果也引入面向共享的增删改的访问控制,则会引起二层网络访问权限过度依赖的问题。假设 Router 所属的租户为 Tenant-A,Router 所接的子网分别来自 Tenant-A,Tenant-B,Tenant-C。当 Tenant-B 的用户也有权限来配置 Router 中的静态路由时,如果 Tenant-B 的用户想要添加到达 Tenant-C 子网的静态路由,那么首先 Tenant-B 的用户需要有 Tenant-C 的网络的访问权限,而这可能是 Tenant-B 本身并不需要的。在 Tenant-A 获得了 Tenant-B 和 Tenant-C 的访问权限后,只由 Tenant-A 来管理 Router 的静态路由,将避免资源管理方面额外的负担。
对于其他依赖于 Neutron 二层和三层网络的高级服务,其理解思路也基本如此。
RBAC-network 在 Neutron code 中的主要实现
除了 Policy 文件的修改,实现 RBAC-network 的主要工作都集中在数据库的接口层面,即增删改查的管理。对于与 Policy 文件有关的细节,我们将在下一小节进行阐述。在本节讲着重介绍 RBAC-network 的相关 code 是如何在数据库接口层面发挥作用的。
首先,我们来看数据模型发生的变化。在引入 RBAC-network 后,Neutron 中新添加了 RBACColumns 和 NetworkRBAC 两个类,这两个类共同构成了数据库中新的表 NetworkRBACs。
表 1.Neutron DB 中的 NetworkRBACs 表
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
id | varchar(36) | NO | PRI | NULL | |
object_id | varchar(36) | NO | MUL | NULL | |
tenant_id | varchar(255) | YES | MUL | NULL | |
target_tenant | varchar(255) | NO | NULL | ||
action | varchar(255) | NO | MUL | NULL |
在这张表中存放着针对某一网络所生成 RBAC-network rule 的四元组(object_id,tenant_id,target_tenant,action)。id 为 RBAC-network rule 自己的 ID。在四元组中,object_id 对应网络 ID,tenant_id 对应网络所属租户的 ID,target_tenant 对应第三方租户的 ID,action 则对应"access_as_shared"和"access_as_external"这两个 action 之一。
需要补充说明的是,当网络的 shared 属性被设置为 True 时,target_tenant 列的值将为'*',即通配符。而对于 target_tenant,截止到本文写作时,Neutron 并不会对 target_tenant 的值进行有效性的检查。
并且对于原有的 ORM 类 Network(对应 Networks 表)和 Subnet(对应 Subnets 表),针对 RBAC 增加了 orm.relationship:
清单 1. 在 Network 类中的 RBAC orm.relationship
rbac_entries = orm.relationship(rbac_dbmodels.NetworkRBAC,
backref='network', lazy='joined',
cascade='all, delete, delete-orphan'_)
清单 2. Subnet 类中的 RBAC orm.relationship
subnets don't have their own rbac_entries, they just inherit from
the network rbac entries
rbac_entries = orm.relationship(
rbac_db_models.NetworkRBAC, lazy='joined', uselist=True,
foreign_keys='Subnet.network_id',
primaryjoin='Subnet.network_id==NetworkRBAC.object_id')
这两个属性将主要在 Network 和 Subnet 的查询发挥作用。
接下来我们要考虑的是 Port,Subnet,Network 这三种 Neutron 核心资源在数据库层面的工作。实际上,对于这三种资源,只有 Network 的创建不会涉及到查询外,Network 的删除,更新,以及 Subnet 和 Port 的增删改查都会涉及到数据的查询。因此本文将主要讲述 RBAC-network 作用于这三种资源的查询工作。
Neutron 对于 RBAC-network 提供支持的代码主要在 CommonDBMixin 类中,主要为两个方法,_model_query 和_apply_filters_to_query。
在_model_query 方法中,通过判断被查询的 Model 是否含有'rbac_entries'属性来判断是否需要对查询语句表达式进行扩展。主要代码片段为:
清单 3. 对含有 rbac_entries 的 Model 进行权限检查
if hasattr(model, 'rbac_entries'):
query = query.outerjoin(model.rbac_entries)
rbac_model = model.rbacentries.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 == '*'))))
当查询来自第三方租户时,context.tenant_id 即为第三方的租户 ID,此时 query_filter 表达式扩展的结果为:在 Networks/Subnets 表中查询能够关联到 NetworkRBACs 表中 action 为"access_as_shared",同时 target_tenant 为自己 ID 或者通配符的记录。
在_apply_filters_to_query 方法中,主体思路一致,这里略过不论。
不同于 Network 和 Subnet,Port ORM 类不具有 rbac_entries 属性。同时对于租户网络上不属于租户的 Port,又需要为租户提供支持查询和删除的能力。为此 RBAC-network 利用到了 query hook 机制来实现对于 Port 的租户权限检查。
query hook 机制的基本思想是由 CommonDBMixin 来实现基本的 query_filter 表达式,而对于不同的 ORM 类,以及不同的 query 场景,则由各个 ORM 类在自己的 hook 方法中生成特定的 query 扩展表达式,并将 hook 方法注册到 CommonDBMixin 类的_model_query_hooks 字典中。当某个 ORM 类通过 CommonDBMixin 的方法被查询时,后者在生成基本的 query 表达式后会检查_model_query_hooks 字典中注册的 query hook,并根据情况扩展 query_filter 表达式。
query hook 机制对于 Neutron 的意义在于,从各个 ORM 类的查询工作中分离了 common query,简化了代码。而对于实现 RBAC-network,query hook 则屏蔽了 Port 与 Network 之间 tenant_id 匹配的细节。
RBAC-network 与 Neutron Policy 的一些冲突与缺陷
当通过 CLI/API 对 Neutron 的资源进行增删改查时,首先需要经过 Policy 的核查。
在实现 RBAC-network 之前,Neutron Policy 的主要思路是除了 admin 外,网络的使用者即是网络的所有者。因此 Policy 文件中有着较多的"admin_or_network_owner"作为资源操作所需要匹配的 rule。而实现 RBAC-network 后,Neutron 并没有对 Policy 进行比较好的更新,因此在使用 RBAC-network 时,将会遇到一些与现有的 Neutron Policy 存在冲突的地方。
主要的冲突与缺陷集中在 Port 上,与 Port 的创建和更新操作有关。虽然创建 RBAC-network rule 后,租户授予了第三方租户在自己网络上创建 Port 的权限,但是这种权限是有限的,第三方无法通过指定 mac_address,fixed_ips,port_security_enabled 等参数的方式来创建 Port。而对于更新 Port,操作本身的检查 rule 为仅支持 admin 或者 Port 的所有者,但当更新操作带有参数时,一些参数的检查 rule 则仅支持 admin 或者 Network 的所有者,这些参数包括 mac_address,fixed_ips,port_security_enabled 等。这将导致对于租户网络上的第三方 Port,只有 admin 才可以更改其部分属性的情况。
而对于 Subnet,则可能存在另外一些令人困惑的问题。在 RBAC-network 的支持下,第三方可以查看到租户的网络以及网络信息,并且也可以在网络中传建 Port,但却无法在网络中创建子网。
对于 Port 这一资源,建议根据需求适当的改变 Policy 文件,可以避免上述冲突与缺陷。
RBAC-network 在 devstack 环境上的基本演示
devstack 部署好的环境中,默认会创建一个 private 网络,通过查看 private 网络的属性以及查看 Keystone 中 Project 表的内容,可以发现这个 private 网络的 tenant_id 是 demo 租户的 ID。除了 admin 和 demo 这两个租户,devstack 环境中 alt_demo 租户也将在本演示用到。以下示例中,alt_demo 租户的 ID 为 73b3f86dbe344ce6ab2206bae60df59f。
清单 4.alt_demo 租户无法发现 private 网络
$ source devstack/openrc alt_demo alt_demo
$ neutron net-show private
Unable to find network with name or id 'private'
清单 5. 为 alt_demo 租户创建 RBAC-network 规则
$ source devstack/openrc demo demo
$ neutron rbac-create --type network --target-tenant 73b3f86dbe344ce6ab2206bae60df59f \
--action access_as_shared private
Created a new rbac_policy:
+---------------+--------------------------------------+
| Field | Value |
+---------------+--------------------------------------+
| action | access_as_shared |
| id | 04b3e607-8fe5-4fdf-a3c8-5fe0ddf161d4 |
| object_id | dec53c22-04fd-45e3-bf07-660aa739c818 |
| object_type | network |
| target_tenant | 73b3f86dbe344ce6ab2206bae60df59f |
| tenant_id | d15ad6028c8f4dd78ac2340138951e5a |
+---------------+--------------------------------------+
清单 6.alt_demo 租户使用 private 网络
清单 6.alt_demo 租户使用 private 网络
$ source devstack/openrc alt_demo alt_demo
$ neutron net-list
+--------------------------------------+---------+----------------------------------------------------------+
| id | name | subnets |
+--------------------------------------+---------+----------------------------------------------------------+
| dec53c22-04fd-45e3-bf07-660aa739c818 | private | 1197ceaf-b8a9-49d8-a399-47820909243a 10.0.0.0/24 |
| | | 69f408a4-1d48-453d-9328-c263b1de1e29 fd81:ce49:b123::/64 |
+--------------------------------------+---------+----------------------------------------------------------+
$ neutron port-create --name port_alt_demo private
Created a new port:
+-----------------------+-------------------------------------------------------------------------------------------------------------+
| Field | Value |
+-----------------------+-------------------------------------------------------------------------------------------------------------+
| admin_state_up | True |
| allowed_address_pairs | |
| binding:vnic_type | normal |
| created_at | 2016-06-14T03:41:19 |
| description | |
| device_id | |
| device_owner | |
| extra_dhcp_opts | |
| fixed_ips | {"subnet_id": "1197ceaf-b8a9-49d8-a399-47820909243a", "ip_address": "10.0.0.9"} |
| | {"subnet_id": "7b72e29a-92fd-48b2-a447-8dd56ee02fe7", "ip_address": "fd81:ce49:a948:0:f816:3eff:fec5:f9ab"} |
| | {"subnet_id": "69f408a4-1d48-453d-9328-c263b1de1e29", "ip_address": "fd81:ce49:b123:0:f816:3eff:fec5:f9ab"} |
| id | 0ad3ed4d-8a44-4fa1-9f50-9b971792d5af |
| mac_address | fa:16:3e:c5:f9:ab |
| name | port_alt_demo |
| network_id | dec53c22-04fd-45e3-bf07-660aa739c818 |
| port_security_enabled | True |
| security_groups | 401ded4e-47fa-4987-b06a-4d3e37566b04 |
| status | DOWN |
| tenant_id | 73b3f86dbe344ce6ab2206bae60df59f |
| updated_at | 2016-06-14T03:41:19 |
+-----------------------+-------------------------------------------------------------------------------------------------------------+
清单 7. 各租户查看 private 网络上的 port
$ source devstack/openrc demo demo
$ neutron port-list -c id -c name
+--------------------------------------+---------------+
| id | name |
+--------------------------------------+---------------+
| 0ad3ed4d-8a44-4fa1-9f50-9b971792d5af | port_alt_demo |
| 487fdacf-e226-4c96-bc64-238b880d845c | |
+--------------------------------------+---------------+
$ source devstack/openrc alt_demo alt_demo
$ neutron port-list -c id -c name
+--------------------------------------+---------------+
| id | name |
+--------------------------------------+---------------+
| 0ad3ed4d-8a44-4fa1-9f50-9b971792d5af | port_alt_demo |
+--------------------------------------+---------------+
清单 8.demo 租户删除其他租户的 port
$ source devstack/openrc demo demo
$ neutron port-delete port_alt_demo
Deleted port: port_alt_demo
$ source devstack/openrc alt_demo alt_demo
$ neutron port-show port_alt_demo
Unable to find port with name or id 'port_alt_demo'
总结
RBAC-network 的引入,增强了租户对于自己的网络访问权限的管理,使得租户自己有权利决定如何向第三方开放自己网络的访问权限。使得租户的网络资源可以被更合理和安全的使用。但是我们也看到 RBAC-network 的一些设计可能会与现有的 Neutron Policy 存在冲突,我们可以通过更改 Neutron Policy 来增加或者缩小租户对其网络相关资源的管理权限范围,但这依赖于管理员对 OpenStack 云平台的网络资源行为的定义。
关键字:路由器, 数据持久化, 数据库, 产品经理
版权声明
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!