[openstack-dev] [all][keystone][product] api keys/application specific passwords

Monty Taylor mordred at inaugust.com
Thu May 18 13:23:30 UTC 2017


On 05/18/2017 06:53 AM, Sean Dague wrote:
> On 05/17/2017 09:34 PM, Adrian Turjak wrote:
>>
>>
>> On 17/05/17 23:20, Sean Dague wrote:
>>> On 05/16/2017 07:34 PM, Adrian Turjak wrote:
>>> <snip>
>>>> Anyway that aside, I'm sold on API keys as a concept in this case
>>>> provided they are project owned rather than user owned, I just don't
>>>> think we should make them too unique, and we shouldn't be giving them a
>>>> unique policy system because that way madness lies.
>>>>
>>>> Policy is already a complicated system, lets not have to maintain two
>>>> systems. Any policy system we make for API keys ought to be built on top
>>>> of the policy systems we end up with using roles. An explosion of roles
>>>> will happen with dynamic policy anyway, and yes sadly it will be a DSL
>>>> for some clouds, but no sensible cloud operator is going to allow a
>>>> separate policy system in for API keys unless they can control it. I
>>>> don't think we can solve the "all clouds have the same policy for API
>>>> keys" problem and I'd suggest putting that in the "too hard for now
>>>> box". Thus we do your step 1, and leave step 2 until later when we have
>>>> a better idea of how to do it without pissing off a lot of operators,
>>>> breaking standard policy, or maintaining an entirely separate policy system.
>>> This is definitely steps. And I agree we do step 1 to get us at least
>>> revokable keys. That's Pike (hopefully), and then figure out the path
>>> through step 2.
>>>
>>> The thing about the policy system today, is it's designed for operators.
>>> Honestly, the only way you really know what policy is really doing is if
>>> you read the source code of openstack as well. That is very very far
>>> from a declarative way of a user to further drop privileges. If we went
>>> straight forward from here we're increasing the audience for this by a
>>> factor of 1000+, with documentation, guarantees that policy points don't
>>> ever change. No one has been thinking about microversioning on a policy
>>> front, for instance. It now becomes part of a much stricter contract,
>>> with a much wider audience.
>>>
>>> I think the user experience of API use is going to be really bad if we
>>> have to teach the world about our policy names. They are non mnemonic
>>> for people familiar with the API. Even just in building up testing in
>>> the Nova tree over the years mistakes have been made because it wasn't
>>> super clear what routes the policies in question were modifying. Nova
>>> did a giant replacement of all the policy names 2 cycles ago because of
>>> that. It's better now, but still not what I'd want to thrust on people
>>> that don't have at least 20% of the Nova source tree in their head.
>>>
>>> We also need to realize there are going to be 2 levels of permissions
>>> here. There is going to be what the operator allows (which is policy +
>>> roles they have built up on there side), and then what the user allows
>>> in their API Key. I would imagine that an API Key created by a user
>>> inherits any roles that user has (the API Key is still owned by a
>>> project). The user at any time can change the allowed routes on the key.
>>> The admin at any time can change the role / policy structure. *both*
>>> have to be checked on operations, and only if both succeed do we move
>>> forward.
>>>
>>> I think another question where we're clearly in a different space, is if
>>> we think about granting an API Key user the ability to create a server.
>>> In a classical role/policy move, that would require not just (compute,
>>> "os_compute_api:servers:create"), but also (image, "get_image"), (image,
>>> "download_image"), (network, "get_port"), (network, "create_port"), and
>>> possibly much more. Missing one of these policies means a deep late
>>> fail, which is not debugable unless you have the source code in front of
>>> you. And not only requires knowledge of the OpenStack API, but deep
>>> knowledge of the particular deployment, because the permissions needed
>>> around networking might be different on different clouds.
>>>
>>> Clearly, that's not the right experience for someone that just wants to
>>> write a cloud native application that works on multiple clouds.
>>>
>>> So we definitely are already doing something a bit different, that is
>>> going to need to not be evaluated everywhere that policy is current
>>> evaluated, but only *on the initial inbound request*. The user would
>>> express this as (region1, compute, /servers, POST), which means that's
>>> the API call they want this API Key to be able to make. Subsequent
>>> requests wrapped in service tokens bypass checking API Key permissions.
>>> The role system is still in play, keeping the API Key in the box the
>>> operator wanted to put it in.
>>>
>>> Given that these systems are going to act differently, and at different
>>> times, I don't actually see it being a path to madness. I actually see
>>> it as less confusing to manage correctly in the code, because they two
>>> things won't get confused, and the wrong permissions checks get made. I
>>> totally agree that policy today is far too complicated, and I fear
>>> making it a new related, but very different task, way more than building
>>> a different declarative approach that is easier for users to get right.
>>>
>>> But... that being said, all of this part is Queens. And regardless of
>>> how this part falls out, the Pike work to just provision these API Keys
>>> looks the same.
>>>
>>> 	-Sean
>>
>> Fully agree that expecting users of a particular cloud to understand how
>> the policy stuff works is pointless, but it does fall on the cloud
>> provider to educate and document their roles and the permissions of
>> those roles. I think step 1 plus some basic role permissions for the
>> Keys with the expectation of operators to document their roles/policy is
>> a safe enough place to start, and for us to document and set some
>> sensible default roles and policy. I don't think we currently have good
>> documentation for what all the roles/policy actually let you do by
>> default, or very clearly stating that by default most services work
>> under the assumption "if you have a role in this project at all you can
>> do most things".
>
> Agreed.
>
>> My worry about policy also is that I'm not sure how safe it is for a
>> project owned API key to inherit permissions from the user who created
>> it. I can't think of a better way to it though but I'm still slightly
>> uncomfortable with it since a user with more roles could make a key
>> with  a subset of those which then someone else in the project can reset
>> the password for and then have access to a API key that 'may' be more
>> powerful than their own user. In clouds like ours where we allow
>> customers to create/manage users within the scope of their own projects,
>> there are often users who have different access all in the same project
>> and this could be an odd issue.
>
> This is a super interesting point I hadn't considered, thanks for
> bringing it up. We could probably address it by just blocking certain
> operations entirely for APIKeys. I don't think we loose much in
> preventing APIKeys from self reproducing. Blocking user/pw reset seems
> like another good safety measure (it also just wouldn't work in
> something like LDAP, because there is no write authority). That would be
> a very good set of things to consider on Monty's spec of any APIs that
> we're going to explicitly prohibit for APIKeys in iteration 1.

