Menu

  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay
  • Home
  • Work
    • Cloud
      • Virtualization
      • IaaS
      • PaaS
    • Java
    • Go
    • C
    • C++
    • JavaScript
    • PHP
    • Python
    • Architecture
    • Others
      • Assembly
      • Ruby
      • Perl
      • Lua
      • Rust
      • XML
      • Network
      • IoT
      • GIS
      • Algorithm
      • AI
      • Math
      • RE
      • Graphic
    • OS
      • Linux
      • Windows
      • Mac OS X
    • BigData
    • Database
      • MySQL
      • Oracle
    • Mobile
      • Android
      • IOS
    • Web
      • HTML
      • CSS
  • Life
    • Cooking
    • Travel
    • Gardening
  • Gallery
  • Video
  • Music
  • Essay

Casbin学习笔记

30
Jan
2020

Casbin学习笔记

By Alex
/ in Go
0 Comments
简介

Casbin是一个权限控制的开发库,它的特性包括:

  1. 支持多种编程语言,包括Go、Java、Node.js、PHP、Python等
  2. 支持ACL、RBAC、ABAC等多种访问控制模型
  3. 支持以典型的 {subject, object, action}形式,或者自定义的形式来定义策略,allow/deny授权均支持
  4. 支持处理访问控制模型,及其策略的存取(和存储后端交互)
  5. 支持管理角色-用户映射,以及角色-角色映射(RBAC中的角色层次)
  6. 支持内置超级用户,例如root/administrator,不需要明确授权就可以作任何事情
  7. 很多内置的操作符,来支持规则匹配

Casbin不负责:

  1. 身份验证
  2. 管理角色、用户的详细信息。但是它维护角色和用户之间的关系
访问控制模型

Casbin支持的访问控制模型列表:

模型 说明
ACL

为对象添加一个访问许可(Permissions)列表,每个条目指定主体(Subject,例如用户/进程)可以对对象执行何种操作(Action)

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

策略示例:

1
2
p, alice, data1, read
p, bob, data2, write 
ACL with superuser

ACL模型,外加指定特权用户

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act || r.sub == "root"
ACL without users

用于没有身份验证机制/用户登陆的系统

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = obj, act
 
[policy_definition]
p = obj, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = r.obj == p.obj && r.act == p.act

策略示例:

1
2
p, data1, read
p, data2, write
ACL without resources

针对资源类别,而非资源实例进行访问控制。例如write-article, read-log,不去控制某个article、log的访问权限

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, act
 
[policy_definition]
p = sub, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = r.sub == p.sub && r.act == p.act
RBAC

基于角色的访问控制

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[role_definition]
g = _, _
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
#   如果请求主体(用户)属于策略主体(角色)
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

策略示例:

1
2
3
4
5
p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin 
RBAC with resource roles

用户、资源都可以具有角色(roles,或groups)

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[role_definition]
g = _, _
g2 = _, _
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act

策略示例:

1
2
3
4
5
6
7
p, alice, data1, read
p, bob, data2, write
p, data_group_admin, data_group, write
 
g, alice, data_group_admin
g2, data1, data_group
g2, data2, data_group
RBAC with domains/tenants

对于不同的域(domain)/租户(tenant),用户可以具有不同的角色

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[request_definition]
r = sub, dom, obj, act
 
[policy_definition]
p = sub, dom, obj, act
 
[role_definition]
g = _, _, _
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act

策略示例:

1
2
3
4
5
6
p, admin, domain1, data1, read
p, admin, domain1, data1, write
p, admin, domain2, data2, read
p, admin, domain2, data2, write
g, alice, admin, domain1
g, bob, admin, domain2 
ABAC

基于属性的角色控制,也叫(Policy-Based Access Control)或CBAC(Claims-Based Access Control)

不同于常见的将用户通过某种方式关联到权限的方式,ABAC通过动态计算一个或一组属性是否满足某种条件来进行授权判断(可以编写简单的逻辑)。属性通常来说分为四类:

  1. 用户属性(如用户年龄)
  2. 环境属性(如当前时间)
  3. 操作属性(如读取)
  4. 对象属性(如一篇文章,又称资源属性)

理论上能够实现非常灵活的权限控制,几乎能满足所有类型的需求

举例来说,规则:允许所有班主任在上课时间自由进出校门,班主任是用户的角色熟悉,上课时间是环境属性,进出是操作属性,校门则是对象属性

