Crates.io | oslo-policy |
lib.rs | oslo-policy |
version | 0.1.0 |
source | src |
created_at | 2023-03-12 22:23:20.120755 |
updated_at | 2023-03-12 22:23:20.120755 |
description | A parser and evaluation engine for oslo.policy rule files |
homepage | https://github.com/majewsky/rust-oslo-policy |
repository | |
max_upload_size | |
id | 808323 |
size | 50,312 |
A parser and evaluation engine for oslo.policy rule files.
This crate may be interesting for you if you are implementing an OpenStack-like service in Rust. If your service does not have anything to do with OpenStack, there are better policy engines to choose from. This engine is designed for the highest reasonable compatibility with the OpenStack way.
Policy rules are usually stored in a YAML or JSON file on disk. Load that file into a HashMap using your IO and deserialization libraries of choice. (The example below uses std and serde_yaml.) Then use this library to parse the rules into a RuleSet object:
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)?;
When handling a request, you need to construct a Request object. At a minimum, a request needs to contain a Token object that describes the token which was supplied with the Request. Ideally, your OpenStack client library of choice should have a type that implements our Token trait. Once you have a Request object, you can evaluate policy rules from the RuleSet and generate your HTTP responses accordingly. (The example below implies that Hyper is used to implement the request handler.)
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());
}
This library does not replicate all of the features and behaviors of the reference implementation.
This library explicitly rejects some fallback behaviors of the reference implementation that we consider dangerous.
@
explicitly.The following functionality will never be implemented in this library. PRs that add these features will be rejected.
"(rule:foo and rule:bar) or rule:qux"
, but in a list of lists of strings like
[["rule:foo", "rule:bar"], ["rule:qux"]]
. This format is described as legacy in the reference
implementation and not in wide use anymore. Always use the string format instead.["foo","bar"]:%(role_name)s
is
technically a valid check, though it does not do what you expect. It actually checks if the target
object attribute role_name
exists and contains the string value ['foo', 'bar']
, since the
left-hand side of the check is parsed and then serialized again through Python's str()
operator.
Supporting all of that is clearly insane and we are not going to do it. We only support checks
with plain string literals, e.g. 'foo':%(name)s
or "foo":%(name)s
.http
for delegating a policy
decision to a different service that is reachable via HTTP. Implementing such a checker is out of
scope for this library. If it is needed, applications can use Enforcer::add_check
to register a
custom implementation of trait Checker
.The following functionality may be implemented in this library in the future if a practical usecase can be demonstrated. Please open an issue to discuss your usecase before sending a PR.
'foo\nbar':%(name)s
or "foo\"bar":%(name)s
, but this
library currently returns a parse error when encountering an escape sequence in a string literal."foo":%(name)s
works, but 42:%(count)d
and "foo_bar":%(id)s_%(name)s
do not work and always
yield false.