- 后端
- 认证鉴权
- 云原生
【免费下载链接】opa
Open Policy Agent (OPA) is an open source, general-purpose policy engine.
在 Open Policy Agent(OPA)的 Rego 语言中,default关键字用于为规则(rules)和函数(functions)提供默认值:当某个规则或函数在其余情况下均未定义(undefined)时,默认值就会被采用。它的核心价值在于"确定性"——让策略作者和调用方都能确信某个文档总是有值,从而无需在每个查询点都额外处理 undefined 的边界情况。阅读本文后,你将掌握default的完整语法约束、在访问控制(默认拒绝)与配置覆盖(override)两种典型场景下的实战写法,以及它作用于函数时的特殊规则。
为什么需要default:undefined 是 Rego 的常态
Rego 中的规则并非总是"有结果"。当规则体内没有任何条件成立、或引用了缺失的字段时,规则求值结果就是undefined。undefined 本身是 Rego 重要的设计特性(用于表达"没有信息"),但对策略的调用方和策略内部的其他规则来说,undefined 常常意味着需要额外的防御性处理。
default关键字解决的问题正是:"无论发生什么,这个文档都必须有一个值"。这一点在访问控制系统中尤为关键——**默认拒绝(default deny)**是安全领域的黄金法则:除非被显式允许,否则一律拒绝。
示例一:默认拒绝(Denying by default)
在default的示例集中,第一个例子演示了最典型的场景。策略代码如下(见 docs/docs/policy-reference/keywords/_examples/default/deny/policy.rego):
package play default allow := false allow if input.admin == true allow if { input.path[0] == "users" input.path[1] == input.user }分析这段策略:
default allow := false声明了allow文档的兜底值为false;- 两个
allow if规则分别描述了"管理员放行"和"访问自己的用户资源放行"两种显式授权条件; - 如果输入
input缺少admin字段、path字段格式不符(例如path为空数组),所有显式规则都求值为 undefined,此时default保证allow依然返回布尔值false。
该示例的说明(见 docs/docs/policy-reference/keywords/_examples/default/deny/intro.md)强调:策略的allow规则依赖input中的字段,如果任何字段缺失,allow应返回false而不是 undefined——这正是通过default关键字实现的,它让策略能够从容应对意外的数据格式,确保结果永远是布尔值。
在 docs/docs/policy-reference/keywords/_examples/default/deny/config.json 的 Playground 配置中,展示输入(showInput: true)而隐藏数据(showData: false);示例输入与期望输出如下:
- 输入
input.json:
{ "roles": [ "admin" ], "path": "/" }- 期望输出
output.json:
{ "allow": false }注意这个输入组合:roles数组包含admin,但策略检查的是input.admin(布尔字段)以及input.path的数组索引结构。input.path是字符串"/",input.path[0]对字符串取下标并不会等于"users",input.admin也不存在——两条显式规则都不成立,但allow仍返回确定的false,完美体现了"默认拒绝"的兜底价值。
示例二:用default函数实现覆盖(override)
第二个示例展示default与函数结合,实现"基础值 + 按条件覆盖"的经典模式。策略代码见 docs/docs/policy-reference/keywords/_examples/default/overrides/policy.rego:
package play default max_amount(_, _) := 1000 max_amount(overrides, role) := overrides[role] allow if { input.amount <= max_amount(data.overrides, input.role) }这里的逻辑:
default max_amount(_, _) := 1000为函数设定基础值:任何角色(参数用_通配)的默认额度上限都是 1000;- 显式定义的
max_amount(overrides, role) := overrides[role]负责从data.overrides中查表;只有当角色在表中存在时才命中; - 当角色查不到(
overrides[role]求值 undefined)时,default兜底返回 1000。
对应示例数据(见 docs/docs/policy-reference/keywords/_examples/default/overrides/data.json):
{ "overrides": { "staff": 10000 } }输入(见 docs/docs/policy-reference/keywords/_examples/default/overrides/input.json):
{ "amount": 3000, "role": "staff" }期望输出(output.json):
{ "allow": true }staff角色在覆盖表中存在,max_amount返回 10000,3000 <= 10000成立,因此allow为true。假如角色换成表中不存在的值(例如"guest"),显式函数定义会求值失败,default函数随即返回 1000——额度超过 1000 的请求就会被拒绝。示例说明(见 docs/docs/policy-reference/keywords/_examples/default/overrides/intro.md)点明了该模式的本质:处理 undefined 不只是为了调用方,更是策略内部自身逻辑的需求——default为函数提供基准情况(base case),在条件满足时被覆盖。
default的语法约束:只能绑定常量
default关键字并非可以随意使用,它的语法被严格限制。在官方语言指南 docs/docs/policy-language.md#default-keyword 中明确规定,使用default时规则语法必须为:
default <name> := <term>其中<term>可以是任何标量(scalar)、复合值(composite)或推导(comprehension)值,但不能是变量或引用(reference)。如果值是复合值,则其内部也不能包含变量或引用;唯一的例外是推导值——因为推导的结果永远不会是 undefined。
这一约束的工程意义很直接:default的值必须是"写死的"、与运行时输入无关的常量,它只服务于一个目的——当其他同名校规则全部未定义时,提供一个确定的、预先可知的回退结果。如果允许default引用外部文档,就可能出现"兜底值本身又依赖其他规则"的循环不确定性,反而违背了default的设计初衷。
default函数的三条硬性属性
default同样可以作用于函数,其值遵循与default规则相同的条件(必须为标量/复合/推导值、不能是变量或引用)。除此之外,default函数还必须满足以下三条属性(见 docs/docs/policy-language.md#L2138-L2143):
- 与同名函数具有相同的元数(arity)——即参数个数必须一致;
- 参数只能是普通变量(plain variables),不能是复合值(如
[x, y]这类模式匹配写法); - 参数名不得重复。
以上约束保证了default函数与同名显式函数在签名上完全对齐,调用方无需感知差异。
一个重要边界:undefined 参数仍会使函数求值失败
default函数还有一个容易被忽略的陷阱:如果调用时传入的任一参数本身是 undefined,函数依然会失败(连默认值都不会返回)。原因在于 Rego 的求值顺序——参数在函数被调用之前就会被求值,任何一个 undefined 参数都会在此刻中断求值(见 docs/docs/policy-language.md#L2145-L2149)。
这意味着default只能兜底"函数体内部的未定义",无法兜底"调用参数本身的未定义"。在实际策略中,若要防御参数 undefined,仍需在调用前使用input.x存在性检查、object.get或条件判断等手段先行处理。
从源码视角理解default的定位
从 OPA 源码结构看,default属于 Rego 语言的保留关键字集合,在 ast/ast.go 的关键字定义中即可找到它的踪迹。它在整个 Rego 关键字体系(if、contains、every、not、some等,完整列表见 docs/docs/policy-reference/keywords/)中承担的是"文档兜底值"这一单一职责:它不改变规则的匹配逻辑,只在所有同名校规则求值结果均为 undefined 时,为对应文档注入一个确定的常量值。
也正因如此,default与complete definitions(完整定义规则)搭配使用最为常见——即同名的多条规则分别描述不同的命中条件,default负责"都不命中时怎么办"。它与if关键字组合(如allow if { ... })是当前 Rego 风格中最简洁、最主流的写法,本文两个示例均采用这一组合,可直接在 OPA Playground 中运行验证。
实战要点小结
- 默认拒绝:
default allow := false+ 若干allow if ...显式授权规则,是访问控制策略的标准骨架,能确保allow永远是布尔值,调用方无需处理 undefined; - 配置覆盖:
default max_amount(_, _) := 1000这类"基础值函数"配合数据驱动的显式函数定义,可在策略内部优雅地实现"有配置用配置、无配置用默认"; - 常量约束:
default的值只能是标量、复合值或推导值,绝不能是变量或引用; - 函数签名对齐:
default函数必须与同名函数元数一致、参数为不重复的普通变量; - 参数 undefined 陷阱:
default函数无法兜底"调用参数本身 undefined"造成的求值失败,必要时需在调用前防御。
掌握了这些规则,你就能在 OPA 策略中写出"永远有答案"的确定性文档,让策略既安全又易于推理。
- 后端
- 认证鉴权
- 云原生
【免费下载链接】opa
Open Policy Agent (OPA) is an open source, general-purpose policy engine.
相关推荐
Regal 规则解析:default-over-else —— 用 Rego default 赋值替代 fallback else 兜底
Regal 规则解析:default over else —— 用 Rego default 赋值替代 fallback else 兜底 导读 在编写 Rego
后端认证鉴权云原生OPA/Rego 的 default 关键字实战:用默认函数值构建可覆盖的基准策略
OPA/Rego 的 default 关键字实战:用默认函数值构建可覆盖的基准策略 本篇文章围绕 Open Policy Agent(OPA)策略语言 Rego
后端认证鉴权云原生OPA Rego 关键字 contains 详解:用多值规则增量构建集合
OPA Rego 关键字 contains 详解:用多值规则增量构建集合 Rego 中的 contains 关键字用于在多值规则(multi value rul
后端认证鉴权云原生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考