ABAC的缺点是过于复杂,因此K8S在1.8版本引入RBAC

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = r.sub == r.obj.Owner
RESTful

支持以HTTP动词,以及/res/*, /res/:id这样的路径来描述操作和资源 

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
#                     通配符
m = r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)

策略示例:

1
2
3
4
5
6
7
p, alice, /alice_data/*, GET
p, alice, /alice_data/resource1, POST
 
p, bob, /alice_data/resource2, GET
p, bob, /bob_data/*, POST
 
p, cathy, /cathy_data, (GET)|(POST)
Deny-override 

支持allow、deny,deny可以覆盖allow

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act, eft
 
[role_definition]
g = _, _
 
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
 
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

策略示例:

1
2
3
4
5
6
7
p, alice, data1, read, allow
p, bob, data2, write, allow
p, data2_admin, data2, read, allow
p, data2_admin, data2, write, allow
p, alice, data2, write, deny
 
g, alice, data2_admin
Priority

策略规则可以支持优先级

模型示例:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act, eft
 
[role_definition]
g = _, _
 
[policy_effect]
e = priority(p.eft) || deny
 
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

策略示例:

1
2
3
4
5
6
7
8
9
10
11
12
p, alice, data1, read, allow
p, data1_deny_group, data1, read, deny
p, data1_deny_group, data1, write, deny
p, alice, data1, write, allow
 
g, alice, data1_deny_group
 
p, data2_allow_group, data2, read, allow
p, bob, data2, read, deny
p, bob, data2, write, deny
 
g, bob, data2_allow_group
PERM元模型

在线编辑器:

在Casbin中,访问控制模型被抽象到基于PERM元模型的CONF文件中。

PERM元模型包含四大要素: https://casbin.org/editor/ 可以用于编写模型、策略。

  1. Request:关于访问请求的信息,简单的请求是主体、操作、资源构成的元组: r = {sub, action, resource}
  2. Policy:构成一个访问规则,例如管理员可以读取用户信息,同样由三元组构成: p = {sub, action, resource}
  3. Matchers:描述请求和策略如何匹配。最简单的方式是相等判断: m = r.sub == p.sub && r.action == p.action && r.resource == p.resource 。对于一个请求来说,所有使用Matcher的Policy都会产生一个值,记为 p.eft
  4. Effect:联合/化简(reducing)匹配某个请求的策略,并得到最终的结果(允许或拒绝访问),例如: e = some(p.eft == allow)

下图展示了基于PERM的模型对一个请求进行授权的过程:

perm 下面的文件是本节示例的完整模型定义(基于ACL):

Conf
1
2
3
4
5
6
7
8
9
10
11
[request_definition]
r = sub, obj, act
 
[policy_definition]
p = sub, obj, act
 
[policy_effect]
e = some(where (p.eft == allow))
 
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

对于该模型定义,定义授权规则的策略文件(模型是定义了公式,策略则是将具体的主体、操作、资源带入公式计算)可以如下: 

Conf
1
2
p, alice, data1, read
p, bob, data2, write

如果我们想允许admin执行任何操作,需要修改matcher: 

Conf
1
2
3
[matchers]
m = r.sub == admin || (r.sub == p.sub && r.obj == p.obj && r.act == p.act)
# 如果太长,可以  \ 结尾换行

要将上述模型从ACL改为ABAC风格,我们可以在matcher中访问资源的属性: 

Conf
1
2
3
4
5
6
[matchers]
m = r.obj.owner == r.sub && (r.sub == p.sub && r.obj == p.obj && r.act == p.act)
    # 如果对象所有者是请求主体
 
m = r.obj == p.obj && r.act == p.act || r.obj in ('data2', 'data3')
# Golang版本的Casbin还支持 in 操作符

可以看到,PERM元模型足够灵活,可以让我们以简单模型开始,并按需切换到复杂的授权模型。

编程
起步

首先,从模型文件、策略文件创建Enforcer:

Go
1
e, _ := casbin.NewEnforcer("path/to/model.conf", "path/to/policy.csv")

判断一个Request是否可以被允许: 

Go
1
2
3
4
5
6
7
8
9
10
// 请求信息
sub := "alice"
obj := "data1"
act := "read"
 
if res := e.Enforce(sub, obj, act); res {
    // 允许访问
} else {
    // 拒绝访问
}
策略管理

Casbin提供了两套管理策略(Permission)的API:

  1. Management API:底层API,完全支持Casbin策略管理
  2. RBAC API:更加友好的,编写RBAC模型的API,是Managlement API的子集
Management API
Subject管理
Go
1
2
3
4
5
// 获取所有主体
allSubjects := e.GetAllSubjects()
 
// 获取指定的命名的策略中的所有主体
allNamedSubjects := e.GetAllNamedSubjects("p")
Object管理
Go
1
2
3
4
// 获取所有资源
allObjects := e.GetAllObjects()
// 获取指定的命名的策略中所有的资源
allNamedObjects := e.GetAllNamedObjects("p")
Action管理
Go
1
2
3
// 获取所有操作
allActions := e.GetAllActions()
allNamedActions := e.GetAllNamedActions("p")
Role管理
Go
1
2
3
// 获取所有角色
allRoles = e.GetAllRoles()
allNamedRoles := e.GetAllNamedRoles("g")
Policy管理 
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 获取所有策略(授权规则)
policy = e.GetPolicy()
 
// 获取过滤后的策略,可以根据字段进行过滤   字段索引 字段值
filteredPolicy := e.GetFilteredPolicy(0, "alice")
 
// 获取命名的策略中的所有授权规则
namedPolicy := e.GetNamedPolicy("p")
 
filteredNamedPolicy = e.GetFilteredNamedPolicy("p", 0, "bob")
 
 
// 获取所有角色继承规则
groupingPolicy := e.GetGroupingPolicy()
filteredGroupingPolicy := e.GetFilteredGroupingPolicy(0, "alice")
namedGroupingPolicy := e.GetNamedGroupingPolicy("g")
namedGroupingPolicy := e.GetFilteredNamedGroupingPolicy("g", 0, "alice")
 
 
// 判断指定的授权规则是否存在
hasPolicy := e.HasPolicy("data2_admin", "data2", "read")
hasNamedPolicy := e.HasNamedPolicy("p", "data2_admin", "data2", "read")
 
// 添加一个授权规则
added := e.AddPolicy("eve", "data3", "read")
 
// 添加若干
rules := [][] string {
                []string {"jack", "data4", "read"},
                []string {"katy", "data4", "write"},
                []string {"leyo", "data4", "read"},
                []string {"ham", "data4", "write"},
        }
 
areRulesAdded := e.AddPolicies(rules)
 
// 添加到命名策略中
added := e.AddNamedPolicy("p", "eve", "data3", "read")
areRulesAdded := e.AddNamedPolicies("p", rules)
 
// 删除一个授权规则
removed := e.RemovePolicy("alice", "data1", "read")
 
// 删除多个授权规则
areRulesRemoved := e.RemovePolicies(rules)
//                            字段索引  字段值...
removed := e.RemoveFilteredPolicy(0, "alice", "data1", "read")
removed := e.RemoveNamedPolicy("p", "alice", "data1", "read")
areRulesRemoved := e.RemoveNamedPolicies("p", rules)
removed := e.RemoveFilteredNamedPolicy("p", 0, "alice", "data1", "read")
 
 
// 添加一个角色继承规则,如果规则已经存在,返回false
added := e.AddGroupingPolicy("group1", "data2_admin")
 
areRulesAdded := e.AddGroupingPolicies(rules)
added := e.AddNamedGroupingPolicy("g", "group1", "data2_admin")
areRulesAdded := e.AddNamedGroupingPolicies("g", rules)
 
 
// 删除角色继承规则
removed := e.RemoveGroupingPolicy("alice", "data2_admin")
Function管理

你添加一个Go函数,并在编写规则时,使用该函数进行Match: 

Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func CustomFunction(key1 string, key2 string) bool {
    if key1 == "/alice_data2/myid/using/res_id" && key2 == "/alice_data/:resource" {
        return true
    } else if key1 == "/alice_data2/myid/using/res_id" && key2 == "/alice_data2/:id/using/:resId" {
        return true
    } else {
        return false
    }
}
 
func CustomFunctionWrapper(args ...interface{}) (interface{}, error) {
    key1 := args[0].(string)
    key2 := args[1].(string)
 
    return bool(CustomFunction(key1, key2)), nil
}
 
e.AddFunction("keyMatchCustom", CustomFunctionWrapper)
RBAC API
Role管理
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 获取具有角色的用户
res := e.GetRolesForUser("alice")
 
// 判断用户是否具有角色
res := e.HasRoleForUser("alice", "data1_admin")
 
// 为用户添加角色
e.AddRoleForUser("alice", "data2_admin")
 
// 为用户删除角色
e.DeleteRoleForUser("alice", "data1_admin")
// 删除用户的所有角色
e.DeleteRolesForUser("alice")
 
// 删除一个角色
e.DeleteRole("data2_admin")
 
 
 
// 获取用户具有的隐式特权,不同于GetRolesForUser,该函数会同时
// 返回所有间接得到的角色(因为角色之间可以有继承关系)
//
// 例如:
//   g, alice, role:admin             alice属于admin
//   g, role:admin, role:user         admin属于user
// 该方法会返回 ["role:admin", "role:user"]
e.GetImplicitRolesForUser("alice")
 
 
// 获取用户的特权,不同于GetPermissionsForUser,该函数会同时
// 返回来自用户所属角色的特权
e.GetImplicitPermissionsForUser("alice")
Permission管理
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 删除一个特权(操作)
e.DeletePermission("read")
 
// 为用户或角色添加一个特权
e.AddPermissionForUser("bob", "read")
 
// 为用户删除一个特权
e.DeletePermissionForUser("bob", "read")
 
// 删除用户的全部特权
e.DeletePermissionsForUser("bob")
 
 
// 查询用户的特权
e.GetPermissionsForUser("bob")
 
 
// 查看用户是否具有指定的特权
e.HasPermissionForUser("alice", []string{"read"})
策略持久化

在Casbin中,策略存储以适配器的形式实现。你可以使用适配器的 LoadPolicy()来加载策略规则,使用 SavePolicy()来保存规则。

所有可用的适配器:https://casbin.org/docs/en/adapters#supported-adapters

接口
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
type Adapter interface {
    // 加载所有策略到model中
    LoadPolicy(model model.Model) error
    // 保存所有策略
    SavePolicy(model model.Model) error
 
    // 添加一个策略到后端存储,作为自动保存特性的一部分
    AddPolicy(sec string, ptype string, rule []string) error
    // 从后端存储删除一个策略,作为自动保存特性的一部分
    RemovePolicy(sec string, ptype string, rule []string) error
    // 从后端存储删除匹配的策略规则,作为自动保存特性的一部分
    RemovFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error
}
 
 
// 建模访问控制模型
type Model map[string]AssertionMap
 
type AssertionMap map[string]*Assertion
 
type Assertion struct {
    Key    string
    Value  string
    Tokens []string
    Policy [][]string
    RM     rbac.RoleManager
}
 
var sectionNameMap = map[string]string{
    "r": "request_definition",
    "p": "policy_definition",
    "g": "role_definition",
    "e": "policy_effect",
    "m": "matchers",
}
使用适配器
Go
1
2
3
4
5
6
7
8
import (
    "github.com/casbin/casbin"
    "github.com/casbin/casbin/file-adapter"
)
 
a := fileadapter.NewAdapter("examples/basic_policy.csv")
// 从适配器,而非文件加载策略
e := casbin.NewEnforcer("examples/basic_model.conf", a)
Etcd适配器

Github地址:https://github.com/sebastianliu/etcd-adapter

Go
1
2
3
4
5
6
7
8
9
import (
    "github.com/sebastianliu/etcd-adapter"
    "github.com/casbin/casbin"
)
 
a := etcdadapter.NewAdapter([]string{"http://127.0.0.1:2379"}, "casbin_policy_test")
 
e := casbin.NewEnforcer("rbac_model.conf", a)
e.LoadPolicy()
角色管理器

角色管理器用于管理RBAC角色层次(用户-角色、角色-角色映射)。角色管理器可以从Casbin策略文件,或者第三方数据源提取角色数据。除了默认角色管理器,都是out-of-tree的。 

接口
Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package rbac
 
type RoleManager interface {
    // 清空所有数据,重置到初始状态
    Clear() error
    // 在两个角色之间添加继承关系。domain是角色的前缀
    AddLink(name1 string, name2 string, domain ...string) error
    // 解除两个角色之间的继承关系
    DeleteLink(name1 string, name2 string, domain ...string) error
    // 判断两个角色之间是否有继承关系
    HasLink(name1 string, name2 string, domain ...string) (bool, error)
    // 获取用户继承的角色列表
    GetRoles(name string, domain ...string) ([]string, error)
    // 获取继承某角色的用户列表
    GetUsers(name string, domain ...string) ([]string, error)
    PrintRoles() error
}
实践
TKE

腾讯的TKE项目使用Casbin实现了权限控制。相关代码位于auth-api和auth-controller中。

加载策略模型

可以先将字符串解析为Model对象,然后再创建Enforcer:

Go
1
2
3
m, err := model.NewModelFromString(authapi.DefaultRuleModel)
// SyncedEnforcer保持和文件或数据库同步
enforcer, err = casbin.NewSyncedEnforcer(m)
调试日志
Go
1
2
3
4
import casbinlog "github.com/casbin/casbin/v2/log"
 
casbinlog.SetLogger(&casbinlogger.WrapLogger{})
enforcer.EnableLog(true) 
策略持久化适配器

在创建auth-controller的ControllerContext时,会初始化适配器:

Go
1
2
3
4
5
6
7
8
9
10
adpt := util2.NewAdapter(client.AuthV1().Rules(), sharedInformers.Auth().V1().Rules().Lister())
 
func NewAdapter(ruleClient authv1client.RuleInterface, ruleLister authv1lister.RuleLister) *RestAdapter {
    adapter := &RestAdapter{
        ruleClient: ruleClient,
        lister:     ruleLister,
    }
 
    return adapter
}

可以猜测到,此适配器使用API Server的Lister接口,从Etcd中读取策略信息。

该适配器的实现:

Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
type RestAdapter struct {
    ruleClient authv1client.RuleInterface
    lister     authv1lister.RuleLister
}
 
 
func (a *RestAdapter) LoadPolicy(model model.Model) error {
    // 加载所有Rule资源
    rules, err := a.lister.List(labels.Everything())
    if err != nil {
        return fmt.Errorf("list all rules failed: %v", err)
    }
 
    for _, rule := range rules {
        a.loadPolicy(rule, model)
    }
 
    return nil
}
 
// 将自定义资源转换为文本,然后从文本解析出策略
// V0 - V6是策略规则可能的参数,一般没有这么多参数
func (a *RestAdapter) loadPolicy(rule *authv1.Rule, model model.Model) {
    casRule := rule.Spec
    lineText := casRule.PType
    if casRule.V0 != "" {
        lineText += ", " + casRule.V0
    }
    if casRule.V1 != "" {
        lineText += ", " + casRule.V1
    }
    if casRule.V2 != "" {
        lineText += ", " + casRule.V2
    }
    if casRule.V3 != "" {
        lineText += ", " + casRule.V3
    }
    if casRule.V4 != "" {
        lineText += ", " + casRule.V4
    }
    if casRule.V5 != "" {
        lineText += ", " + casRule.V5
    }
    if casRule.V6 != "" {
        lineText += ", " + casRule.V6
    }
 
    persist.LoadPolicyLine(lineText, model)
}
 
// 将内存中的策略保存到Etcd,保存为若干Rule资源
func (a *RestAdapter) SavePolicy(model model.Model) error {
    // 删除老数据
    err := a.destroy(context.Background())
    if err != nil {
        return err
    }
 
    var rules []authv1.Rule
 
    for ptype, ast := range model["p"] {
        for _, line := range ast.Policy {
            rules = append(rules, ConvertRule(ptype, line))
        }
    }
 
    for ptype, ast := range model["g"] {
        for _, line := range ast.Policy {
            rules = append(rules, ConvertRule(ptype, line))
        }
    }
 
    return a.savePolicy(context.Background(), rules)
}
 
func (a *RestAdapter) savePolicy(ctx context.Context, rules []authv1.Rule) error {
    for _, rule := range rules {
        if _, err := a.ruleClient.Create(ctx, &rule, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
            return err
        }
    }
    return nil
}
定制函数

TKE使用的默认模型是:

Conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[request_definition]
r = sub, dom, obj, act
 
[policy_definition]
p = sub, dom, obj, act, eft
 
[role_definition]
# 请求主体, 策略主体, 租户
g = _, _, _
 
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
 
[matchers]
m = g(r.sub, p.sub, r.dom) && keyMatchCustom(r.obj, p.obj) && keyMatchCustom(r.act, p.act)

其中keyMatchCustom是自定义的函数:

Go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
enforcer.AddFunction("keyMatchCustom", CustomFunctionWrapper)
 
func CustomFunctionWrapper(args ...interface{}) (interface{}, error) {
    key1 := args[0].(string)
    key2 := args[1].(string)
 
    return keyMatchCustomFunction(key1, key2), nil
}
 
// 目标匹配规则
//   /project:123/cluster:456 匹配 /project:*/cluster:456
//   registry:123/* 匹配 registry:123/456
func keyMatchCustomFunction(key1 string, key2 string) bool {
    key1 = strings.ToLower(key1)
    key2 = strings.ToLower(key2)
 
    key2 = strings.Replace(key2, "*", ".*", -1)
 
    re := regexp.MustCompile(`(.*):[^/]+(.*)`)
    i := 2
    for {
        if !strings.Contains(key2, "/:") {
            break
        }
 
        key2 = re.ReplaceAllString(key2, "$1[^/]+$2")
        i = i + 1
    }
 
    return casbinutil.RegexMatch(key1, "^"+key2+"$")
}
角色管理器

