ABAC 实现:基于属性的细粒度访问控制
ABAC(Attribute-Based Access Control)是 coomia-dip 三层权限模型的第二层,负责基于主体属性、资源属性和环境属性的组合条件来实现细粒度的访问控制。本文详解 ABAC 的属性模型、策略表达式引擎、8 种运算符的实现、条件评估的性能优化,以及与 RBAC 层和 ReBAC 层的协同工作机制。
Coomia发布于 2025年9月16日13 分钟阅读
分享本文Twitter / X
“系列:S6 平台工程 · 第 3 篇 | 难度:高级 | 阅读时间:18 分钟
ABAC 实现:基于属性的细粒度访问控制
#TL;DR
ABAC(Attribute-Based Access Control)是 coomia-dip 三层权限模型的第二层,负责基于主体属性、资源属性和环境属性的组合条件来实现细粒度的访问控制。本文详解 ABAC 的属性模型、策略表达式引擎、8 种运算符的实现、条件评估的性能优化,以及与 RBAC 层和 ReBAC 层的协同工作机制。
#1. ABAC 的核心思想
#1.1 从角色到属性的演进
RBAC 通过角色间接授权,但角色是静态的。ABAC 通过动态属性实现上下文感知的授权:
Code
+-------------------+ +-------------------+ +-------------------+
| 主体属性 | | 资源属性 | | 环境属性 |
| Subject Attrs | | Resource Attrs | | Environ Attrs |
+-------------------+ +-------------------+ +-------------------+
| - department | | - classification | | - time |
| - clearance_level | | - owner | | - ip_address |
| - location | | - sensitivity | | - device_type |
| - job_title | | - data_region | | - mfa_status |
| - certifications | | - retention_days | | - network_zone |
+-------------------+ +-------------------+ +-------------------+
\ | /
+----------------------+----------------------+
|
+----------------------------+
| ABAC Policy Engine |
| 8 种运算符评估策略 |
+----------------------------+
|
ALLOW / DENY
#1.2 ABAC 的优势
| 维度 | RBAC | ABAC |
|---|---|---|
| 授权粒度 | 角色级 | 属性级 |
| 动态性 | 静态角色分配 | 实时属性评估 |
| 上下文感知 | 无 | 时间、IP、设备等 |
| 数据感知 | 无 | 分类级别、敏感度等 |
| 策略灵活性 | 角色组合 | 属性表达式任意组合 |
| 管理复杂度 | 低 | 中-高 |
#2. 属性模型设计
#2.1 属性分类体系
coomia-dip 将属性分为四大类,每类包含预定义和自定义属性:
Code
属性体系
├── 主体属性 (Subject Attributes)
│ ├── 身份属性: user_id, username, email
│ ├── 组织属性: department, team, division
│ ├── 安全属性: clearance_level, mfa_enabled
│ ├── 角色属性: roles[], groups[]
│ └── 自定义属性: certifications, specialties
│
├── 资源属性 (Resource Attributes)
│ ├── 分类属性: classification (A1-D)
│ ├── 所有权属性: owner, project, tenant
│ ├── 元数据属性: created_at, sensitivity
│ ├── 地理属性: data_region, storage_location
│ └── 自定义属性: retention_policy, audit_required
│
├── 操作属性 (Action Attributes)
│ ├── 操作类型: action_type (READ/WRITE/DELETE)
│ ├── 批量标识: is_bulk_operation
│ └── 导出标识: is_export
│
└── 环境属性 (Environment Attributes)
├── 时间属性: current_time, day_of_week
├── 网络属性: source_ip, network_zone
├── 设备属性: device_type, os, browser
├── 认证属性: auth_method, mfa_status
└── 会话属性: session_duration, last_activity
#2.2 属性数据模型
PROTOBUF
message AttributeDefinition {
string name = 1; // 属性名: "department"
string display_name = 2; // 显示名: "部门"
AttributeType type = 3; // STRING, INT, BOOL, LIST, MAP
AttributeCategory category = 4; // SUBJECT, RESOURCE, ENV
bool is_required = 5; // 是否必填
string default_value = 6; // 默认值
repeated string allowed_values = 7; // 允许的枚举值
string validation_regex = 8; // 验证正则
}
enum AttributeType {
STRING = 0;
INTEGER = 1;
BOOLEAN = 2;
DOUBLE = 3;
TIMESTAMP = 4;
STRING_LIST = 5;
STRING_MAP = 6;
}
message AttributeValue {
string name = 1;
oneof value {
string string_value = 2;
int64 int_value = 3;
bool bool_value = 4;
double double_value = 5;
google.protobuf.Timestamp timestamp_value = 6;
StringList list_value = 7;
StringMap map_value = 8;
}
}
#3. 策略表达式引擎
#3.1 策略结构
ABAC 策略由条件表达式树组成,支持 AND/OR/NOT 逻辑组合:
Code
PolicyRule
├── effect: ALLOW | DENY
├── target:
│ ├── subjects: {属性匹配条件}
│ ├── resources: {属性匹配条件}
│ └── actions: [READ, WRITE]
└── conditions:
└── LogicalExpression (AND/OR/NOT)
├── Condition (attribute, operator, value)
├── Condition (attribute, operator, value)
└── LogicalExpression (nested)
#3.2 策略 YAML 定义
YAML
policy:
id: "abac-dataset-access-001"
name: "数据集访问控制策略"
effect: ALLOW
target:
resource_types: [DATASET, OBJECT]
actions: [READ, EXPORT]
conditions:
operator: AND
children:
- attribute: "subject.clearance_level"
op: "gte"
value_ref: "resource.classification_level"
- operator: OR
children:
- attribute: "environment.network_zone"
op: "eq"
value: "INTERNAL"
- attribute: "subject.mfa_enabled"
op: "eq"
value: true
- attribute: "environment.current_time"
op: "between"
value: ["08:00", "20:00"]
obligations:
- type: MASK
condition:
attribute: "resource.sensitivity"
op: "gte"
value: "HIGH"
params:
mode: PARTIAL_MASK
fields: ["phone", "email", "ssn"]
- type: AUDIT
params:
level: DETAILED
#3.3 表达式评估引擎
Java
public class AbacExpressionEvaluator {
private final Map<String, OperatorEvaluator> operators;
public AbacExpressionEvaluator() {
operators = Map.of(
"eq", new EqualityOperator(),
"ne", new InequalityOperator(),
"gt", new GreaterThanOperator(),
"lt", new LessThanOperator(),
"gte", new GreaterOrEqualOperator(),
"lte", new LessOrEqualOperator(),
"in", new InSetOperator(),
"contains", new ContainsOperator(),
"matches", new RegexMatchOperator(),
"between", new BetweenOperator()
);
}
public boolean evaluate(LogicalExpression expr,
EvaluationContext ctx) {
if (expr.isLeaf()) {
return evaluateCondition(expr.getCondition(), ctx);
}
switch (expr.getLogicalOperator()) {
case AND:
return expr.getChildren().stream()
.allMatch(child -> evaluate(child, ctx));
case OR:
return expr.getChildren().stream()
.anyMatch(child -> evaluate(child, ctx));
case NOT:
return !evaluate(
expr.getChildren().get(0), ctx);
default:
throw new IllegalArgumentException(
"Unknown operator: "
+ expr.getLogicalOperator());
}
}
private boolean evaluateCondition(
Condition condition, EvaluationContext ctx) {
Object actualValue = ctx.resolveAttribute(
condition.getAttribute());
Object expectedValue = condition.isValueRef()
? ctx.resolveAttribute(condition.getValueRef())
: condition.getValue();
OperatorEvaluator op = operators.get(
condition.getOperator());
if (op == null) {
throw new PolicyEvaluationException(
"Unknown operator: " + condition.getOperator());
}
return op.evaluate(actualValue, expectedValue);
}
}
#4. 八种运算符详解
#4.1 运算符实现
Java
// 等于运算符
public class EqualityOperator implements OperatorEvaluator {
@Override
public boolean evaluate(Object actual, Object expected) {
if (actual == null) return expected == null;
return actual.equals(coerce(expected, actual.getClass()));
}
}
// 集合包含运算符
public class InSetOperator implements OperatorEvaluator {
@Override
public boolean evaluate(Object actual, Object expected) {
if (expected instanceof Collection<?> set) {
return set.contains(actual);
}
throw new PolicyEvaluationException(
"IN operator requires collection value");
}
}
// 正则匹配运算符
public class RegexMatchOperator implements OperatorEvaluator {
private final Cache<String, Pattern> patternCache =
Caffeine.newBuilder().maximumSize(1000).build();
@Override
public boolean evaluate(Object actual, Object expected) {
String pattern = expected.toString();
Pattern compiled = patternCache.get(pattern,
Pattern::compile);
return compiled.matcher(actual.toString()).matches();
}
}
// 范围运算符
public class BetweenOperator implements OperatorEvaluator {
@Override
public boolean evaluate(Object actual, Object expected) {
if (expected instanceof List<?> range
&& range.size() == 2) {
Comparable comp = (Comparable) actual;
Comparable min = (Comparable) coerce(
range.get(0), actual.getClass());
Comparable max = (Comparable) coerce(
range.get(1), actual.getClass());
return comp.compareTo(min) >= 0
&& comp.compareTo(max) <= 0;
}
throw new PolicyEvaluationException(
"BETWEEN requires [min, max] array");
}
}
#4.2 运算符兼容矩阵
Code
+----------+--------+-----+------+------+-----------+--------+
| 运算符 | String | Int | Bool | Time | List<Str> | Double |
+----------+--------+-----+------+------+-----------+--------+
| eq | Y | Y | Y | Y | Y | Y |
| ne | Y | Y | Y | Y | Y | Y |
| gt | Y | Y | - | Y | - | Y |
| lt | Y | Y | - | Y | - | Y |
| in | Y | Y | - | - | - | Y |
| contains | Y | - | - | - | Y | - |
| matches | Y | - | - | - | - | - |
| between | Y | Y | - | Y | - | Y |
+----------+--------+-----+------+------+-----------+--------+
#5. 属性解析与收集
#5.1 属性收集架构
Code
+-------------------+
| 请求到达 |
+-------------------+
|
+----v----+
| 属性 | 从多个来源收集属性
| 收集器 |
+----+----+
|
+----+----+----+----+
| | | | |
v v v v v
JWT LDAP DB Env Custom
属性 属性 属性 属性 属性
提取 查询 查询 感知 提供者
|
+----v----+
| 属性 | 合并、验证、缓存
| 上下文 |
+----+----+
|
+----v----+
| ABAC | 策略评估
| 评估器 |
+---------+
#5.2 属性收集器实现
Java
@Component
public class AttributeCollector {
private final List<AttributeProvider> providers;
private final Cache<String, Map<String, Object>> cache;
public EvaluationContext collectAttributes(
AuthenticationContext auth,
ResourceRef resource,
HttpServletRequest request) {
// 主体属性
Map<String, Object> subjectAttrs = new HashMap<>();
subjectAttrs.put("user_id", auth.getUserId());
subjectAttrs.put("roles", auth.getRoles());
subjectAttrs.put("department",
auth.getClaim("department"));
subjectAttrs.put("clearance_level",
auth.getClaim("clearance_level"));
subjectAttrs.put("mfa_enabled",
auth.isMfaAuthenticated());
// 资源属性(带缓存)
Map<String, Object> resourceAttrs = cache.get(
resource.getId(), () ->
loadResourceAttributes(resource));
// 环境属性
Map<String, Object> envAttrs = new HashMap<>();
envAttrs.put("current_time",
LocalTime.now().toString());
envAttrs.put("day_of_week",
LocalDate.now().getDayOfWeek().name());
envAttrs.put("source_ip",
request.getRemoteAddr());
envAttrs.put("network_zone",
classifyNetworkZone(request.getRemoteAddr()));
envAttrs.put("device_type",
parseDeviceType(
request.getHeader("User-Agent")));
// 自定义属性提供者
for (AttributeProvider provider : providers) {
provider.enhance(subjectAttrs, resourceAttrs,
envAttrs);
}
return new EvaluationContext(
subjectAttrs, resourceAttrs, envAttrs);
}
private String classifyNetworkZone(String ip) {
if (ip.startsWith("10.") || ip.startsWith("192.168."))
return "INTERNAL";
if (ip.startsWith("172."))
return "DMZ";
return "EXTERNAL";
}
}
#6. 性能优化
#6.1 短路评估
Java
// AND 表达式的短路评估
// 第一个 false 结果即可终止评估
public boolean evaluateAndExpression(
List<LogicalExpression> children,
EvaluationContext ctx) {
for (LogicalExpression child : children) {
if (!evaluate(child, ctx)) {
return false; // 短路:无需评估剩余条件
}
}
return true;
}
// OR 表达式的短路评估
// 第一个 true 结果即可终止评估
public boolean evaluateOrExpression(
List<LogicalExpression> children,
EvaluationContext ctx) {
for (LogicalExpression child : children) {
if (evaluate(child, ctx)) {
return true; // 短路:无需评估剩余条件
}
}
return false;
}
#6.2 策略编译优化
Java
public class CompiledPolicy {
// 预编译正则表达式
private final Map<String, Pattern> compiledPatterns;
// 预解析属性路径
private final Map<String, AttributePath> resolvedPaths;
// 预排序条件(成本低的优先评估)
private final List<Condition> sortedConditions;
public static CompiledPolicy compile(PolicyRule rule) {
CompiledPolicy compiled = new CompiledPolicy();
// 提取并编译所有正则表达式
for (Condition c : rule.getAllConditions()) {
if ("matches".equals(c.getOperator())) {
compiled.compiledPatterns.put(
c.getValue().toString(),
Pattern.compile(c.getValue().toString()));
}
}
// 按评估成本排序条件
compiled.sortedConditions = rule.getAllConditions()
.stream()
.sorted(Comparator.comparingInt(
CompiledPolicy::estimateCost))
.collect(Collectors.toList());
return compiled;
}
private static int estimateCost(Condition c) {
return switch (c.getOperator()) {
case "eq", "ne" -> 1;
case "gt", "lt", "gte", "lte" -> 2;
case "in" -> 3;
case "between" -> 4;
case "contains" -> 5;
case "matches" -> 10; // 正则最贵
default -> 5;
};
}
}
#6.3 性能基准
| 场景 | 平均耗时 | P99 耗时 |
|---|---|---|
| 简单 eq 条件 (1-2 个) | 0.1ms | 0.5ms |
| 复合 AND 条件 (3-5 个) | 0.3ms | 1.2ms |
| 嵌套 AND/OR (5-10 个) | 0.8ms | 3.5ms |
| 含正则匹配 | 1.5ms | 6.0ms |
| 含属性值引用 | 1.2ms | 5.0ms |
#7. 实际策略示例
#7.1 工作时间限制策略
YAML
policy:
id: "abac-time-restriction"
name: "工作时间数据访问限制"
effect: DENY
conditions:
operator: AND
children:
- attribute: "resource.classification"
op: "gte"
value: "B2"
- operator: OR
children:
- attribute: "environment.current_time"
op: "lt"
value: "08:00"
- attribute: "environment.current_time"
op: "gt"
value: "20:00"
#7.2 地理围栏策略
YAML
policy:
id: "abac-geo-fence"
name: "中国数据仅限境内访问"
effect: DENY
conditions:
operator: AND
children:
- attribute: "resource.data_region"
op: "eq"
value: "CN"
- attribute: "environment.source_country"
op: "ne"
value: "CN"
#7.3 安全级别匹配策略
YAML
policy:
id: "abac-clearance-match"
name: "安全级别匹配"
effect: ALLOW
conditions:
operator: AND
children:
- attribute: "subject.clearance_level"
op: "gte"
value_ref: "resource.classification_level"
- attribute: "subject.department"
op: "in"
value_ref: "resource.allowed_departments"
#8. 与 RBAC 和 ReBAC 的协同
#8.1 评估顺序
Code
请求 -> [RBAC 快速路径] -> [ABAC 条件细化] -> [ReBAC 关系检查]
| | |
快速放行/拒绝 条件评估 关系图遍历
| | |
+-----> DENY-overrides 合并 <-----------+
#8.2 ABAC 增强 RBAC 的典型模式
Code
场景: DATA_ANALYST 角色有 READ 权限 (RBAC ALLOW)
但需要 ABAC 进一步约束:
RBAC: DATA_ANALYST -> READ -> DATASET (ALLOW)
ABAC: + classification < C1 (条件 1)
+ network_zone = INTERNAL (条件 2)
+ time between 08:00-20:00 (条件 3)
最终: 仅当所有 ABAC 条件满足时才允许
#9. 策略管理
#9.1 策略版本控制
Code
策略变更流程:
1. 编写策略 YAML
2. 策略验证(语法、属性引用、类型检查)
3. 影响分析(模拟评估现有请求)
4. 审批流程
5. 灰度发布(先在测试环境验证)
6. 全量发布
7. 监控告警
#9.2 策略仿真
Python
from ontology_sdk import OntoPlatform
platform = OntoPlatform(endpoint="grpc://control-Layer:9090")
# 仿真策略评估
simulation = await platform.policy.simulate(
policy_id="abac-dataset-access-001",
test_cases=[
{
"subject": {"clearance_level": "B3",
"department": "engineering"},
"resource": {"classification": "B2",
"type": "DATASET"},
"environment": {"time": "10:00",
"network_zone": "INTERNAL"},
"expected": "ALLOW"
},
{
"subject": {"clearance_level": "A2",
"department": "marketing"},
"resource": {"classification": "C1",
"type": "DATASET"},
"environment": {"time": "22:00",
"network_zone": "EXTERNAL"},
"expected": "DENY"
}
]
)
for result in simulation.results:
print(f"Case: {result.case_id}, "
f"Decision: {result.decision}, "
f"Match Expected: {result.matches_expected}")
#10. 监控与告警
#10.1 ABAC 评估指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
| abac_evaluation_duration_ms | 评估耗时 | P99 > 10ms |
| abac_evaluation_total | 评估总次数 | - |
| abac_evaluation_deny_rate | 拒绝率 | > 40% |
| abac_attribute_resolution_errors | 属性解析错误 | > 0 |
| abac_policy_compilation_errors | 策略编译错误 | > 0 |
| abac_cache_hit_ratio | 属性缓存命中率 | < 60% |
#Key Takeaways
- 四类属性:主体、资源、操作、环境属性的组合提供了无限灵活的授权表达能力
- 8 种运算符覆盖等值比较、范围比较、集合判断、正则匹配等所有企业级需求
- 表达式树支持 AND/OR/NOT 嵌套组合,可表达任意复杂的策略逻辑
- 短路评估和策略编译优化确保亚毫秒级评估性能
- 属性值引用允许条件中引用其他属性(如 subject.clearance >= resource.classification)
- 策略仿真能力使策略变更安全可控
#Next Article
下一篇 S6-04: ReBAC 实现:基于关系的访问控制 将讲解如何借鉴 Google Zanzibar 论文,通过关系元组和关系图遍历实现基于关系的访问控制。
Tags: #ABAC #属性访问控制 #策略引擎 #运算符 #细粒度权限 #表达式引擎 #coomia-dip #平台工程 #安全 #Palantir