Yes. I totally agree - and also, thank you!

I've been thinking of this in terms of the API Key 'inheriting' the 
user's roles - but not ever being able to gain more ability. So at most 
an API Key can do what the user who created it can do - so the role 
system still is totally in effect. But the on top of that a User can 
limit further what a given key can do.

We'll also need a flag at creation - essentially, "blacklist" or 
"whitelist". That is - does this API Key start off with permissions to 
do NOTHING and specific permissions must be granted, or does this API 
Key start off with permissions to do everything the roles the user who 
created it could do and specific things will be blocked.

Both are potentially important. We'll need the step one version to be 
whitelist - since it won't be possible to add things it can do yet.

But think of the following use cases:

As a user, I want to make an API key that I'm going to use for general 
automation just like I use my Password auth plugin based user account 
today. I want it to be able to do everything I can do today - but I 
value the revocation features.

As a user, I want to make an API key that can only upload content to 
swift. I don't want to have to list every possible other API call.


What if we think about it like this:

For step one:

- A User creates an API Key in a Project. It will be a blacklist Key.
- That API Key is created with identical role assignments to the User 
that created it.
- The role assignment clone is done by keystone and is not tied to the 
User's ability to perform role assignments
- All API Keys are hardcoded in keystone to not be able to do 
(POST,DELETE) /projects/{project_id}/api-key
- All API Keys are hardcoded in keystone to not be able to do 
(POST,PATCH,DELETE) /users
- All API Keys are hardcoded in keystone to not be able to do 
(POST,PATCH,DELETE) /projects/{project_id}

For step two:
- A User creates a whitelist API Key. It can't do ANYTHING by default, 
no further action is needed on API key restrictions.
- A User creates a blacklist API Key. All API Key restrictions from step 
one are added as initial blacklist filters.

The change in step two would allow a User to decide that they want to 
opt-in to letting an API Key do *dangerous* things - but it would 
require explicit action on their part ... even if they have requested a 
blacklist Key.

We should also potentially add a policy check that would disallow a User 
from removing the API Key blacklist exclusions, since it's possible and 
reasonable that an Admin does not want a User to be able to create keys 
that can manage keys.

> This is definitely a way in which they would be not like Users, and I
> think brings up an important consideration about why they are a bit
> different from users.
>
>> As for step 2, as long as it honors the policy set by operators, and
>> provides sensible errors to users when they've done something silly
>> about setting a policy that the roles don't allow, then this should be
>> fine. We just need to be really careful to integrate the two policy
>> layers so they work well enough together regardless of whatever silly
>> policy operators do themselves. I don't envy anyone that task.
>
> Definitely will still honor operator policy, it will just have an
> additional permissions check even before getting there. My feeling is
> the 2 things being separate actually will make it easier to rationalize
> the right thing to do. But, a lot of that will need

Yup. Agree. (I think I responded to this bit already above)

>> The API keys may not solve some multi-project automation type things, so
>> there users are going to still have to be used, and I'm not sure if API
>> keys could really be made to work in multi-project unless at least we
>> allow sub-project inheritance in some sense. I don't think we should
>> allow multi-project ownership of API keys, but if the user creating it
>> has inherited roles we can probably do something with that.
>
> Yeh, multi project is going to be at least phase 3 (if not later). I can
> vaguely see how in a hierarchy it's doable.

I actually don't think it's hard. If we consider an API Key to inherit 
roles at creation time, then if a user has roles on more than one 
project, the API Key will also have roles on more than one project. We 
keep it from being super complex by not allowing explicit role 
assignment for API Keys - so if more projects are created and the user 
gets assigned roles in them, they would need to make a new API Key if 
they wanted to be able to do multi-project things with it.

We should not allow multi-project ownership of keys, because 
multi-project ownership of resources isn't really a thing. A resource 
exists in a project, so an API key exists in a project.

An API Key should never be able to do more than the creating user. An 
API Key should certainly be able to do less.



More information about the OpenStack-dev mailing list