TKE使用了自定义的角色管理器:

Go
1
2
3
rm := domainrolemanager.NewRoleManager(10)
enforcer.SetRoleManager(rm)
enforcer.StartAutoLoadPolicy(cfg.CasbinReloadInterval)

该角色管理器来自github.com/dovics/domain-role-manager

← 2020年春节快乐
通过WebAssembly扩展Envoy →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Related Posts

  • 通过自定义资源扩展Kubernetes
  • Etcd学习笔记
  • Go语言数据库编程
  • 扩展Istio
  • Goland知识集锦

Recent Posts

  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
  • A Comprehensive Study of Kotlin for Java Developers
  • 背诵营笔记
  • 利用LangChain和语言模型交互
  • 享学营笔记
ABOUT ME

汪震 | Alex Wong

江苏淮安人,现居北京。目前供职于腾讯云,专注容器方向。

GitHub:gmemcc

Git:git.gmem.cc

Email:gmemjunk@gmem.cc@me.com

ABOUT GMEM

绿色记忆是我的个人网站,域名gmem.cc中G是Green的简写,MEM是Memory的简写,CC则是我的小天使彩彩名字的简写。

我在这里记录自己的工作与生活,同时和大家分享一些编程方面的知识。

GMEM HISTORY
v2.00:微风
v1.03:单车旅行
v1.02:夏日版
v1.01:未完成
v0.10:彩虹天堂
v0.01:阳光海岸
MIRROR INFO
Meta
  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
