openstack policy 鉴权过程分析

转:http://blog.chinaunix.net/uid-20940095-id-4144300.html

1. openstack 鉴权简单介绍   
    众所周知,openstack通过keystone用来完成authenticate(认证),真正的鉴权(authorize)是在各个模块分别做的,具体实现为每个模块都有一个policy文件,叫policy.json,里面定义了鉴权用的rules。
    以nova为例,policy文件的位置在:/etc/nova/policy.json,下面先来看几条rules,了解其基本含义:

本含义:

"compute:create": "",
"compute:create:attach_network": "",
"compute:create:attach_volume": "",
"compute:create:forced_host": "is_admin:True",
"compute:get_all": "",
"compute:get_all_tenants": "",
"compute:start": "rule:admin_or_owner",
"compute:stop": "rule:admin_or_owner",
"compute:unlock_override": "rule:admin_api",

语法规则为:rule:[result]
rule:指这条规则是干啥的,通常对应一个action,以类似scope:action的形式给出,scope表示作用范围,action表示执行哪种操作
result: 表示这条rule的判定结果或者如何进行判定,比如"compute:create:forced_host":"is_admin:True",如果执行此操作的用户具有admin角色(role),则这条结果的判定结果就是True。
另外,rule是可以嵌套的,比如"compute:stop": "rule:admin_or_owner",表示compute:stop这条规则的结果为admin_or_owner这条规则的结果,而admin_or_owner规则如下:

"admin_or_owner": "is_admin:True or project_id:%(project_id)s",

如果调用这个操作的用户的角色是admin,就返回True,或者返回用户所属的project的id.

2. policy鉴权代码分析
针对每一个操作,都会经过一个叫@wrap_check_policy的decorator,以nova的resize操作为例,在执行真正的resize代码之前,先要经过一个叫@wrap_check_policy的装饰器来完成policy的check过程,具体参见后面的代码check_policy函数:

    @wrap_check_policy
    @check_instance_lock
    @check_instance_cell
    @check_instance_state(vm_state=[vm_states.ACTIVE, vm_states.STOPPED],
                          task_state=[None])
    def resize(self, context, instance, flavor_id=None,
               **extra_instance_updates):

check_policy(context, action, target, scope=‘compute‘)函数有四个参数:
(1) context: 执行resize操作的上下文,其内容包括project_id, user_id, role,auth_token等信息,具体如下:

(2) action:表示当前执行的操作是啥,这里就是resize
(3) target:操作针对的object是啥,这里就是instance id
(4) scope:当前操作的作用域是啥,主要为了与policy文件中定义的作用域匹配,这里为compute,即nova执行的操作

def check_policy(context, action, target, scope=‘compute‘):
        _action = ‘%s:%s‘ % (scope, action)  ##这里拼接成policy.json的rule,即_action=compute:resize
        nova.policy.enforce(context, _action, target)
------------------------------------------------------------------------------------------------------------------------
    def enforce(context, action, target, do_raise=True):
        """Verifies that the action is valid on the target in this context.

           :param context: nova context
           :param action: string representing the action to be checked
               this should be colon separated for clarity.
               i.e. ``compute:create_instance``,
               ``compute:attach_volume``,
               ``volume:attach_volume``
           :param target: dictionary representing the object of the action
               for object creation this should be a dictionary representing the
               location of the object e.g. ``{‘project_id‘: context.project_id}``
           :param do_raise: if True (the default), raises PolicyNotAuthorized;
               if False, returns False

           :raises nova.exception.PolicyNotAuthorized: if verification fails
               and do_raise is True.

           :return: returns a non-False value (not necessarily "True") if
               authorized, and the exact value False if not authorized and
               do_raise is False.
        """
        init()   ##policy.json被cache到cache_info数据结构中,init()函数就是去检查policy.json是否已经被加载或修改过,如果cache_info结构为空,说明policy.json还没有加载过,则执行加载;如果policy.json被修改过,也会重新进行加载

        credentials = context.to_dict()  ##将context转化成dictonary,就是上面context给出的内容,以便后面代码使用

        # Add the exception arguments if asked to do a raise
        extra = {}
        if do_raise:
            extra.update(exc=exception.PolicyNotAuthorized, action=action)  ##增加no auth hook函数,即如果rule的结果为False,则执行no auth hook函数做一些处理

        return policy.check(action, target, credentials, **extra)  ##进行policy的check
