本文主要讲解 Keystone 的两类基本服务,如下图蓝色部分:

  • Assignment:包括 role 和 role assignment,用于描述某个 identity 对某个 resource 下的资源拥有的访问权限。
  • Policy:定义 OpenStack API 基于 role 的访问权限规则。

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 具有以下关系。

role assignment

  • 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 版本时,数据库的权限校验被移除