Allow policy registration from code
Add a capability to olso.policy to register default policy rules in code. This will allow consuming projects, if they register all of their policies, to expose a few things: * Deployers will only need to configure policies that differ from these defaults. * Given a RequestContext a list of policies that will pass for that context can be generated. This can be built upon so that projects can expose allowable actions to their users. Change-Id: I06493dec60f23671f8aca2534b44661ca91f53d3
This commit is contained in:
parent
16733d2b93
commit
c2aa12082e
|
@ -0,0 +1,252 @@
|
|||
..
|
||||
|
||||
==============
|
||||
Policy in code
|
||||
==============
|
||||
|
||||
|
||||
https://blueprints.launchpad.net/oslo?searchtext=policy-in-code
|
||||
|
||||
For a while now there has been a desire to embed sane policy defaults in code
|
||||
and allow for a policy file to override them. This would allow deployers to
|
||||
only configure policies that they specifically want to override which could
|
||||
reduce the size and complexity of those files. It would also allow for
|
||||
generating a sample policy file which includes an exhaustive list of all
|
||||
policies.
|
||||
|
||||
|
||||
Problem description
|
||||
===================
|
||||
|
||||
There are two issues being addressed here:
|
||||
|
||||
Given a deployed policy file it is not trivial to determine how much it differs
|
||||
from the defaults that a project expects. This is due to there not being an
|
||||
authoritative place to find all policies and their defaults. Some projects
|
||||
provide sample files but they're not always exhaustive. And it's not easy to
|
||||
diff a production policy file against the sample file after extensive
|
||||
modification.
|
||||
|
||||
Given an authenticated request context it is not possible to determine which
|
||||
policies will pass. This is because policy checks are ad hoc throughout the
|
||||
code with no central registry of all possible checks. And a policy file may not
|
||||
have all policies listed as some may be left to fallback to the default rule.
|
||||
|
||||
|
||||
Proposed change
|
||||
===============
|
||||
|
||||
The proposal is that any policy that should be checked in the code can be
|
||||
registered with the Enforcer class, similar to how configuration
|
||||
registration is done. A new method for policy enforcement will be added which
|
||||
errors if the policy being checked has not previosly been registered. Current
|
||||
methods of policy loading from a file and policy checking will not be affected.
|
||||
|
||||
Registration will require two pieces of data:
|
||||
|
||||
1. The rule name, e.g. "compute:get" or "os_compute_api:servers:index"
|
||||
2. The rule, e.g. "rule:admin_or_owner" or "role:admin"
|
||||
|
||||
Registration will optionally take a third piece of data:
|
||||
|
||||
3. A description string. This can help guide admins with information on each
|
||||
policy.
|
||||
|
||||
The rule name is needed for later lookups. The rule is necessary in order to
|
||||
set the defaults and generate a sample file. The description can be added as a
|
||||
comment to policy sample files.
|
||||
|
||||
Registration will be done by passing a PolicyOpt class to
|
||||
Enforcer.register_rule or a list of PolicyOpt's to Enforcer.register_rules.
|
||||
|
||||
As an example, based on how Nova might use this::
|
||||
|
||||
-- nova/policy/create.py
|
||||
|
||||
from oslo_policy import policy
|
||||
from nova import policy as nova_policy
|
||||
|
||||
server_policies = [
|
||||
policy.PolicyOpt(rulename='os_compute_api:servers:create',
|
||||
rule='rule:admin_or_owner',
|
||||
description='Checked on POST /servers'),
|
||||
policy.PolicyOpt(rulename='os_compute_api:servers:create:forced_host',
|
||||
rule='rule:admin_or_owner',
|
||||
description='Controls whether the forced_host '
|
||||
'scheduler hint is allowed.'),
|
||||
policy.PolicyOpt(rulename='os_compute_api:servers:create:attach_volume',
|
||||
rule='rule:admin_or_owner',
|
||||
description='Checks if a volume can be attached '
|
||||
'during instance create.'),
|
||||
policy.PolicyOpt(rulename='os_compute_api:servers:create:attach_network',
|
||||
rule='rule:admin_or_owner',
|
||||
description='Checks if a network can be attached '
|
||||
'during instance create.'),
|
||||
]
|
||||
|
||||
policy_engine = nova_policy.get_policy()
|
||||
# registration will error if a duplicate policy is defined
|
||||
policy_engine.register_rules(server_policies)
|
||||
|
||||
|
||||
-- nova/api/openstack/compute/servers.py
|
||||
|
||||
from nova import policy
|
||||
|
||||
policy_engine = policy.get_policy()
|
||||
|
||||
def create(self, context):
|
||||
...
|
||||
policy_engine.authorize('os_compute_api:servers:create', target, creds)
|
||||
try:
|
||||
# This would error because the policy is not registered
|
||||
policy_engine.authorize(
|
||||
'os_compute_api:servers:create_not_registered', target, creds)
|
||||
except:
|
||||
pass
|
||||
if volume_to_attach:
|
||||
policy_engine.authorize(
|
||||
'os_compute_api:servers:create:attach_volume', target, creds)
|
||||
|
||||
|
||||
The proposed change to oslo.policy is that the Enforcer class will gain two new
|
||||
methods: "register_rule" and "register_rules". These methods will process and
|
||||
store the registered policies. The "load_rules" method will be modified to
|
||||
merge rules loaded from policy files in with the registered defaults. Rules
|
||||
loaded from files will overwrite registered defaults.
|
||||
|
||||
An "authorize" method will be updated so that attempting to check against a
|
||||
rule that doesn't exist will be an error. In other words the default rule loses
|
||||
its special status and is not a fallback for rules that are not defined. It
|
||||
will still remain as a reference for other rules to use.
|
||||
|
||||
A PolicyOpt class will be added which defines a policy to be registered. It
|
||||
will initially hold rulenames, rules, and descriptions.
|
||||
|
||||
Files to change:
|
||||
|
||||
* olso_policy/policy.py
|
||||
|
||||
Alternatives
|
||||
------------
|
||||
|
||||
Rather than modifying the Enforcer class in oslo_policy/policy.py a new Policy
|
||||
class could be added which handles registration and contains a new "authorize"
|
||||
method. The Policy class would mostly handle registration and storage of
|
||||
policies and would proxy to Enforcer for loading policy from files and handling
|
||||
the actual enforcement. Over time it may make sense to pull the loading of
|
||||
policy from files out of the Enforcer class and into Policy.
|
||||
|
||||
Impact on Existing APIs
|
||||
-----------------------
|
||||
|
||||
A new "register" method will be added to the Enforcer class.
|
||||
|
||||
Security impact
|
||||
---------------
|
||||
|
||||
There is no security impact from this change. The way that policies are
|
||||
enforced does not change, just where they're loaded from.
|
||||
|
||||
Performance Impact
|
||||
------------------
|
||||
|
||||
Registration of policies from code will have a slight peformance at the time of
|
||||
registration, but this should be no different than registering configuration
|
||||
options
|
||||
|
||||
Configuration Impact
|
||||
--------------------
|
||||
|
||||
There is no direct configuration impact from this change. This change will
|
||||
allow projects who have registered policies to not need a policy file in order
|
||||
to use those defaults. This will allow deployers to trim down, or remove, their
|
||||
policy files if they are running close to the defaults.
|
||||
|
||||
Developer Impact
|
||||
----------------
|
||||
|
||||
It will not be required, but it will be encouraged, that projects switch to
|
||||
registering policy rules before using them. So developers will need to get in
|
||||
the habit of adding that registration before use, similar to adding a new
|
||||
configuration option.
|
||||
|
||||
Testing Impact
|
||||
--------------
|
||||
|
||||
Unit testing should be sufficient here. This adds a new capability that can be
|
||||
used by other projects but it is not directly dependent on anything.
|
||||
|
||||
Implementation
|
||||
==============
|
||||
|
||||
Assignee(s)
|
||||
-----------
|
||||
|
||||
Primary assignee:
|
||||
alaski
|
||||
|
||||
Other contributors:
|
||||
None
|
||||
|
||||
Milestones
|
||||
----------
|
||||
|
||||
Target Milestone for completion:
|
||||
newton-1
|
||||
|
||||
Work Items
|
||||
----------
|
||||
|
||||
* Add a PolicyOpt class to oslo_policy/policy.py
|
||||
* Add a "register_rule" method to Enforcer for registration of rules
|
||||
* Add a "register_rules" method to Enforcer for registration of rules
|
||||
* Update Enforcer.load_rules() to merge registered rules with file loaded rules
|
||||
* Add an "authorize" method to Enforcer which functions like "enforce" but
|
||||
errors if the policy being checked has not been registered.
|
||||
|
||||
Incubation
|
||||
==========
|
||||
|
||||
N/A
|
||||
|
||||
Adoption
|
||||
--------
|
||||
|
||||
Nova would like to use this functionality.
|
||||
|
||||
Library
|
||||
-------
|
||||
|
||||
N/A
|
||||
|
||||
Anticipated API Stabilization
|
||||
-----------------------------
|
||||
|
||||
N/A
|
||||
|
||||
Documentation Impact
|
||||
====================
|
||||
|
||||
The ability to register policy rules will be documented in developer facing
|
||||
documentation. Any deployer facing changes will be the responsibility of
|
||||
consuming projects to document as they switch over to using policy
|
||||
registration.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
None
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
Nova spec for this capability: https://review.openstack.org/#/c/290155/
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
This work is licensed under a Creative Commons Attribution 3.0
|
||||
Unported License.
|
||||
http://creativecommons.org/licenses/by/3.0/legalcode
|
||||
|
Loading…
Reference in New Issue