3. ABAC 与策略引擎:基于属性的访问控制,以及 XACML/OPA 等策略引擎实战

好,咱们今天聊点硬核的——ABAC。说实话,我在刚入行那会儿,大部分系统还在用 RBAC(基于角色的访问控制)。角色嘛,无非就是管理员、运营、普通用户,分得清清楚楚。但后来项目越做越复杂,你会发现一个问题:角色根本不够用。

举个例子。一个文档系统里,同样是“编辑”角色,有的人只能改自己写的文档,有的人能改部门文档,有的人能改全公司文档。你总不能为了这个场景,拆出十个角色吧?那维护成本就炸了。这时候,ABAC 就派上用场了。

3.1 什么是 ABAC?

ABAC,全称 Attribute-Based Access Control,基于属性的访问控制。说白了,它不看你“是谁”,而是看“你有什么属性”以及“资源有什么属性”,再加上“当前环境怎么样”。

我习惯把 ABAC 的决策模型拆成三部分:

  • 主体属性:用户是谁?部门、职级、安全等级、地理位置。
  • 资源属性:要访问的东西是什么?文档密级、创建者、所属项目。
  • 环境属性:现在是什么情况?时间、IP 段、设备类型、网络环境。

然后策略引擎根据这些属性,算出一个“允许”或“拒绝”的结果。你想想看,这比硬编码角色灵活太多了。

核心公式: 访问决策 = f(主体属性, 资源属性, 环境属性, 策略规则)

3.2 ABAC vs RBAC:什么时候该换?

我经常被问到:“老师,我们该用 RBAC 还是 ABAC?” 我的回答是:别盲目追新。RBAC 在 80% 的场景下够用,而且简单。但如果你遇到下面这些情况,就该考虑 ABAC 了:

维度 RBAC ABAC
角色数量 少,通常 < 50 可以很少,靠属性组合
策略粒度 粗粒度(角色级别) 细粒度(属性级别)
动态性 低,角色变更麻烦 高,属性变化即生效
维护成本 低,适合稳定业务 中高,需要策略管理工具
典型场景 企业内部系统、CMS 云平台、微服务、数据湖

嗯,这里要注意:不要为了用 ABAC 而用 ABAC。我曾经见过一个团队,只有三个角色,硬上了 OPA,结果策略写了一堆,反而比 RBAC 还难维护。合适才是最好的。

3.3 策略引擎:XACML 与 OPA

聊完理论,咱们看看落地工具。目前主流的两大策略引擎是 XACML 和 OPA。我个人的经验是:XACML 偏传统企业级,OPA 偏云原生。

3.3.1 XACML

XACML(eXtensible Access Control Markup Language)是一个老牌的 OASIS 标准。它定义了一套完整的架构,包括:

  • PEP(策略执行点):拦截请求,问 PDP 能不能放行。
  • PDP(策略决策点):根据策略算结果。
  • PAP(策略管理点):写策略的地方。
  • PIP(策略信息点):获取属性值的来源。

它的策略是用 XML 写的。说实话,可读性一般,但胜在标准成熟,金融、政府项目里很常见。

我的建议: 如果你的团队有专门的策略管理员,且对 XML 不排斥,XACML 是个稳妥的选择。但如果是开发团队自己维护,我建议你往下看 OPA。

3.3.2 OPA(Open Policy Agent)

OPA 是我近两年用得最多的策略引擎。它用一门叫 Rego 的声明式语言写策略。你想想看,用代码写权限规则,比 XML 舒服太多了。

一个简单的 OPA 策略示例:

package example.authz

default allow = false

allow {
    input.method == "GET"
    input.path == "/api/v1/documents"
    input.user.role == "viewer"
}

allow {
    input.method == "POST"
    input.path == "/api/v1/documents"
    input.user.role == "editor"
    input.resource.owner == input.user.id
}

这段规则什么意思?第一,GET 请求,viewer 角色就能看。第二,POST 请求,只有文档的 owner 才能编辑。你看,逻辑清晰,而且很容易测试。

避坑指南: 我曾经在项目中把 OPA 策略写得过于复杂,一个规则嵌套了七八层。结果出问题的时候,调试起来非常痛苦。记住:策略也要遵循“单一职责”,一个规则只做一件事。

3.4 实战:用 OPA 实现 ABAC

咱们来点实际的。假设你有一个微服务架构,每个服务都需要做权限校验。传统做法是在每个服务里写 if-else,但那样太耦合了。用 OPA,你可以把策略抽出来,做成一个独立的策略服务。

架构图如下:

OPA 策略决策流程 用户/客户端 业务服务 (PEP) OPA (PDP) 属性数据源 (PIP) 请求 查询决策 拉取属性 允许/拒绝 响应 说明: 1. 业务服务作为 PEP,拦截请求后向 OPA 查询决策。 2. OPA 作为 PDP,根据策略和属性数据计算决策结果。

具体实现步骤:

  1. 部署 OPA:作为一个独立的 HTTP 服务运行,或者用 sidecar 模式挂载到每个服务旁边。
  2. 编写 Rego 策略:把 ABAC 规则写成 Rego 文件,加载到 OPA 中。
  3. 业务服务集成:在每个需要鉴权的 API 入口,调用 OPA 的 /v1/data 接口,传入主体、资源、环境属性。
  4. 属性数据源对接:OPA 可以从 Redis、数据库、甚至 HTTP API 拉取属性数据。

我的经验: 属性数据源(PIP)往往是整个 ABAC 系统最容易被忽视的环节。属性不准,策略再牛也没用。我建议把属性管理做成一个独立服务,保证数据一致性。

3.5 策略管理的最佳实践

最后,分享几个我在项目中踩过的坑和总结的经验:

  • 策略版本控制:策略也是代码,必须进 Git。我曾经见过有人直接在 OPA 的 API 里改策略,结果改错了回滚不了,那叫一个惨。
  • 策略测试:Rego 支持写单元测试。每次改策略,先跑测试再上线。别偷懒。
  • 性能监控:OPA 的决策延迟一般在毫秒级,但如果策略复杂或者属性查询慢,会拖垮整个服务。建议加个超时和熔断。
  • 审计日志:每次决策都要记录:谁、什么时间、访问了什么、结果是什么。出了事好追溯。

我曾经犯过的错: 有一次我把所有策略写在一个大文件里,结果一个规则出了问题,整个鉴权都挂了。后来我改成按模块拆分策略文件,每个模块独立加载,互不影响。记住:隔离性不仅在代码里重要,在策略里同样重要。

好了,ABAC 和策略引擎的内容就聊到这儿。核心就三句话:用属性代替角色,用策略引擎代替硬编码,用 Rego 代替 XML。你回去可以拿一个小项目试试手,感受一下 ABAC 的灵活度。