基于属性的策略(ABAC)介绍与使用场景
聊到权限管理,很多人第一反应是RBAC——角色一二三,权限一二三,简单粗暴。但说白了,RBAC是静态的。你今天给张三绑了个"管理员"角色,他走到哪儿都是管理员。可在云环境里,事情没那么简单。
我最早接触ABAC是在一个多租户的SaaS项目里。客户要求:同一个API,A租户只能读自己的数据,B租户只能写自己的数据,还不能互相看见。你想想看,如果用RBAC,得给每个租户建一套角色,再给每个角色绑一堆策略。维护量直接爆炸。后来换成ABAC,用属性(租户ID、资源标签、操作时间)动态判断,几百行的策略就搞定了。
嗯,这就是ABAC的魅力——Attribute-Based Access Control。它不是基于"你是谁",而是基于"你、资源、环境都有哪些特征"。
什么是ABAC
ABAC把权限判断拆成四个要素:
- 主体属性 —— 谁在请求?比如用户ID、部门、安全级别
- 资源属性 —— 要访问什么?比如资源类型、标签、所属项目
- 环境属性 —— 在什么场景下?比如时间、IP范围、网络区域
- 动作 —— 想做什么?读取、写入、解密、删除
策略就是一条规则:当主体属性、资源属性和环境属性同时满足某些条件时,允许或拒绝某个动作。我习惯把这种策略叫"带条件的通行证",而不是"固定角色的门票"。
ABAC vs RBAC:直观对比
| 对比维度 | RBAC(基于角色) | ABAC(基于属性) |
|---|---|---|
| 策略粒度 | 角色级别,粗放 | 属性级别,细到每个请求 |
| 变更效率 | 改角色或绑角色 | 改策略里的属性条件 |
| 动态响应 | 差,需要重新分配 | 好,条件变了权限自动变 |
| 多租户场景 | 每个租户一套角色 | 一套策略+租户属性字段 |
| 可读性 | 直观(角色名带含义) | 需要理解属性逻辑 |
| 扩展性 | 角色数量暴增 | 属性维度可控 |
这张表不是为了说谁好谁坏。实际项目中我经常混合使用:大方向用RBAC兜底,细粒度用ABAC补刀。效果还不错。
使用场景:什么时候必须上ABAC?
我总结了三个典型场景,几乎每个都能对应到我踩过的坑:
场景一:多租户隔离
前面提过的SaaS平台。租户数据混在同一个桶里,但靠资源标签来区分。策略写成:只有resource.tag.tenantId == user.attr.tenantId 才允许读。你想想看,如果每个租户都开一个桶,运维成本直接上天。
场景二:临时提升权限
有一次生产故障,需要紧急登录一台敏感服务器。平时只有运维经理能进。用ABAC,我在策略里加了一条:如果当前时间在"事件窗口"内,并且请求来源是公司VPN,并且有运维Leader审批的ticket,则允许临时访问。故障修复后,把时间条件移掉,权限自动收回。全程不用改角色绑定。
场景三:基于资源归属的动态控制
比如一个项目组只能操作自己项目的KMS密钥。每个密钥打了project:alpha标签,用户的IAM角色也有project:alpha属性。策略里写死标签匹配,新增项目时只需要给密钥打新标签,给用户加新属性,策略一行不用改。我曾经因为没这么做,导致每次新项目上线都要发PR改策略,累得要命。
ABAC在AWS KMS中的实战
KMS把ABAC玩出了花——通过条件键(Condition Keys)来写属性策略。最常用的是kms:RequestTag和kms:ResourceTag。
举个例子:只允许用户解密那些env=prod标签的密钥。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:ResourceTag/env": "prod"
}
}
},
{
"Effect": "Deny",
"Action": "kms:Decrypt",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"kms:ResourceTag/env": "prod"
}
}
}
]
}
你看,策略里没有写死任何用户或密钥ARN。只要密钥上打了env=prod标签,用户就能解密。哪天密钥退休了,去掉标签,权限自然消失。
ABAC策略评估的完整流程
理解策略引擎是怎么"思考"的,能帮你写出更靠谱的策略。下面这张图描述了从请求发起到底层决策的完整链路:
流程并不复杂:提取三个维度的属性,喂给策略引擎做条件匹配。如果有一条策略同时命中了主体、资源、环境的所有条件,并且是Allow,再检查是否有Deny,没有则放行。任何条件不满足,直接走隐式Deny。
设计ABAC策略的几个关键点
- 属性选择别贪多 —— 我刚入坑时恨不得把几十个标签全写进策略,结果策略又臭又长,出问题都查不清。后来我只选3-5个核心属性:租户ID、环境类型、数据分级、操作时间。够用就行。
- 警惕权限爆炸 —— ABAC其实很容易不小心让用户拿到不该有的权限。比如你写了个条件"资源标签包含project",但用户自己可以给资源打标签。那他还不是想访问啥就访问啥?解决方案:把标签的创建权限收拢,或者用
aws:ResourceTag配合aws:RequestTag做双向校验。 - 性能方面 —— ABAC评估比RBAC多一步属性提取和条件匹配。好在AWS的IAM和KMS后端做得很成熟,我还没遇到过因为ABAC导致明显延迟的情况。但如果你的策略里有几百个条件键,建议做一次压力测试。
最佳实践总结
- 从小范围开始 —— 先在一两个密钥或桶上测试ABAC策略,跑通后再推广到生产环境。
- 用条件键做合理约束 —— 比如
kms:CallerAccount可以限制只有在自己的账号内才能操作密钥,防止跨账号误用。 - 日志审计不可少 —— 启用CloudTrail和CloudWatch,对每次ABAC判断记录日志。我曾经排查一次权限故障,全靠日志里"Implicit Deny"的提示,定位到是资源标签少了个字母。
- 定期审核属性定义 —— 公司的组织架构和项目名会变,对应的标签体系也得跟着变。我每季度会过一次所有在用标签,淘汰掉废弃的,统一命名规范。
ABAC不是什么万能钥匙,但它确实能在动态、细粒度的场景里帮你省掉大量繁琐的权限维护工作。我个人习惯是:能用属性解决的,绝不硬编码;能用策略解决的,绝不绑角色。嗯,大概就是这样,下一种思路。