返回 AIPA 笔记
AIPA Day 103

策略引擎 I — 声明式规则 (principal/action/resource/condition 四元组)

策略引擎 I — 声明式规则 (principal/action/resource/condition 四元组)

2026-09-25
policy-enginecedardeclarative-authzpolicy-as-code

日期: 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 平台」尺度上有三个致命毛病:

  1. 规则散落在代码里,合规官读不懂、改不动。AML 的授权边界(提交 SAR 需 director 角色、跨境案强制人审)是业务/监管规则,却埋在 TypeScript 的 if 里——每改一条要发版、过 code review,合规团队完全无法独立维护。
  2. 规则无法被分析。硬编码的 if-else 链谁能证明「不存在一条路径让 junior 自动提交 SAR」?逻辑冲突、过度授权、规则空洞,全靠人脑 review。
  3. 每个 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 < 500principal.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 节算法逐条复刻)
principalOAuthUser(JWT sub+tags) / IamEntity(ARN)role/scope/id 字段(对齐 Day 51 OAuth scope)
action 粒度每工具一 action(Tool___method工具名(对齐 Day 53 ALLOWED_TOOLS
conditionwhen{}/unless{} 对 context 求值when[] 属性级谓词(对齐 Day 81 金额/跨境)
schema 校验从网关工具自动生成 Cedar schema,建策略时校验复用 toolRegistry.tsinputSchema 派生合法 action/ctx 字段
静态分析自动推理检 always-allow/always-denyv1 用单测覆盖关键路径(无自动推理)
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 permitCedar 三铁律;forbid 给监管红线结构性保证
红线表达监管禁止用 forbid,日常授权用 permitforbid-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 53 riskGateway 内 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。

参考资料

  1. 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)
  2. 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)
  3. 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)
  4. AWS — Policy in Amazon Bedrock AgentCore is now generally available:Policy GA 2026-03-03,13 区域 (2026-03)
  5. 本仓库 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.tsCTR_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 变化即失效,须谨慎)。