理解 Role, Policy 以及 Role-Based Access Control
本文主要讲解 Keystone 的两类基本服务,如下图蓝色部分:
- Assignment:包括 role 和 role assignment,用于描述某个 identity 对某个 resource 下的资源拥有的访问权限。
- Policy:定义 OpenStack API 基于 role 的访问权限规则。
Assignment 简介
Role
Role 可简单的理解为用户级别,用户角色的级别越高,对 project 里资源拥有的操作权限就越大。Keystone 提供和 role 相关增删改查的 API。
$ keystone role-list
+----------------------------------+-------------------------------------+
| id | name |
+----------------------------------+-------------------------------------+
| 507bface531e4ac2b7019a1684df3370 | cloud_admin |
| 9fe2ff9ee4384b1894a90878d3e92bab | limited_user |
| e00e9406b536470dbde2689ce1edb683 | user |
| aa60501f1e664ddab72b0a9f27f96d2c | domain_admin |
+----------------------------------+-------------------------------------+
Role Assignment
Role Assignment 定义了某个 identity(user 或者 group) 对某个 resource(project 或者 domain) 下的资源拥有的访问权限。如果用户 Acme 想要访问 Bob project 的资源,就必须通过 role assignment 在 Bob project 赋予 Acme 相关的 role。
$ keysone user-role-add --user Acme --tenant Bob --role admin
其中 user, group, project 和 domain 具有以下关系。
- Project 和 domain 均可以赋予 user 或者 group 某种角色(role)。
- 如果在 Project A 赋予 Group A 角色 admin,那么 Group A 下的 User B 和 User C 在 Project A 下均为 admin 角色。
- 如果在 Domian A 赋予 User A 角色 admin,那么 User A 在 Project B 和 Project C 均为 admin 角色。
Policy
OpenStack 官网是这么介绍 policy:
The Policy service provides a rule-based authorization engine and the associated rule management interface.
上句话可以理解成以下两点:
- Policy 是一种基于 rule 的授权机制。
- Policy 通常用来管理服务的 interface,即 OpenStack 的 API 访问规则。
早期各个组件都有 policy 相关模块,如:
- Keystone: /keystone/openstack/common/policy.py
- Nova: /nova/openstack/common/policy.py
- Cinder: /cinder/openstack/common/policy.py
以 Nova 为例,policy 模块根据 /etc/nova/policy.json 所设定的 rule,定义基于 API 粒度授权访问控制规则,详情见下节。随着项目的迭代发展,policy 以 olso.policy 的形式成为了公共模块。
Role-based Access Control
在日常应用中,特别在安全领域,有多种访问访问控制规则,比如:
- 基于 IP 的访问控制:如 iptables,可以设定哪些 ip 具有访问权限
- 基于 PIN 码的访问控制:如某些认证系统,可以设定哪些 PIN 码具有访问权限
- 基于 Role 的访问控制:如某些认证系统,根据 Role 来判读是否具有访问权限
OpenStack 采用 Role-based Access Control (RBAC),所有的 API 在入口处根据 policy.json 的规则判定用户拥有的 role 是否具有访问权限,policy.json 的语法请参考此文。
在不同的 API 里,其代码表示形式略有不同,以 nova 创建虚拟机为例:
@hooks.add_hook("create_instance")
def create(self, context, instance_type,
image_href, kernel_id=None, ramdisk_id=None,
min_count=None, max_count=None,
display_name=None, display_description=None,
key_name=None, key_data=None, security_group=None,
availability_zone=None, user_data=None, metadata=None,
injected_files=None, admin_password=None,
block_device_mapping=None, access_ip_v4=None,
access_ip_v6=None, requested_networks=None, config_drive=None,
auto_disk_config=None, scheduler_hints=None, legacy_bdm=True):
"""Provision instances, sending instance information to the
scheduler. The scheduler will determine where the instance(s)
go and will handle creating the DB entries.
Returns a tuple of (instances, reservation_id)
"""
# 下面函数检验了用户是否具有创建虚拟机的权限
self._check_create_policies(context, availability_zone,
requested_networks, block_device_mapping)
...
以 nova 删除虚拟机为例:
# 装饰器 @wrap_check_policy 检验了用户是否具有删除虚拟机的权限
@wrap_check_policy
@check_instance_lock
@check_instance_cell
@check_instance_state(vm_state=None, task_state=None,
must_have_launched=False)
def delete(self, context, instance):
"""Terminate an instance."""
LOG.debug(_("Going to try to terminate instance"), instance=instance)
self._delete_instance(context, instance)
/etc/nova/policy.json 默认定义各个 API 的访问规则如下:
{
"context_is_admin": "role:admin",
"admin_or_owner": "is_admin:True or project_id:%(project_id)s",
"default": "rule:admin_or_owner",
"compute:create": "",
"compute:delete": "",
"compute_extension:admin_actions:migrate": "rule:admin_api"
}
以上配置文件具有以下含义:
- 所有 role 均可以创建虚拟机
- 所有 role 均可以删除虚拟机
- 迁移虚拟机需要 admin role,即对于 role 为 member 级别的用户,它无法迁移虚拟机
同样,如果我们要求必须拥有 admin 角色的 user 才能创建虚拟机,那么上述配置文件可更新为:
"compute:create": "role:admin"
此时如果角色为 member 的用户创建虚拟机时,nova 将返回 403,HTTPForbidden 的错误。
浅谈角色设计
角色设计
以支持子账户功能的公有云为例,可设计成以下 4 类基本角色,就权限等级而言有如下关系:
cloud_admin > domain_admin > user > limited_user
- cloud_admin:即全局超级管理员,对所有 project 都有 CRUD 权限。
- domain_admin:即某个 domian 的超级管理员,对 domain 下的 project 都有 CURD 权限,但是不能创建 domain,也不能授权用户超出 domain_admin 的角色。
- user:相当于某个 project 的管理员,对项目资源有 CRUD 权限,但是不能管理者账户。
- limited_user:可理解为欠费用户,对项目资源只有只读权限。
Drawbacks
事实上,OpenStack 在权限设计上存在以下缺点。
- Keystone V2 API 用户角色被写死在代码中,仅支持 admin 和 member 两种角色。
- Nova 针对数据库的操作添加了权限校验,增加权限设计的复杂性。在 L 版本时,数据库的权限校验被移除。