策略引擎 I — 声明式规则 (principal/action/resource/condition 四元组)
策略引擎 I — 声明式规则 (principal/action/resource/condition 四元组)
日期: 2026-09-25 阶段: Phase 4 - 自建 Agent 平台×求职冲刺 标签: #policy-engine #cedar #declarative-authz #policy-as-code
核心问题
P2 的 Day 53 建了风控网关(riskGateway),P3 的 Day 81 建了渐进式授权(authorize)。两者都能拦工具调用——但都是命令式硬编码:if (call.tool not in ALLOWED_TOOLS) deny()、switch (riskTier, trustLevel)。这套到 P4「自建 Agent 平台」尺度上有三个致命毛病:
- 规则散落在代码里,合规官读不懂、改不动。AML 的授权边界(提交 SAR 需 director 角色、跨境案强制人审)是业务/监管规则,却埋在 TypeScript 的
if里——每改一条要发版、过 code review,合规团队完全无法独立维护。 - 规则无法被分析。硬编码的
if-else链谁能证明「不存在一条路径让 junior 自动提交 SAR」?逻辑冲突、过度授权、规则空洞,全靠人脑 review。 - 每个 Agent 一套判据,必然漂移。P4 要管多个 Agent(调查 Copilot、SAR 起草、证据检索),各写各的
if必然不一致。
今天回答:怎么把授权从「写死在代码里的 if」升级成「声明式策略数据」? 锚定 AWS 的工业级答案——Amazon Bedrock AgentCore Policy(2026-03-03 GA,本日核实)选 Cedar 作策略语言。核心拆三件事:(A) principal/action/resource/condition 四元组凭什么是授权的最小完备表达;(B) 怎么从 Day 53/81 的命令式网关升级成声明式策略引擎;(C) 对照 AgentCore Policy + Cedar 的工程口径,确认本项目方向。
本篇是策略引擎 v1——声明式 DSL + 评估语义。事中拦截执行器(每次调用过判定)留 Day 104,Agent 注册表绑定策略留 Day 105。
关键内容
A. 四元组:principal × action × resource × condition 为何最小完备
Cedar 的核心抽象是:一条授权策略 = 一个 effect(permit/forbid)+ 一个三元域(who/what/which)+ 可选 condition(when/unless)。AWS 官方定义(AgentCore Policy core concepts, 2026-03):「Each policy specifies who (principal) can perform what action (tool invocation) on which resource (gateway) under what conditions. Policies are evaluated for every tool invocation request.」
为什么恰好是这四个维度、不多不少:
- principal(谁):发起调用的实体。AgentCore 落两类——
AgentCore::OAuthUser(从 JWT 的sub取,带 username/scope/role 标签)与AgentCore::IamEntity(从 IAM ARN 取,支持稳定principal ==匹配)。映射 AML:调查员、复核 director、SAR 起草 Agent,各是一个 principal,带角色/scope 标签。 - action(做什么):被请求的操作。AgentCore 把每个网关工具映射成一个 action(如
RefundTool___process_refund、本项目的submit_sar/hybrid_search/draft_sar)。这是关键——action 不是抽象动词,而是具体到工具名,与 Day 53 的ALLOWED_TOOLS白名单同构,但升级成可声明的命名实体。 - resource(对哪个对象):被作用的资源。AgentCore 用 Gateway ARN。本项目落「网关/工具集」粒度即可(v1 单网关)。
- condition(在什么条件下):
when {...}/unless {...}子句,对请求上下文做谓词判断——context.input.amount < 500、principal.getTag("role") == "director"。这是把 Day 81 的「金额 ≥$10,000 风险档 +1」「跨境强制人审」从switch搬进声明式条件的地方。
四元组的完备性论证:任何「在某情境下,某主体能否对某对象执行某操作」的授权问题,都能分解为 (principal, action, resource) 定位「这次请求落在哪」+ condition 约束「上下文是否满足」。少了 condition 就只能做粗粒度 RBAC(角色 × 操作),表达不了「金额 <$500 才放行」这类 ABAC(属性级)约束——而 AML 的合规规则绝大多数是属性级的(金额阈值、跨境标记、置信档)。Cedar 把 RBAC 与 ABAC 统一进同一个四元组,这是它比纯 RBAC(如 Day 53 白名单)表达力强的根本原因。
一条真实 Cedar 策略(AgentCore NL2Cedar 文档示例,2026-03):
permit(
principal is AgentCore::OAuthUser,
action == AgentCore::Action::"RefundTool___process_refund",
resource == AgentCore::Gateway::"arn:...:gateway/refund-gateway"
)
when {
principal.hasTag("username") &&
principal.getTag("username") == "refund-agent" &&
context.input.amount < 500
};
读法:允许 username 为 refund-agent 的 OAuth 用户,对 refund 网关,调用 process_refund 工具,当且仅当 退款金额 <$500。把「refund」换成「submit_sar」、「amount<500」换成「role==director && case.amount<CTR」,就是本项目的 SAR 提交策略。
B. 从命令式网关升级到声明式策略引擎:评估语义
Day 53 的网关是命令式:拦截器内写 if (条件) deny(),规则就是控制流本身。声明式策略引擎反过来——规则是数据(一组策略),引擎是固定的评估器,对每次请求跑同一套评估算法。
本项目策略引擎 v1 的 DSL schema(TS 类型,复刻 Cedar 四元组语义):
type Effect = 'permit' | 'forbid'
interface Policy {
id: string
effect: Effect
principal: { role?: string; scope?: string; id?: string } // 省略=匹配任意("All users")
action: string // 工具名,如 'submit_sar';'*' 匹配任意
resource: string // 网关/工具集 id;v1 单网关用 '*'
when?: Condition[] // 全部为真才匹配(AND)
annotation?: string // 监管依据,可读,写审计
}
// Condition:对 request context 的属性级谓词
type Condition =
| { ctx: string; op: 'lt'|'lte'|'gt'|'gte'|'eq'|'neq'; value: number|string|boolean }
| { ctx: string; op: 'in'|'nin'; value: (string|number)[] }
| { ctx: string; op: 'exists' }
评估算法——default-deny + forbid-wins(Cedar 三铁律,AgentCore 文档 2026-03 逐字:「everything is denied by default / forbid always wins / at least one permit required」):
evaluate(request{principal, action, resource, context}, policies) -> Decision:
matched = [p for p in policies if matches(p, request)] # 四元组+condition 全中
forbids = [p for p in matched if p.effect == 'forbid']
permits = [p for p in matched if p.effect == 'permit']
if forbids 非空: return DENY(forbids[0].id) # ① forbid 优先,任一命中即拒
if permits 非空: return ALLOW(permits[0].id) # ② 至少一条 permit 才放行
return DENY('default-deny: no matching permit') # ③ 无 permit → 默认拒绝
matches(p, request) = principal 字段子集匹配(未声明的字段视为通配)∧ action 匹配(含 *)∧ resource 匹配 ∧ when 全部条件对 context 求值为真。
反直觉洞察①(forbid-wins 不是冗余,是合规的安全阀):default-deny 下「没 permit 就拒」,那为何还要 forbid?AWS 文档点破:「Even if someone writes a broader permit policy, the forbid policy takes precedence」。在 AML 里这是救命的——合规团队写一条粗 permit「允许所有调查员调用 SAR 工具集」图省事,某天又加一条 forbid「junior 角色禁止提交 SAR」。forbid-wins 保证这条禁令永远盖过那条宽 permit,无论二者书写顺序、无论谁后来又加了更宽的 permit。把「监管红线(绝不可逾越的禁止)」用 forbid 表达、把「日常授权」用 permit 表达,红线就有了不被误开的结构性保证。这是命令式
if-else给不了的——if链的语义依赖书写顺序,谁手滑把宽if放前面就漏了。
声明式相对命令式的可分析性红利(AgentCore Cedar analysis, 2026-03):因策略是数据,引擎能用自动推理静态检出「always-allow(无条件限制的过宽 permit)」和「always-deny(无例外的 forbid 把工具锁死)」——「identify policies that always allow... or always deny... helping ensure policies implement intended access control」。命令式 if 链做不到这种全路径分析。
C. 对照 AgentCore Policy:声明式策略引擎的工程要件
把本项目 v1 与 AgentCore Policy(2026-03-03 GA)逐项对齐,确认要件没漏:
| 要件 | AgentCore Policy (2026-03 GA) | 本项目策略引擎 v1 |
|---|---|---|
| 策略语言 | Cedar(开源,AWS 自研,专为授权) | TS DSL 复刻 Cedar 四元组语义 |
| 评估语义 | default-deny + forbid-wins + ≥1 permit | 同(B 节算法逐条复刻) |
| principal | OAuthUser(JWT sub+tags) / IamEntity(ARN) | role/scope/id 字段(对齐 Day 51 OAuth scope) |
| action 粒度 | 每工具一 action(Tool___method) | 工具名(对齐 Day 53 ALLOWED_TOOLS) |
| condition | when{}/unless{} 对 context 求值 | when[] 属性级谓词(对齐 Day 81 金额/跨境) |
| schema 校验 | 从网关工具自动生成 Cedar schema,建策略时校验 | 复用 toolRegistry.ts 的 inputSchema 派生合法 action/ctx 字段 |
| 静态分析 | 自动推理检 always-allow/always-deny | v1 用单测覆盖关键路径(无自动推理) |
| NL2Cedar | 自然语言→Cedar(neuro-symbolic 反馈环) | v1 不做(合规官直接写 DSL JSON;NL 留后续) |
| 评估位置 | Gateway,LLM/agent 代码之外 | 网关层,模型推理外(核心,见反洞察②) |
反直觉洞察②(策略必须在 LLM 之外评估才可信——这是整个设计的命门):直觉上「让 Agent 自己检查权限」最方便(prompt 里写「提交 SAR 前先确认你有权限」)。AWS 安全博客(Why AgentCore chose Cedar, 2026-03)一句话戳穿:「The LLM's plan is the thing you can't trust—it can't be responsible for enforcing its own constraints.」 把策略集中在网关,是「a single checkpoint the LLM can't circumvent; one that's auditable and can be verified independently of the application code」。换言之——让被监管对象自己执行对自己的约束,等于没约束(prompt injection / 幻觉一冲就破,这正是 Day 52 MCPTox 证伪的)。声明式策略引擎的全部价值,建立在「它是模型推理之外的确定性数据驱动评估器」之上:相同请求永远同样判定(「identical requests always produce the same authorization decision, regardless of evaluation order or system state」),与 LLM 的概率性输出彻底解耦。这与 Day 53「网关不能是又一个 LLM judge」、Day 81「两道闸第二道才是合规的那道」是同一条命门的三次重申——P4 把它从「硬编码确定性代码」再升一级到「声明式确定性数据」,可读性、可分析性、可独立维护性全部到位,但确定性 + 协议外 这条底线一寸不让。
设计要点/决策表
| 要点 | 决策 | 理由 |
|---|---|---|
| 授权表达 | principal×action×resource×condition 四元组 | RBAC+ABAC 统一,覆盖 AML 属性级规则(金额/跨境/置信) |
| 规则形态 | 声明式策略数据,非命令式 if | 合规官可读可改、可静态分析、不发版 |
| 评估语义 | default-deny + forbid-wins + ≥1 permit | Cedar 三铁律;forbid 给监管红线结构性保证 |
| 红线表达 | 监管禁止用 forbid,日常授权用 permit | forbid-wins 保证红线不被宽 permit 误开(反洞察①) |
| 评估位置 | 网关层、LLM 推理之外、确定性 | 被监管对象不能自我执行约束(反洞察②) |
| action 粒度 | 一工具一 action,复用 toolRegistry 名 | 与 Day 53 白名单同构,schema 可派生 |
| 与 Day 53/81 关系 | 策略引擎是二者的声明式抽象,非另起炉灶 | 一套判据,避免多 Agent 规则漂移 |
| v1 范围 | DSL + 评估语义 + 单测 | NL2Cedar、自动推理分析、事中执行器留后续 |
对本项目的落地
- 新建
src/agent/policy/policyEngine.ts:导出Policy/Condition类型(A/B 节 schema)、evaluate(request, policies): Decision(B 节 default-deny+forbid-wins 算法,纯函数、确定性,无时钟/网络/LLM)、以及内置策略集AML_POLICIES: Policy[](把 Day 53 的ALLOWED_TOOLS/HIGH_RISK_TOOLS与 Day 81 的金额/跨境/角色规则翻译成声明式 forbid/permit 条目,每条带annotation标监管依据如「BSA 31 CFR 1010.311 CTR」)。 - action 复用
toolRegistry.ts:策略里的action字段直接取McpToolSpec.name;condition 的ctx字段合法集从工具inputSchema.properties派生(复刻 AgentCore「从网关工具自动生成 Cedar schema」),保证策略不会引用不存在的参数——这是把 Day 53「PARAM_RULES 复用 evalChecks」升级为「策略 schema 由工具 schema 派生」。 - 不替换 Day 53/81,而是抽象其上:
policyEngine.evaluate()成为 Day 53riskGateway内 PDP 决策的新实现——网关骨架(PEP 拦截点、三段式、审计 wrapper)不变,把命令式if判定换成evaluate(req, AML_POLICIES)。Day 81 的「风险×信任矩阵」中与监管恒定的硬约束(高风险/不可逆恒 SYNC_APPROVE、低置信恒人审)翻译成 forbid 策略;信任度相关的松绑留在authorize()命令式层(信任是运行时聚合量,不适合写死进静态策略)——职责切分:策略引擎管「监管恒定的能/不能」,授权层管「信任驱动的松/紧」。 - 诚实标注:
policyEngine.ts头注写明——v1 是 Cedar 四元组语义的 TS 教学复刻(DSL JSON + default-deny/forbid-wins 评估),不是 Cedar 引擎本身(无 Cedar parser、无自动推理分析、无 NL2Cedar);评估为纯函数确定性、静态仓库可跑可测;事中执行器(每次工具调用过evaluate)见 Day 104、Agent 绑定策略集见 Day 105。
参考资料
- AWS — Policy in Amazon Bedrock AgentCore: Core concepts:principal(OAuthUser/IamEntity)/action(每工具一 action)/resource(Gateway)/condition 四元组;policy engine default-deny + forbid-wins;Cedar schema 从工具自动生成;Cedar validation/analysis (2026-03)
- AWS — Writing policies in natural language (NL2Cedar):permit/forbid 效果;三铁律逐字「everything denied by default / forbid always wins / at least one permit required」;
when{}condition 语法、数值/字符串/布尔/存在性谓词;refund-agent <$500 完整 Cedar 示例 (2026-03) - AWS Security Blog — Why Policy in Amazon Bedrock AgentCore chose Cedar for securing agentic workflows:「LLM's plan is the thing you can't trust」「single checkpoint the LLM can't circumvent, auditable independently」「deterministic guarantees, identical requests same decision」「O(n) bounded evaluation」 (2026-03)
- AWS — Policy in Amazon Bedrock AgentCore is now generally available:Policy GA 2026-03-03,13 区域 (2026-03)
- 本仓库
src/agent/mcp/riskGateway.ts(Day 53 命令式 PDP,本篇声明式化目标)、src/aml/authorization.ts(Day 81 风险×信任矩阵)、src/agent/mcp/toolRegistry.ts(action 名/condition schema 来源)、src/aml/typology.ts(CTR_THRESHOLD_CENTS锚定 condition 阈值)(2026-06)
SOTA 检查 (2026-06-11)
- 声明式 policy-as-code(Cedar)治理 agent-工具授权在 2026-06 是工业级 SOTA:AgentCore Policy 已 GA(2026-03-03,本日核实,非任务卡所述 2025-12 preview——已升级,执行当周须再确认),13 区域可用;Cedar 因「可读、可分析、可自动推理、与代码解耦」被 AWS 选为 agent 授权语言。方向与 SOTA 对齐。
- 「策略在 LLM 之外评估」是 2026 agent 安全的硬共识:AWS 安全博客(2026-03)、OWASP Agentic Top 10(2025-12-10,ASI01 行为劫持列首危)、Day 53 引的零信任框架三方一致——把 LLM 视为不可信主体,强制点必须在编排边界(工具调用处),不在模型层。
- Cedar vs OpenFGA/OPA 之争未定但 Cedar 在 agent 域领先:Day 81 SOTA 检查已记 WorkOS 等用 FGA(OpenFGA)做 agent 细粒度授权;2026-06 看,AgentCore 押注 Cedar(强在 schema 校验 + 自动推理),OpenFGA 强在关系图(ReBAC)。本项目动作集小、规则属性级,Cedar 四元组足够;若 P4 后期资源关系复杂化(案件—调查员—团队层级),再评估 ReBAC 引擎,回填本笔记。
- NL2Cedar(自然语言→策略)是 2026 新方向但有坑:AgentCore 用 neuro-symbolic 反馈环把英文转 Cedar,文档反复警告「natural language is flexible, but precision is essential」并列 5 类常见错误(模糊 principal/主观条件如「金额合理时」)。本项目 v1 让合规官直接写结构化 DSL(避开 NL 歧义),把 NL2Cedar 列为后续——但须警惕:NL 生成的策略必须经 schema 校验 + 静态分析才能上线,不能直接信任 LLM 产出的策略(否则又把信任交回不可信的 LLM)。
- 过时认知警示:「把授权写进系统提示 / 让 Agent 自查权限」「命令式 if-else 网关够用」在 P4 多 Agent 平台尺度已过时——前者被 Day 52 证伪,后者无法被合规官维护、无法静态分析、必然在多 Agent 间漂移。声明式 + 协议外 + 确定性是 2026-06 的工程下限。
- 待跟踪:Day 104 实装事中执行器时,复核 AgentCore Policy 的 ~50-150ms 评估延迟(本日另一来源数据)对「每次工具调用必过」的性能影响,以及是否需 Day 45 语义缓存思路缓存判定结果(注意:缓存授权判定有风险,context 变化即失效,须谨慎)。