Writing HTTP check rules¶
oslo.policy has supported the following syntax for a while:
http:<target URL>, which delegates the check to a remote server
Starting with 1.29, oslo.policy will also support https url(s) as well:
https:<target URL>, which delegates the check to a remote server
Both http
and https
support are implemented as custom check rules.
If you see the setup.cfg for oslo.policy, you can see the following
entry points:
oslo.policy.rule_checks =
http = oslo_policy._external:HttpCheck
https = oslo_policy._external:HttpsCheck
When a policy is evaluated, when the engine encounters https
like in
a snippet below:
{
...
"target 1" : "https://foo.bar/baz",
...
}
The engine will look for a plugin named https
in the rule_checks
entry point and will try to invoke that stevedore plugin.
This mechanism allows anyone to write their own code, in their own library with their own custom stevedore based rule check plugins and can enhance their policies with custom checks. This would be useful for example to integrate with an in-house policy server.
Example code - HttpCheck¶
Note
Full source located at _external.py
1class HttpCheck(_checks.Check):
2 """Check ``http:`` rules by calling to a remote server.
3
4 This example implementation simply verifies that the response
5 is exactly ``True``.
6 """
7
8 def __call__(self, target, creds, enforcer, current_rule=None):
9 timeout = enforcer.conf.oslo_policy.remote_timeout
10
11 url = ('http:' + self.match) % target
12 data, json = self._construct_payload(creds, current_rule,
13 enforcer, target)
14 try:
15 with contextlib.closing(
16 requests.post(url, json=json, data=data, timeout=timeout)
17 ) as r:
18 return r.text.lstrip('"').rstrip('"') == 'True'
19 except Timeout:
20 raise RuntimeError("Timeout in REST API call")
21
22 @staticmethod
23 def _construct_payload(creds, current_rule, enforcer, target):
24 # Convert instances of object() in target temporarily to
25 # empty dict to avoid circular reference detection
26 # errors in jsonutils.dumps().
27 temp_target = copy.deepcopy(target)
28 for key in target.keys():
29 element = target.get(key)
30 if type(element) is object:
31 temp_target[key] = {}
32 data = json = None
33 if (enforcer.conf.oslo_policy.remote_content_type ==
34 'application/x-www-form-urlencoded'):
35 data = {'rule': jsonutils.dumps(current_rule),
36 'target': jsonutils.dumps(temp_target),
37 'credentials': jsonutils.dumps(creds)}