1个不稳定版本
0.1.0 | 2023年3月12日 |
---|
#481 在 认证
39KB
531 行
oslo-policy
oslo.policy规则文件的解析器和评估引擎。
如果你在Rust中实现类似于OpenStack的服务,这个crate可能会对你很有趣。如果你的服务与OpenStack无关,有更好的策略引擎可供选择。这个引擎是为了与OpenStack的最高合理兼容性而设计的。
用法
策略规则通常存储在磁盘上的YAML或JSON文件中。使用你选择的I/O和反序列化库将该文件加载到HashMap中。(下面的示例使用std和serde_yaml。)然后使用这个库将规则解析到RuleSet对象中
let buf = std::fs::read("/etc/myservice/policy.yaml")?;
let rules = serde_yaml::from_bytes(&buf)?;
let mut ruleset = oslo_policy::RuleSet::new();
ruleset.add_rules(rules)?;
在处理请求时,你需要构造一个Request对象。至少,请求需要包含一个Token对象,该对象描述了与请求一起提供的令牌。理想情况下,你选择的OpenStack客户端库应该有一个实现了我们的Token特质的类型。一旦你有了一个Request对象,你就可以从RuleSet评估策略规则,并相应地生成HTTP响应。(下面的示例暗示使用Hyper实现请求处理器。)
use hyper::{Body, Request, Response, Server};
// in request handler:
let req = oslo_policy::Request::new(&token);
if !ruleset.evaluate("instance:create", &req) {
return Err(Response::builder().status(403).body("Forbidden").unwrap());
}
与参考实现的差异
这个库并没有复制参考实现的所有特性和行为。
故意的不可兼容性
这个库明确拒绝了参考实现中我们认为危险的一些回退行为。
- 在参考实现中,空字符串是一个有效的规则,表示“接受所有”。这在意外的地方是一个糟糕的行为,所以这个库会通过解析错误拒绝空规则字符串。如果你想“接受所有”,请显式地写出
@
。 - 参考实现支持指定规则作为默认规则。为什么这很危险:当服务的新版本中添加了新的API端点,并且操作员没有更新策略以匹配新版本时,新的端点将受到默认规则的影响,无论这个规则多么保守或自由。这个库采取了安全的默认做法,在请求名称下未定义规则时返回false。
有意不在此范围内
以下功能将永远不会在这个库中实现。添加这些功能的PR将被拒绝。
- 参考实现支持一种替代规则语法,其中规则不是以字符串格式编码,如
"(rule:foo and rule:bar) or rule:qux"
,而是在字符串列表的列表中,如[["rule:foo", "rule:bar"], ["rule:qux"]]
。这种格式在参考实现中被描述为旧格式,并且不再广泛使用。始终使用字符串格式。 - 参考实现支持当规则文件在磁盘上更改时自动重新加载规则文件。此实现不支持这一点,因为这会引入很多复杂性。大多数人不会想要这个额外的复杂性,因为他们无论如何都会在更改配置后重启(特别是在容器化环境中)。
- 参考实现允许在检查的左侧使用任意的Python字面量表达式(只要不使用空格或冒号),例如
["foo", "bar"]:%(role_name)s
在技术上是一个有效的检查,尽管它并不符合你的预期。实际上,它检查目标对象的属性role_name
是否存在并包含字符串值['foo', 'bar']
,因为检查的左侧被解析并再次通过Python的str()
运算符序列化。支持所有这些显然是荒谬的,我们不会这样做。我们只支持具有纯字符串字面量的检查,例如'foo':%(name)s
或"foo":%(name)s
。 - 参考实现提供了一个名为
http
的预定义检查器,用于将策略决策委托给可通过HTTP访问的不同服务。实现这样的检查器不在此库的范围内。如果需要,应用程序可以使用Enforcer::add_check
注册自定义的trait Checker
实现。
目前不在此范围内
如果可以证明有实际用途,以下功能将来可能会在这个库中实现。请在发送PR之前提出一个讨论您用例的问题。
- 我们在检查左侧的字符串字面量的解析中不支持转义序列。参考实现允许
'foo\nbar':%(name)s
或"foo\"bar":%(name)s
,但此库当前在字符串字面量中遇到转义序列时返回解析错误。 - 当在检查右侧插入目标对象属性时,我们只支持一个覆盖整个右侧的单个字符串插值。例如,
"foo":%(name)s
是有效的,但42:%(count)d
和"foo_bar":%(id)s_%(name)s
是无效的,并且总是返回 false。
依赖关系
~0.3–0.8MB
~19K SLoC