Cedar是AWS在2023年开源的一种授权策略语言,名字来自阿拉斯加的雪松,定位是成为一个独立于具体产品的策略引擎。它解决的核心问题是:传统应用里权限判断逻辑往往散落在业务代码各处,if-else越写越多,改一个权限要发一次版,审计时也很难说清楚“某个人到底为什么能访问某个资源”。Cedar把这些判断统一抽象成策略文件,由专门的评估引擎执行,应用只需要问一句“允许还是拒绝”,把授权和业务彻底解耦。

Cedar的基本模型:主体、操作、资源与上下文
理解Cedar要先理解它的四元组模型。任何一次授权请求都会被拆解成四个部分:principal(谁在发起请求)、action(想做什么操作)、resource(作用在哪个对象上)以及context(请求附带的额外信息,比如来源IP、当前时间)。Cedar评估器拿这四元组去遍历策略集合,最终输出允许、拒绝或者无法判定三种结果。
实体在Cedar里通过命名空间加类型加标识符来表示,例如MyApp::User::"alice"表示命名空间MyApp下类型User中ID为alice的用户。这种结构化的实体表示方式,让策略可以直接引用具体对象,也能配合实体类型系统做静态检查。Cedar自带一个验证器,可以在策略写入时检查引用的类型和属性是否存在,把大量低级错误挡在部署之前。
与常见的RBAC框架不同,Cedar原生支持把实体组织成层级结构。比如用户属于某个组,文档存在某个文件夹里,通过in操作符就能表达“属于某个组的成员”或“位于某个目录下的资源”这类关系,不需要为层级授权额外建表或写递归查询。
策略语法详解:从结构到条件表达式
Cedar的策略分为两个作用域:permit表示允许,forbid表示拒绝。一条最简单的策略长这样:
permit ( principal == MyApp::User::"alice", action == MyApp::Action::"view", resource == MyApp::Document::"doc-123" );
这条策略的含义一目了然:alice可以对doc-123文档执行view操作。等号可以换成in,比如principal in MyApp::Group::"editors"就表示编辑组的所有成员都匹配,这就是典型的基于角色控制。当多条策略同时匹配时,Cedar遵循“forbid优先”原则:只要有一条forbid命中,结果就是拒绝,无论有多少条permit允许,这和AWS IAM的显式拒绝逻辑一致。
策略的主体部分还可以用when和unless子句追加条件。when里的表达式必须为真策略才生效,unless则相反。看一个带条件的例子:
permit (
principal in MyApp::Group::"editors",
action == MyApp::Action::"edit",
resource in MyApp::Folder::"annual-reports"
)
when {
context.authentication_level == "strong" &
amp;&
context.current_time >= resource.available_from
};
上面策略表达的是:编辑组成员要修改年度报告目录下的文件,必须通过了强认证,而且当前时间要晚于资源的开放时间。条件表达式支持常见的比较运算、布尔运算、字符串操作,还能访问实体属性,例如principal.department == resource.owner.department这种属性间比较,实现了基于属性(ABAC)的灵活控制。需要修正一点,上面的连接符应写作单个&&,Cedar支持的逻辑运算符包括&&、||和!,语法上和主流语言保持一致。
Cedar还提供策略模板机制,用?principal和?resource作为占位符,一份模板可以实例化出多条具体策略,适合“每个用户只能删除自己创建的内容”这类批量场景,避免策略文件无限膨胀。
如何在项目中集成Cedar
Cedar以Rust实现,官方同时提供Rust、Java、Swift等语言的SDK,还有一个独立的命令行工具cedar-cli用于本地验证和测试。以最常见的场景为例,应用在收到请求后,把四元组传给Cedar引擎做判断:
use cedar_policy::{Engine, Entities, Request, PolicySet};
fn main() -> Result<()> {
// 加载策略集合,通常来自数据库或配置文件
let policies: PolicySet = r#"
permit (
principal in MyApp::Group::"editors",
action == MyApp::Action::"edit",
resource in MyApp::Folder::"reports"
);
"#.parse()?;
// 加载实体数据,描述用户、组、资源之间的关系
let entities: Entities = r#"
[
{
"uid": {"__entity": {"type": "MyApp::User", "id": "alice"}},
"attrs": {},
"parents": [{"__entity": {"type": "MyApp::Group", "id": "editors"}}]
}
]
"#.parse()?;
let request = Request::new(
("MyApp::User", "alice").into(),
("MyApp::Action", "edit").into(),
("MyApp::Folder", "reports").into(),
serde_json::json!({}).into(),
);
let engine = Engine::new(policies, entities);
let answer = engine.is_authorized(&request)?;
println!("决策结果: {:?}", answer.decision());
Ok(())
}
这段代码展示了完整流程:解析策略、加载实体、构造请求、调用is_authorized拿到决策。实体数据可以用JSON描述,parents字段声明层级关系,运行时Cedar会自动沿着层级匹配in条件。实际项目中建议把策略存在数据库并做版本管理,每次变更前先用验证器跑一遍类型检查。
如果不想自己搭建评估服务,AWS的Amazon Verified Permissions就是托管的Cedar服务,控制台里可以直接编写和测试策略,按授权请求次数计费,适合不想维护策略引擎基础设施的团队。开源方案则可以把Cedar嵌入到现有的鉴权微服务中,策略评估延迟通常在毫秒级,性能完全够用。
使用Cedar的常见坑与建议
第一个坑是forbid的条件写法。forbid策略的主体四元组匹配部分不支持使用属性条件,如果你写了forbid (principal, action, resource == ...)配合复杂条件,要确保条件放在when子句里,并且理解forbid命中即终判的特性,避免一条过宽的forbid把整个功能锁死。
第二个坑是实体数据的一致性。Cedar策略里引用的属性和层级关系,完全依赖传入的实体数据,如果同步程序漏掉了某个组的父子关系,对应的permit就不会生效。建议把实体数据构建放在一个统一模块里,并编写集成测试覆盖关键角色和资源组合。
第三个建议是充分利用官方的cedar-cli做本地测试。它提供validate命令检查策略与Schema的一致性,提供authorize命令模拟授权请求,可以在CI流水线里对策略文件跑一轮全量断言,把权限回归问题消灭在发布前。Schema是用JSON格式描述实体类型、操作和属性定义的文件,写好Schema之后,策略编辑器还能提供自动补全,体验会好很多。
总体来看,Cedar把策略语言设计得足够简洁,普通人不需要懂编程也能读懂一条策略在说什么,这对需要业务方参与权限设计的团队非常有价值。如果你的系统正在被散落的权限判断代码折磨,把授权逻辑迁移到Cedar上是值得认真评估的方向。
Cedar策略语言AWS Verified Permissions权限控制修改时间:2026-09-04 06:04:38