Policy in OpenStack is the mechanism by which Role-Based-Access-Control is implemented. Policy is distributed in rules files which are processed at the time of a user request. Audit has come to mean the automated emission and collection of events used for security review. The two processes are related and need a common set of mechanisms to build a secure and compliant system.
This is a little rough, but I promised I would sum up our discussion.
The policy enforces authorization decisions. These decisions need to be audited.
Assume that both policy and audit are implemented as middleware pipeline components. If policy happens before audit, then denied operations would not emit audit events.If policy happens after audit, the audit event does not know if the request was successful or not.If audit and policy are not unified, the audit event does not know what rule was actually applied for the authorization decision.
Tokens are unpacked by a piece of code called keystonemiddleware.auth_token. (actually, its in keystoneclient at the moment, but moving)
Auth token middleware today does too much. It unpacks tokens, but it also enforces policy on them; if an API pipeline calls into auth_token, the absence of a token will trigger the return of a ’401 Unauthorized’.
The first step to handling this is that a specific server can set ‘delay_auth_decision = True’ in the config file, and then no policy is enforced, but the decision is instead deferred until later.
Currently, policy enforcement is performed on a per-project basis. The Keystone code that enforces policy starts with a decorator defined here in the Icehouse codebase;
The Glance code base uses this code;
And the other projects are comparable. This has several implications. Probably the most significant is that policy implementation can vary from project to project, making the administrators life difficult.
Deep object inspection
What is different about Keystone’s implementation? It has to do with the ability to inspect objects out of the database before applying policy. If a user wants to read, modify, or delete an object, they only provide the ID to the remote server. If the server knows what the project ID is of the object, it can apply policy. But that information is not in the request. So the server needs to find what project owns the object. The decorator @controller.protected contains the flag get_member_from_driver which fetches the object prior to enforcing the policy.
Cleaning up policy implementation
- Clean up the keystone server implementation of policy. The creation of https://github.com/openstack/keystone/blob/master/keystone/common/authorization.py was a start, but the code called from the decorators that knows how to deal with the token data in controller.py need to be pulled into authorization.py as well.
- Move authorization.py into keystonemiddleware
- Make the keystone server use the middleware implementation
- convert the other projects to use the middleware implementation.
- convert the other projects to use “delay_auth_decision” so this can eventually be the default.
- put the audit middleware into Keystone middleware as-is. This lets people use audit immediately.
- Extract out the logic from the middleware into code that can be called from policy enforcement.
- Create a config option to control the emission of audit events from policy enforcement.
- Remove the audit middleware from the API paste config files and enable the config option for policy emission of events.
Why not Oslo-policy.
Oslo policy is a general purpose rules engine. Keeping that separate from the OpenStack RBAC specific implementation is a good separation of concerns. Other parts of OpenStack may have needs for a policy/rules enforcement that is completely separate from RBAC. Firewall configs in Neutron is the obvious first place.