--------------------------------------------------------------------------------------------------------------------
def init():
    global _POLICY_PATH
    global _POLICY_CACHE
    if not _POLICY_PATH:
        _POLICY_PATH = CONF.policy_file
        if not os.path.exists(_POLICY_PATH):
            _POLICY_PATH = CONF.find_file(_POLICY_PATH)
        if not _POLICY_PATH:
            raise exception.ConfigNotFound(path=CONF.policy_file)
    utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE,
                           reload_func=_set_rules) ##加载policy.json文件
----------------------------------------------------------------------------------------------------------------------

def read_cached_file(filename, cache_info, reload_func=None):
    """Read from a file if it has been modified.

    :param cache_info: dictionary to hold opaque cache.
    :param reload_func: optional function to be called with data when
                        file is reloaded due to a modification.

    :returns: data from file

    """
    mtime = os.path.getmtime(filename)  ###获取policy.json文件的modify time,如果与cache_info中的mtime不同,则说明文件被修改过,则执行重新加载
    if not cache_info or mtime != cache_info.get(‘mtime‘):
        LOG.debug(_("Reloading cached file %s") % filename)
        with open(filename) as fap:
            cache_info[‘data‘] = fap.read()
        cache_info[‘mtime‘] = mtime
        if reload_func:
            reload_func(cache_info[‘data‘])
    return cache_info[‘data‘]            ###返回加载后的policy.json文件的内容
---------------------------------------------------------------------------------------------------------------------------
def check(rule, target, creds, exc=None, *args, **kwargs):
    """
    Checks authorization of a rule against the target and credentials.

    :param rule: The rule to evaluate.
    :param target: As much information about the object being operated
                   on as possible, as a dictionary.
    :param creds: As much information about the user performing the
                  action as possible, as a dictionary.
    :param exc: Class of the exception to raise if the check fails.
                Any remaining arguments passed to check() (both
                positional and keyword arguments) will be passed to
                the exception class. If exc is not provided, returns
                False.

    :return: Returns False if the policy does not allow the action and
             exc is not provided; otherwise, returns a value that
             evaluates to True. Note: for rules using the "case"
             expression, this True value will be the specified string
             from the expression.
    """

    # Allow the rule to be a Check tree
    if isinstance(rule, BaseCheck):
        result = rule(target, creds)
    elif not _rules:
        # No rules to reference means we‘re going to fail closed
        result = False
    else:
        try:
            # Evaluate the rule
            result = _rules[rule](target, creds)  ##没一条rule执行一个函数,这个对应关系记录在全局变量_rules
        except KeyError:
            # If the rule doesn‘t exist, fail closed
            result = False

    # If it is False, raise the exception if requested
    if exc and result is False:
        raise exc(*args, **kwargs)

    return result

3. 总结 
    之前一直以为修改了policy.json文件,需要重启service才能重新加载policy.json生效,通过分析代码,证明policy.json是动态更新的。另外,通过分析代码,也搞清楚了如何添加自定义的rule,以便实现更细粒度的rule,稍后会给出一个自己实现的例子。

原文地址:https://www.cnblogs.com/menkeyi/p/8556297.html

时间: 2024-10-09 03:52:02

openstack policy 鉴权过程分析的相关文章

微服务架构中的安全认证与鉴权

转载:http://www.bootdo.com/blog/open/post/125 从单体应用架构到分布式应用架构再到微服务架构,应用的安全访问在不断的经受考验.为了适应架构的变化.需求的变化,身份认证与鉴权方案也在不断的变革.面对数十个甚至上百个微服务之间的调用,如何保证高效安全的身份认证?面对外部的服务访问,该如何提供细粒度的鉴权方案?本文将会为大家阐述微服务架构下的安全认证与鉴权方案. 单体应用 VS 微服务 随着微服务架构的兴起,传统的单体应用场景下的身份认证和鉴权面临的挑战越来越大

