最近在研究 iam 相关的内容,iam 即身份访问管理(identify access management) 身份: 用户在整个系统体系中扮演什么样的角色 访问管理:对身份的权限控制。 那既然谈到权限控制,不得不谈谈 casbin, casbin 目前是 github 上在权限控制处理方面 star 数是最多的,虽然之前没接触过 casbin,但也调研了一段时间,从易用性,扩展性,实现上来谈谈 casbin。
核心概念
权限模型目前主流的主要包括acl
, rbac
, abac
。 简单先从这几个模型说起。而了解这几个模型之前,我们先约定一下一些术语。
subject
主体,在一般的权限体系中,主体一般是指操作者,比如某个用户,某个角色(其实角色最下面也是个用户),当然更广义的讲,可能主体也可以代表其他需要约束的对象,比如在物联网中,他也可以代表一个iot
设备。resouce
资源,一切可操作的实体都可以当做是一种资源,比如aliyun
上的我们购买的ecs
实例,后台系统的一个user
action
操作,主体对资源的操作,比如我们可以对ecs
实例进行开机,关机,重启等操作,可以新增,删除,编辑一个user
。condition
操作的条件,一般基于主体与资源的约事条件,比如user
的ip
必须在172.168.0.1/24
的段内effect
影响效力,一般只有allow(允许)/deny(不允许)
有了这些术语,我们去解释对应的权限模型,可能更知道不同模型的区别
ACL
acl(访问控制列表),他代表的是,哪些用户(subject)或系统进程可以访问(action)资源(resource) 如果某个文件 apple.jpg(resource) 的 ACL 包含(Alice(subject): read(action),write(action);Bob(subject): read(action)),这将赋予 Alice 读写文件的权限,而只赋予 Bob 读取文件的权限。
RBAC
ABAC
casbin 中的概念
理解casbin
,最主要理解其核心思路,casbin
中的核心思路是使用policy
(策略)中的规则去应用到model
(模型)中,model 是一个规则引擎,帮我们处理一个主体(subject)是否有操作(action
)某个资源(subject
)的权限。
policy
策略:一组规则的集合, 规则
model
模型:对每行规则进行解析
因此,对于我们使用者来说,大多时候仅仅只需要关注policy
和model
就行。
model 初览
在model
层面,casbin
又基于 PERM (Policy, Effect, Request, Matcher)
. 一个完整的model(perm)
文件格式如下:
|
|
request_definition
|
|
定义了在 Enforcer.Enforce
方法中请求的参数和这些传入参数的顺序;一个基本的 Request
由一个三元组组成:[sub,obj,act],subject 是指访问的实体,也就是用户;obj 是指请求的资源,act 是指对这个资源的操作,比如alice
请求了一个接口/user/add
, 我们就可以传入sub(alice)
, obj(user/add)
, act(post)
,casbin
的规则引擎会将alice
,user/add
,post
这三个参数赋值给 r。
当然,如果我们需要更多的请求判断,可以将三元组往后扩展,变成四元组,甚至五元组,这取决于我们的业务需求。
policy_definition
|
|
定义了访问策略的模型,其实就是定义了在 Policy Document 中的策略规则的字段名称以及顺序, 同样,在一个 policy 定义中,由一个三元组组成:[sub,obj,act],但在不同的模型中,可能会有不一样,如 abac 模型中,sub 可以是一个表达式,用于对象属性的处理。
policy_effect
|
|
策略影响效力,一般 effect 的值为 allow,deny, 如果我们并未定义,默认的 p.eft 为 allow, 代表只要有任意一条规则匹配通过(allow),则代表最终的效力是通过(allow)的。
当然我们也可以显式的定义在策略规则(policy document)中。就像如下再通过一个属性去接收 eft
|
|
对于效力的处理,默认的使用了 allow_overwrite. 同时,casbin 也支持 deny overwrite, 意思是没有匹配到任意一条 deny 的规则,那么最终的效力是通过(deny)的
|
|
而在大多数情况下,如果 allow 与 deny 同时出现,一般都是 deny 优先,就是未匹配到任意一条 deny 的规则,同时也得匹配到任意一条 allow 的规则,最终的效力才是通过(allow)的。 具体的定义如下:
|
|
matchers
通过上面的各种变量定义及效力判断,matchers 中就可以引入上面定义的内容,进行匹配规则的定义
|
|
上面的含义就是 r.sub(请求中传递的主体)等于策略中的定义的主体 并且 请求中传递的操作资源 等于策略中的操作资源 并且 请求中传递的操作等于策略中定义的操作。
matchers 给了我们很大的自由度去定义匹配规则。同时 casbin 也内置了一些方法帮我们去快速的处理一些判断。
role_definition
如果使用 rbac 模型, 我们还需要定义用户的角色, 角色定义的值依旧从 policy document 中读取
|
|
model 的存储
虽然 casbin 提供了很多方式存储 model,但一般对于我们使用者来说,可按以下两种情况去存储。
- 需要很多不同的 model 去匹配规则,那我们就存储在 mysql 中
- 只需要少量几个 model 去匹配规则,那我们可以以 string 的方式写在配置中
policy 文件
在上面了解了 model 的基本语法后,我们从 model 中可以看出,policy_definition 实际上就是读取 policy 文件的内容。
那 policy 文件长啥样? 大概的格式如下:
|
|
p 代表这是一条策略规则,alice, data1, read 分别对应 policy_definition 中的 sub, obj, act.
如果是使用 RBAC model,那么还会在这个文件定义用户与角色的关系,[role_definition] 根据定义生成用户和角色的实例,比如:
|
|
g 代表这是一条角色定义策略,表示用户 alice 属于角色 data2_admin.
policy document 存储
官方给出的示例基本上是以文件的形式存储成以下格式
|
|
而对于我们使用者来说,显然,不会以文件文本的方式存储,一般都会存储至数据库,或存储至 redis 做缓存。 官方有一些 adapter 的封装,如果存储至 mysql, policy 的定义字段大概如下:
id | ptype | v0 | v1 | v2 | v3 | v4 | v5 |
---|---|---|---|---|---|---|---|
1 | p | data2_admin | data2 | write | |||
2 | p | data2_admin | data2 | read | |||
3 | g | alice | admin |
可以看出,对应的字段的含义其实是与我们上面的文件形式一一对应的。ptype 代表策略规则类型,v0-v5 代表具体规则的内容。一般可能我们只能用到其中几列,但如果我们规则的复杂度够高,可能需要更多的列,那就可以在剩下的列中处理。一般的 adapter 也只帮我们处理到 v0-v5,比如 gorm-adapter, 所以,如果有超过 v5 的列,只能只行去实现 adapter.
实现 adapter 也很简单,adapter 是一个接口类型,只需要实现以下接口即可
|
|
实战
如何实现一个模型,带有主体的属性判断,主体又可能是角色/用户组/用户
在我们的系统中,不纯粹只有 rbac, 还有部分带有 abac 的特性,比如需要主体(用户)的 ip 在某个段内(比如 192.168.1.0/24)访问, 或需要主体的访问时间在每天的 10 点-22 点之间,那如何处理呢?
- 定义 request_definition
|
|
cond 代表接收一个条件,我们可以用 json 去传递,例如,{“ip”:“192.168.1.2”}
- 定义 policy_definition
|
|
同时定义 eft, cond, eft 用于定义一组规则的影响效力,cond 代表这组规则比如 ip 的域需要在 192.168.1.0/24 内,例如 {“cidr”:{“type”:“equal”, “value”:“192.168.1.0/24”}}
- 定义 policy_effect, 我们使用的是 deny 优先,同时规则必须包含要命中 allow。
|
|
- 定义 matcher, 因为增加了一个 cond 的匹配,而 cond 的匹配很灵活,我们可以借助自定义的函数帮助检验
|
|
- 定义 role_definition, 因为有使用到角色相关的
|
|
- 自定义函数 condChecker
|
|
- policy document 的记录
|
|
- 鉴权处理
|
|
可能存在的问题
-
如果使用 casbin 的 adapter,目前看,所有的用户共享一张表,casbin 很有可能将这些所有的策略规则都放在一个文件里,很显然,当规则很多的时候,每个用户都会走一次全部的规则,是不是会很影响效率?
-
如果我们建立的规则类似 aws iam 这种组织方式,可能一个策略中 resource, condition, effect 都共用,而 casbin 的 policy 更像是结构化的存储,多个 action 就冗余 resource, conition, effect, 实际上还是挺占用空间的。在设计层面上可能不太优雅,但对于量不是特别大的话,可能影响也并不算大