Recent Posts
  • Investigating and Solving the Issue of Failed Certificate Request with ZeroSSL and Cert-Manager
    In this blog post, I will walk ...
  • A Comprehensive Study of Kotlin for Java Developers
    Introduction Purpose of the Study Understanding the Mo ...
  • 背诵营笔记
    Day 1 Find Your Greatness 原文 Greatness. It’s just ...
  • 利用LangChain和语言模型交互
    LangChain是什么 从名字上可以看出来,LangChain可以用来构建自然语言处理能力的链条。它是一个库 ...
  • 享学营笔记
    Unit 1 At home Lesson 1 In the ...
  • K8S集群跨云迁移
    要将K8S集群从一个云服务商迁移到另外一个,需要解决以下问题: 各种K8S资源的迁移 工作负载所挂载的数 ...
  • Terraform快速参考
    简介 Terraform用于实现基础设施即代码(infrastructure as code)—— 通过代码( ...
  • 草缸2021
    经过四个多月的努力,我的小小荷兰景到达极致了状态。

  • 编写Kubernetes风格的APIServer
    背景 前段时间接到一个需求做一个工具,工具将在K8S中运行。需求很适合用控制器模式实现,很自然的就基于kube ...
  • 记录一次KeyDB缓慢的定位过程
    环境说明 运行环境 这个问题出现在一套搭建在虚拟机上的Kubernetes 1.18集群上。集群有三个节点: ...
  • eBPF学习笔记
    简介 BPF,即Berkeley Packet Filter,是一个古老的网络封包过滤机制。它允许从用户空间注 ...
  • IPVS模式下ClusterIP泄露宿主机端口的问题
    问题 在一个启用了IPVS模式kube-proxy的K8S集群中,运行着一个Docker Registry服务 ...
  • 念爷爷
      今天是爷爷的头七,十二月七日、阴历十月廿三中午,老人家与世长辞。   九月初,回家看望刚动完手术的爸爸,发

  • 6 杨梅坑

  • liuhuashan
    深圳人才公园的网红景点 —— 流花山

  • 1 2020年10月拈花湾

  • 内核缺陷触发的NodePort服务63秒延迟问题
    现象 我们有一个新创建的TKE 1.3.0集群,使用基于Galaxy + Flannel(VXLAN模式)的容 ...
  • Galaxy学习笔记
    简介 Galaxy是TKEStack的一个网络组件,支持为TKE集群提供Overlay/Underlay容器网 ...
TOPLINKS
  • Zitahli's blue 91 people like this
  • 梦中的婚礼 64 people like this
  • 汪静好 61 people like this
  • 那年我一岁 36 people like this
  • 为了爱 28 people like this
  • 小绿彩 26 people like this
  • 杨梅坑 6 people like this
  • 亚龙湾之旅 1 people like this
  • 汪昌博 people like this
  • 彩虹姐姐的笑脸 24 people like this
  • 2013年11月香山 10 people like this
  • 2013年7月秦皇岛 6 people like this
  • 2013年6月蓟县盘山 5 people like this
  • 2013年2月梅花山 2 people like this
  • 2013年淮阴自贡迎春灯会 3 people like this
  • 2012年镇江金山游 1 people like this
  • 2012年徽杭古道 9 people like this
  • 2011年清明节后扬州行 1 people like this
  • 2008年十一云龙公园 5 people like this
  • 2008年之秋忆 7 people like this
  • 老照片 13 people like this
  • 火一样的六月 16 people like this
  • 发黄的相片 3 people like this
  • Cesium学习笔记 90 people like this
  • IntelliJ IDEA知识集锦 59 people like this
  • 基于Kurento搭建WebRTC服务器 38 people like this
  • Bazel学习笔记 37 people like this
  • PhoneGap学习笔记 32 people like this
  • NaCl学习笔记 32 people like this
  • 使用Oracle Java Mission Control监控JVM运行状态 29 people like this
  • 基于Calico的CNI 27 people like this
  • Ceph学习笔记 27 people like this
  • Three.js学习笔记 24 people like this
Tag Cloud
ActiveMQ AspectJ CDT Ceph Chrome CNI Command Cordova Coroutine CXF Cygwin DNS Docker eBPF Eclipse ExtJS F7 FAQ Groovy Hibernate HTTP IntelliJ IO编程 IPVS JacksonJSON JMS JSON JVM K8S kernel LB libvirt Linux知识 Linux编程 LOG Maven MinGW Mock Monitoring Multimedia MVC MySQL netfs Netty Nginx NIO Node.js NoSQL Oracle PDT PHP Redis RPC Scheduler ServiceMesh SNMP Spring SSL svn Tomcat TSDB Ubuntu WebGL WebRTC WebService WebSocket wxWidgets XDebug XML XPath XRM ZooKeeper 亚龙湾 单元测试 学习笔记 实时处理 并发编程 彩姐 性能剖析 性能调优 文本处理 新特性 架构模式 系统编程 网络编程 视频监控 设计模式 远程调试 配置文件 齐塔莉
Recent Comments
  • qg on Istio中的透明代理问题
  • heao on 基于本地gRPC的Go插件系统
  • 黄豆豆 on Ginkgo学习笔记
  • cloud on OpenStack学习笔记
  • 5dragoncon on Cilium学习笔记
  • Archeb on 重温iptables
  • C/C++编程:WebSocketpp(Linux + Clion + boostAsio) – 源码巴士 on 基于C/C++的WebSocket库
  • jerbin on eBPF学习笔记
  • point on Istio中的透明代理问题
  • G on Istio中的透明代理问题
  • 绿色记忆:Go语言单元测试和仿冒 on Ginkgo学习笔记
  • point on Istio中的透明代理问题
  • 【Maven】maven插件开发实战 – IT汇 on Maven插件开发
  • chenlx on eBPF学习笔记
  • Alex on eBPF学习笔记
  • CFC4N on eBPF学习笔记
  • 李运田 on 念爷爷
  • yongman on 记录一次KeyDB缓慢的定位过程
  • Alex on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • will on Istio中的透明代理问题
  • haolipeng on 基于本地gRPC的Go插件系统
  • 吴杰 on 基于C/C++的WebSocket库
©2005-2025 Gmem.cc | Powered by WordPress | 京ICP备18007345号-2