使用ranger对kafka进行鉴权

使用ranger对kafka进行鉴权测试环境:ranger-kafka-plugin为0.6.3版本,kafka版本为kafka_2.10-0.10.1.1,且kafka broker为一个节点.一.Ranger对kafka进行权限控制,前提需要kafka开启kerberos认证(注意:若kafka不开启kerberos的话Ranger无法获取kafka相关操作的用户,进而无法完成鉴权操作)二.开启kerberos认证包括zookeeper开启kerberos认证,kafka开启zookeepe

web系统中ACL, RBAC等鉴权系统的异同

ACL, 强调面向资源, 描述对具体资源对象的操作鉴权, 有诸如Zend_ACL(好用), symfony-acl(不好用)等实现 应用场景如:对一条帖子资源的增删改鉴权, 整个鉴权流程中, 权限部分是由具体帖子对象和增删改等操作共同构成的.授权的结果是将 "资源---操作" 组合授权给用户. RBAC,强调面向角色的权限节点鉴权, 描述对功能节点的鉴权,有诸如ThinkPHP-RBAC, sylius/rbac-bundle(symfony)等实现 应用场景如: 依据不同用户角色显示

带鉴权信息的SIP呼叫

INVITE sip:[email protected]/2.0 Via: SIP/2.0/UDP192.168.50.32:2445;branch=z9hG4bK-d8754z-244fd550d2729557-1---d8754z-;rport Max-Forwards: 70 Contact:<sip:[email protected]:2445> To: <sip:[email protected]> From:"1002"<sip:[email 

WebSocket 的鉴权授权方案

引子 WebSocket 是个好东西,为我们提供了便捷且实时的通讯能力.然而,对于 WebSocket 客户端的鉴权,协议的 RFC 是这么说的: This protocol doesn't prescribe any particular way that servers canauthenticate clients during the WebSocket handshake. The WebSocketserver can use any client authentication me

无线端安全登录与鉴权一之Kerberos

无线端登录与鉴权是安全登录以及保证用户数据安全的第一步,也是最重要的一步.之前做过一个安全登录与鉴权的方案,借这个机会,系统的思考一下,与大家交流交流 先介绍一下TX系统使用的Kerberos方案,参考了 http://blog.csdn.net/wulantian/article/details/42418231 的文章 一.概念介绍 Kerberos:起源于希腊神话,是一支守护着冥界长着3个头颅的神犬,在keberos Authentication中,Kerberos的3个头颅代表中认证过程

开放平台鉴权以及OAuth2.0介绍

OAuth 2.0 协议 OAuth是一个开发标准,允许用户授权第三方网站或应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的内容. OAuth 2.0不兼容1.0. 协议的参与者 RO (resource owner): 资源所有者,对资源具有授权能力的人. RS (resource server): 资源服务器,它存储资源,并处理对资源的访问请求. Client: 第三方应用,它获得RO的授权后便可以去访问RO的资源. AS (authoriz

api-gateway实践(7)鉴权场景和网关场景梳理、OAuth2待澄清问题列表

一.身份鉴权验证 1.业务请求 1.1.父元素声明了 "/GroupA/VersionB/*",子元素声明了 "/GroupA/VersionB/Cxxx",access="ROLE_XXXX" 身份识别: 有效token 无token.无效token   权限鉴别: 有权限: 无权限: 1.2.父元素声明了 "/GroupA/VersionB/*",子元素没有声明的 "/GroupA/VersionB/Dxxx&q

搭建一个分布式MongoDB鉴权集群

今天休假在家,测试并搭建了一个replica set shard MongoDB鉴权集群.replica set shard 鉴权集群中文资料比较少,本文是个人笔记,同时也希望对后来者有所帮助.本文仅是搭建步骤和Q&A,用于实际工作中的使用查阅,阅读者需要有分布式集群的理论基础. 关键字:Replica-Set Shard 副本 分片 鉴权 KeyFile auth MongoDB根据部署的不同,有两种添加鉴权的方式,分别是单实例的鉴权方式和KeyFile的鉴权方式.两种方式的共同点都是,先在没