While I tend to play up bug 968696 for dramatic effect, the reality is we have a logical contradiction on what we mean by ‘admin’ when talking about RBAC.
In early iterations of OpenStack, roles were global. This is reflected in many of the Policy checks that only look for the global role. However, prior to the Keystone-Light rewrite, role assignments became scoped to tenants. This shows up in the Keystone git history. As this pattern got established, some people wrote policy checks that assert:
role==admin and tenant_id=resource.tenant_id
This contradicts the global-ness of the admin roles. If I assign
I’ve just granted them the ability to perform all of the admin operations.
Thus, today we have a situation where, unless the user rewrites the default policy, they have to only assign the role admins to users that are trusted to be admins on the whole deployment.
We have a few choices.
- Remove Admin from the scoping for projects. Admin is a special role reserved only for system admins. Replace project scoped admins with ‘manager’ or some other comparable role. This is actually the easiest solution.
- Create a special project for administrative actions. Cloud admin users are assigned to this project. Communicate that project Id to the remote systems. This is what the policy.v3cloudsample.json file (http://git.openstack.org/cgit/openstack/keystone/tree/etc/policy.v3cloudsample.json) recommends.
However, 2 is really not practical without some significant engineering. For a new deployment, it would require the following steps.
- Every single policy file would have to be “templatized”
- Then deployment mechanism would have to create the admin project, get the id for it, and string replace it in the policy file.
We could make this happen in Devstack. The same is true of Puppet, OSAD, and Fuel. There would be a lag and the downstream mechanisms would eventually pick it up, multiple releases down the road.
I went through this logic back when I started proposing the Dynamic Policy approach. If OpenStack managed policy deployment via an inte4rnal mechanism, then adding things like the admin_project_id becomes trivial.
While I think Dynamic Policy provides a lot of value, I concede that it is overkill for just substituting in a single value. The real reason I am backing off Dynamic Policy for the moment is that we need to better understand what part of policy should be dynamic and what part should be static; we are just getting that clean now.
There is an additional dimension to the admin_project_id issue that several developers want solved. In larger deployments, different users should have administrative capabilities on different endpoints. Sometimes this is segregated by service (storage admins vs network admins) and sometimes by region.
Having a special project clearly communicates the intention of RBAC. But even clearer would be to have the role assignment explicitly on the catalog item itself. Which of the following statements would you think is clearer?
- Assign Joe the admin role on the project designated to administer endpoint 0816.
- Assign Joe the admin role on endpoint 0816.
I think you will agree that it is the latter. Making this happened would not be too difficult on the Keystone side, and would require fairly simple changes on the policy enforcement of the remote projects. We’ve already discussed “endpoint binding of tokens” where an endpoint needs to know its own ID. Having a new “scope” in a token that is endpoint_id would be fairly easy to execute.
One drawback, though, it that all of the client tooling would need to change. Horizon, openstackclient, and keystoneauth would need to handle “endpoint” as the scope. This includes third party integrations, which we do not control.
All of these constraints drive toward a solution where we link the admin project to the existing endpoint ids.
Make the catalog a separate domain.
Make regions, services, and endpoints projects
Use the rules of Hierarchical Multitenancy to manage the role assignments for a project.
On the enforcing side, endpoints *must* know their own ID. They would have checks that assert token.project_id = self.endpoint_id.
This is the “least magic” approach. It reuses existing abstractions without radically altering them. The chance of a collision between an existing project_id and and endpoint_id is vanishingly small\, and could be addressed by modifying one or the other accordingly. The biggest effort would be in updating the policy files, but this seems to be within the capability of cross project efforts.
Please read this, process it, and be ready to help come to a proper conclusion of this bug.