Both Core APIs and Policy have been static for a long part of OpenStack’s lifespan. While I’ve been working on Dynamic Policy, the Nova team has been looking to use microversions to allow the API to morph more quickly. Are the two approaches going to interoperate, or are they going to conflict?
With a microversion, a service like Nova can make changes between commits that provide different ways to perform the same operation. It can also provide a new operation. Both will challenge the Policy mechanism to keep up.
Of the two, the easier one to handle is new functionality. Let’s walk through what this process would look like:
A Nova dev needs to provide access to a new resource. Let’s just for grins, call it a Container. Containers never existed in Nova before this, so all of the CRUD APIs are new. Each of them should, thus, get a new policy rule name. Ideally, this would be cleanly namespaced and clearly self documenting:
(and, yes, I am, at the moment, ignoring the fact that these really should look like the URLS that access them, as that is a whole ‘nother post entirely)
Now, the Nova team should add these rules to the default policy, right?
Well, probably…but now we are getting in to conflict with Dynamic Policy. It is based on the workflow: lets assume that a Nova server will only execute policy that is fetched dynamically. The changes made in the upstream default policy file need to then get uploaded to the Keystone Policy Admin API. However, we can’t just blindly overrwrite all of the rules that are uploaded. There are two options:
- Each microversion gets its own policy file, and the executed policy is the sum of all the files. The external system is then responsible for tracking which policy files have been applied to the Policy Database.
- When Uploading a new set of policy rules to the Policy Database, allow an option that specifies “no overwrite” which will indicate that the rule should only be added if it is not there already. This will allow a CMS to blindly apply the default policy multiple times.
I prefer the second.
Until the Nova server fetches the policy file from the Keystone server, the new API should never pass the policy check. This could either be done via a default rule, or via oslo.policy requiring an exact match. Again, I prefer the second approach. Default rules are, based on what I’ve seen in the other OpenStack policy.json files, too easy to make to permissive.So, just deploying new packages won’t get you the feature enabled until you update policy, too. This should be acceptable, as the commitment to Dynamic Policy implies continuing to maintain policy.
What about the case where an API changes? It turns out microversions already give us the answer for that. With a microversion, you can distinguish between the older and new versions of the API in the call. Policy needs to respect that. It means that policy must be updated to reflect the difference. Let’s user our theoretical container resource as an example, again. Both versions of the API are going to be active at the same time.Lets say the original container had the fields
id, tenant_id, description
and the new one has
id, project_id, description, label
For Old policy, we want to enforce on tenant_id, but for the new one we want to enforce on both project_id and possible label (yeah, I’ve been thinking about SELInux)
The original pre-dates microversions, so it has the policy rules “compute:create_container” and “compute:delete_container” but what about the new ones? Those need to specify a different rule to fetch from the policy file. It could be based on the microversion string, or any other distinguishing factor. oslo.policy does not dictate how to distinguish. If we go with the microversion approach, we append the min-version to the rule in policy:
I’d probably prefer something more self documenting, that captures the differences between old and new, but I suspect min-versions are the most succinct string to use.
If the old API is removed, the rule will stick around until told to go away, and cause no harm.
The code absolutely has to be microversion aware. Policy is not checked by a middleware component that is unaware of the underlying API call, and so we don’t have the need or the ability to automatically map the microversion in. That gets back to the issue about mapping URLs to policy that I punted on before.
As with most things in Dynamic Policy, this is not set in stone. This is, at this point, an attempt to think through how it will work.