谷歌统一权限系统Zanzibar

摘要:
Google Zanzibar 权限服务

Zanzibar

1. 介绍

Zanzibar 是一个用于存储和评估访问控制列表的全球系统。 Zanzibar 提供统一的数据模型和配置语言,用于表达来自 Google 数百个客户端服务的广泛访问控制策略,包括Calendar、Cloud、 Drive、Maps、Photos、YouTube。

image-20210616114929969
  • Consistent

    保证用户操作ACL的因果顺序,提供外部一致性。

  • Flexible

    支持丰富的访问控制策略

  • Scalable

    数以万亿计的 ACL 条目,百万check qps

  • Fast

    95%请求小于10ms,99.9%请求小于100ms

  • Available

    过去 3 年 可用率99.999%

2. 模型

2.1 Relation Tuples

ACL 表示为关系元组的对象-用户或对象-对象关系的集合。组只是具有成员资格语义的 ACL。关系元组具有高效的二进制编码,我们使用方便的文本符号表示它们:

1
2
3
4
5
6
7
⟨*tuple*⟩ ::= ⟨*object*⟩‘#’⟨*relation*⟩‘@’⟨*user*⟩ 

⟨*object*⟩ ::= ⟨*namespace*⟩‘:’⟨*object id*⟩

⟨*user*⟩ ::= ⟨*user id*⟩ | ⟨*userset*⟩

⟨*userset*⟩ ::= ⟨*object*⟩‘#’⟨*relation*⟩

Simple Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// user1 has access on dir1
dir1#access@user1
// Have a look on the subjects concept page if you don't know the empty relation.
dir1#parent@(file1#)
// Everyone with access to dir1 has access to file1. This would probably be defined
// through a subject set rewrite that defines this inherited relation globally.
// In this example, we define this tuple explicitly.
file1#access@(dir1#access)
// Direct access on file2 was granted.
file2#access@user1
// user2 is owner of file2
file2#owner@user2
// Owners of file2 have access to it; possibly defined through subject set rewrites.
file2#access@(file2#owner)
image-20210617160709202

2.2 Consistency Model

Example Tuple Semantics
doc:readme#owner@10 User 10 is an owner of doc:readme
group:eng#member@11 User 11 is a member of group:eng
doc:readme#viewer@group:eng#member Members of group:eng are viewers of doc:readme
doc:readme#parent@folder:A#… doc:readme is in folder:A

2.3 Relation Configs

为了减少关系元组在表达关系上会出现很多条的关系组,客户端通过关系配置中的用户集重写规则来定义对象不可知的关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
name: "doc"
relation { name: "owner" }
relation {
name: "editor"
userset_rewrite {
union {
child { _this {} }
child { computed_userset { relation: "owner" } }
}}}
relation {
name: "viewer"
userset_rewrite {
union {
child { _this {} }
child { computed_userset { relation: "editor" } }
child { tuple_to_userset {
tupleset { relation: "parent" }
computed_userset {
object: $TUPLE_USERSET_OBJECT # parent folder
relation: "viewer" }}}
}}}

child 节点

  • _this

    返回所有用户集合,默认行为

  • computed_userset

    计算出一个新的用户集合,例如使 viewer 用户引用 editor 用户。

  • tuple_to_userset
    从输入对象中获取匹配的关系组,例如匹配其父级文件夹并继承其 viewer 权限

一个用户集表达式也可以由多个子表达式组成,通过并集、交集和排除等操作组合。

3. 架构

image-20210616233003291

3.1 aclserver

aclservers 是主要的服务器类型。它们被组织成集群并响应 Check、Read、Expand 和 Write 请求。请求到达集群中的任何服务器,并且该服务器根据需要将工作分发到集群中的其他服务器。这些服务器可以依次联系其他服务器以计算中间结果。初始服务器收集最终结果并将其返回给客户端。

3.2 watchserver

watchservers 是一种特殊的服务器类型,可以响应 Watch 请求。他们跟踪更改日志并近乎实时地为客户端提供命名空间更改流。

3.2 Storage

  • Namespace Config Storage

    命名空间配置存储在具有两个表的数据库中。一张表包含配置并以命名空间 ID 为键。另一个是配置更新的更改日志.

  • Relation Tuple Storage

    每个命名空间的关系元组存储在一个单独的数据库中,其中每一行都由主键(分片 ID、对象 ID、关系、用户、提交时间戳)标识。主键的排序允许我们查找给定对象 ID 或(对象 ID,关系)对的所有关系元组。
    我们的客户端根据其数据模式配置命名空间的分片。通常,分片 ID 仅由对象 ID 确定。在某些情况下,例如,当命名空间存储具有大量成员的组时,分片 ID 是根据对象 ID 和用户计算得出的。

  • change log

    用于存储 Watch API 的元组更新历史记录。主键是(更改日志分片 ID、时间戳、唯一更新 ID),其中每次写入随机选择一个更改日志分片。