Openstack-Common/Fine-Grained-Policy

= Fine Grained Policy =

Our current policy engine provides the capability of making a simple yes or no decision. It is quite powerful, but it has a couple of flaws:


 * Policies are expressed as lists of lists, which is rather opaque
 * It can only make yes or no decisions

Accordingly, I'm brainstorming possible alterations to the policy engine, with the goal of addressing the above flaws. My goals are:


 * Policies can also be expressed in a policy language.
 * This will give us better expressiveness.
 * One argument against will be the parsing of the policy language, but I believe this will be of minimal impact, since the results of the parsing can be cached. If we really want to, we could even cache the results in a manner similar to how Python caches compiled Python code.
 * By having a policy language, we can allow alternate returns from the policy checks: instead of a True or False result, we can also have it return things like strings.
 * For backwards compatibility, we must continue to accept the existing list of lists model.

So, the major piece of design is exactly what can we do with the policy language. We'll assume the list-of-lists structure can be compiled to an underlying representation. So, what will this language look like? For basic rules, we need a True or False result, and that will be simply an expression. This becomes quite simple to express; we use a form like "role:admin or (project_id:%(project_id)s and role:projectadmin)". Here we have the standard boolean operators, "and", "or", and "not", along with parentheses. The rules themselves correspond to the existing rules accepted by the policy engine.

To allow the second goal, alternate returns from the policy checks, I propose a case mechanism; that would look something like this: 'case { "fulladmin"=role:admin; "projadmin"=project_id:%(project_id)s and role:projectadmin }'. Here, the string enclosed in quotes preceding the '=' would be the return value, and the rules would be evaluated in order; than is, we first test "role:admin", and if that's true, the policy result would be the string "fulladmin"; otherwise, we test "project_id:%(project_id)s and role:projectadmin", and if that's true, we return "projadmin"; otherwise, we return False.

The ultimate format of the policy.json file remains the same—it is a JSON dictionary mapping rule names to rules. The rules can be expressed as lists of lists, as currently, or can be expressed as the text form described above. The interesting point comes when we start to discuss what the internal representation should be. If we were just doing the yes/no decision, we could express this as just a list of lists; however, with the case statement, this becomes more complicated. Given that the rules in the case statement would be similar to the yes/no rules, what I will propose is that we compile the policy rules into trees of objects. This also means we could extend the language in the future, if we need to.