Resource ids are not unique per tenant
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Gnocchi |
Fix Released
|
Medium
|
Julien Danjou |
Bug Description
Dear Gnocchi Devs,
I've been trying out gnocchi and came to realised that resource ids are not unique per project.
Also, the resource's uuid seems to be generated from https:/
This means that
1) When a user tries to create a resource of the same name as an existing resource (in another project), they get a HTTP 409. However, they can't see the resource using a `gnocchi resource list`. E.g.
$ gnocchi resource create test
Resource 7fd19145-
$ gnocchi resource list
$
2) Given that there are no quotas (that I know of), it might be trivial to DoS gnocchi resources across the whole system.
(2) is not so much of a problem, but I can see (1) being kinda annoying to users when gnocchi is rolled out. Everyone likes to do a `gnocchi resource create test`.
I wonder if there is a reason behind this design decision? Please let me know if this is a known bug or a WONTFIX.
Changed in gnocchi: | |
status: | New → Triaged |
importance: | Undecided → Medium |
Julien Danjou (jdanjou) wrote : | #1 |
Jake Yip (waipengyip) wrote : | #2 |
Thanks Julien for replying! Hopefully this discussion can help other gnocchi users with the same questions.
I agree that resource ids should be unique across the system. Maybe the name should not be? Just thinking along the lines of nova names, cinder names and uuid...
Maybe name-to-uuid transformation can be better. Off the top of my mind, a possible improvement can be to use the tenant uuid to generate the resource uuid. What do you think?
Of course we have to take care of existing resource, which can be handled via the upgrade script.
Re: quota, we can handle this separately. I was just making a point that dictionary collisions occur much more easily/frequently then UUID collision.
xiaozhuangqing (xiaozhuangqing) wrote : | #3 |
Hi Julien:
Does has no name field?? can I wen add a filed of name to gnocchi resource ?
I hope I can do it ^^
Julien Danjou (jdanjou) wrote : | #4 |
I thought about using the name-to-uuid transformation based on another UUID: the problem is that the project_id is not always an UUID, so that is not possible. :(
gordon chung (chungg) wrote : | #5 |
name-to-uuid transform both resource and project?
hmm.. yeah. i think the issue is that `gnocchi resource create <value>` is actually taking in the identifier, which should be unique, rather than a name.
gordon chung (chungg) wrote : | #6 |
although, now that i think about it, i don't think we can change name-to-uuid logic to incoporate project-id or else it completely destroys the current name-to-uuid mapping?
Jake Yip (waipengyip) wrote : | #7 |
@gordon, do you think we can migrate the uuid/names to the new schema during an upgrade by running the gnocchi-upgrade script?
gordon chung (chungg) wrote : | #8 |
yes, we probably could. that doesn't fix the fact that when we run 'gnocchi resource show <uuid>' it would again fail probably because uuid is now no longer unique.
gordon chung (chungg) wrote : | #9 |
here's a proposal. how about we just allow the ability to create resource and have id optional. if you don't submit one, we just generate one. this way we dont' need any migrations and all data is still valid.
Jake Yip (waipengyip) wrote : | #10 |
I wonder if we could make 'gnocchi resource show <name>' use the name-to-uuid mapping and 'gnocchi resource show <uuid>' to use the uuid directly? I was under the impression that this is how gnocchi does things now, i.e. do a name-to-uuid conversion only if the the provided param is not already an uuid.
summary: |
- Resource UUID are not unique per tenant + Resource names are not unique per tenant |
gordon chung (chungg) wrote : Re: Resource names are not unique per tenant | #11 |
that is already how it happens. if you pass in a name aka. non-uuid, it will run through a translation method to switch it to uuid. the problem is that translation does not account for project which causes your conflict. if we take project into account, it will require us to migrate all the previous data as that data didn't use project when it did translation. maybe we do need migration, but i'm trying to think of a solution which doesn't :)
i guess my solution doesn't let you query by name which might be required?
i'm good with either way. don't have time to work on it currently though.
Jake Yip (waipengyip) wrote : | #12 |
Yes that's exactly what I meant: use a new name-to-uuid algorithm that takes into account project uuid. And also migrate data using the upgrade script at the same time.
It is not terribly urgent for us at this point in time, but might be when we get more users storing their own data in gnocchi. I will see if I can fix it when I get some time.
I hope that having a bug report will help point users in the correct direction when they encounter this problem. And please leave comments / upvote if you would like this change.
Sam Morrison (sorrison) wrote : | #13 |
Where this caught me is with the resource type of swift_account. I had created a custom resource type called "project" with the idea of storing some metrics against openstack projects. This however failed as the swift_account resource type already had resources with the same project IDs (swift_acocunt is really a project, it is poorly named).
My fix was to change the gnocchi_
summary: |
- Resource names are not unique per tenant + Resource ids are not unique per tenant |
gordon chung (chungg) wrote : | #14 |
i think we should do what Jake suggests... any other options?
gordon chung (chungg) wrote : | #15 |
man this sucks. i attempted to implement this and i realise it looks very strange if we implement project-scoped ids using the current mechanism we have. specifically, when you rest interface, if i ask for /v1/resources/
Julien Danjou (jdanjou) wrote : | #16 |
Current thoughts:
* Merge created_
* Each auth_type can map its own headers to the "owner" field for ACL
* Remove user_id,project_id from generic – each auth type module can map this as it wants
* Make (resource_id,owner) unique
Changed in gnocchi: | |
assignee: | nobody → Julien Danjou (jdanjou) |
gordon chung (chungg) wrote : | #17 |
i don't really undertand the first 3 bullets...
so if i request /v1/resource/
Julien Danjou (jdanjou) wrote : | #18 |
If you request /v1/resource/
When you do a request a token is always scoped to user/project/domain with Keystone. So if you want to do the same request for a different project you need a different token.
gordon chung (chungg) wrote : | #19 |
does that mean role:admin doesn't actually mean much anymore? i believe you previously could see everything? if you have admin now, no matter what you're scoped to a project?
Julien Danjou (jdanjou) wrote : | #20 |
So each module of auth (keystone, noauth) will be able to implement its own scheme in this regard.
For Keystone, I think that the listing will be able to list everything, that's no problem. For /v1/resource/
Sam Morrison (sorrison) wrote : | #21 |
This is really just an issue when getting data from ceilometer as gnocchi is using IDs from another system as it's own unique ID.
Wouldn't the correct solution be to use a unique uuid for a resource that is generated by gnocchi and storing eg. in the case of a nova instance the uuid as an attribute of that?
gordon chung (chungg) wrote : | #22 |
@jd, it just seems a little weird that if i call /v1/resource/
@Sam, i think that's the cleaner solution but it will break all existing queries (against REST at least. not necessarily end of world but it is what it is. it will also probably require the most changes.
Julien Danjou (jdanjou) wrote : | #23 |
The problem with Sam's solution is that you cannot know the URL of a resource in advance without knowing its random id. Which kinda kill the workflow of "gnocchi resource show <instance-id>" inside OpenStack.
gordon chung (chungg) wrote : | #24 |
right, i wonder how nova works. it allows you to pass in a name or id when running 'nova show'. i have a preference that whatever url you use and letting client handle all the redirect / id-masking.
gordon chung (chungg) wrote : | #25 |
i should mention i don't have a code so if you have code for your path i don't want to stop you (not that i can :P)
Julien Danjou (jdanjou) wrote : | #26 |
I dug into Nova client source code, and what it does is a detailed listing/search to get the right resource and tries to guess if the <instance-id> is an id or an human name (because it also works with the display_name of an instance).
Julien Danjou (jdanjou) wrote : | #27 |
I've started working on that, and I've almost finished a PoC of fixing this. It changes the indexer so the resources in database are not usind (id) as primary key, but (id, creator). This works fine, except for the one case – introduced by Ceilometer – where you want to access a resource that you did not created, e.g.:
GET /v1/resource/
If the resource <someuuid> have been created by Ceilometer but your project_id is in it, the current policy allows you to get the resource and its information. With the new scheme, this is not possible anymore because <someuuid> can exists 10 times in the database (e.g. 1 created by Ceilometer and 9 others created by random people). So it'd be very costly to check that which of the 10 you have access to, and if 2 are accessible, that's a problem as the API was not designed to return more than one resource on that URL.
The solution to that problem is either:
1. Break that use case, so there's no sharing of resources/data anymore between tenants using Gnocchi. So in the case of Ceilometer, no user will be able to access data pushed by it anymore.
2. Add a header called X-Created-By, which if provided when requesting "GET /v1/resource/
Another totally different solution that I just thought about, is to keep the current resource id to be the primary key – so id is still unique. However, since this bug is mainly around having the ability to do "gnocchi create resource foobar" with foobar meaning 2 different id for different users, we could change the UUID5 generation mechanism from:
uuid.
to
uuid.
which would solve that problem quite easily. There *might* be some breakage for people having hardcoded those generated ID somewhere, but if it's not hardcoded, it should be pretty to make work and to upgrade to this new scheme.
gordon chung (chungg) wrote : | #28 |
the last scenario will still make GET /v1/resources/uuid return different resources depending auth headers right? i think that's kind of weird to be honest.
my use case is using some 'admin' id, i want to be able to work against all metrics of a project regardless of who/what pushed it into Gnocchi. it seems like that could be handled by first solution?
Julien Danjou (jdanjou) wrote : | #29 |
"the last scenario will still make GET /v1/resources/uuid return different resources depending auth headers right? i think that's kind of weird to be honest."
No, because the ID is a primary key, so all resources have a unique id.
The thing is that if you do:
$ gnocchi resource create foobar
as user "jd", the resource id will be computed based on (foobar, jd) and let's say abc123.
If you gordc create a resource with:
$ gnocchi resource create foobar
your resource id will be (foobar, gordc) and it'll be let's say def456.
If I want to access your resource because e.g. you set a project_id to something that we both share <3 I can do:
$ gnocchi resource show foobar --created-by gordc
and in this case the client will compute the UUID with (foobar, gordc), which will show me the resource you created.
So all the ID are computed client side so that works.
The only case where what you describe happen is if I use the UUID computing on the server side, e.g. GET /v1/resource/
Is this clearer?
gordon chung (chungg) wrote : | #30 |
sure. as long as it's not on server side i think we're good :)
gordon chung (chungg) wrote : | #31 |
oh, one question. if it's server side, what if i actually put:
gnocchi resource show foobar vs gnocchi resource show <actual primary key id>?
Julien Danjou (jdanjou) wrote : | #32 |
Well gnocchiclient will compute uuid5(foobar, gordc) and that'll return the UUID primary key.
And if you go on HTTP and ask /v1/resource/
and /v1/resource/
Clearer? :)
gordon chung (chungg) wrote : | #33 |
sure. but how does it know that foobar in /v1/resource/
i was hoping that via REST foobar in /v1/resource/
if you use client gnocchi resource show foobar, it will assume uuid first and if nothing, try uuid5(foobar, project-id) also, do we want it project scoped or user scoped? if we make it user scoped doesn't that mean i can't get everything from my project even if i'm admin?
Julien Danjou (jdanjou) wrote : | #34 |
> "sure. but how does it know that foobar in /v1/resource/
This is already in the API. It checks if foobar is an uuid or not. If it's not it converts it.
The UUID translation is not user nor project scoped, it's "creator" scoped (see the recent patch branch). Which in the Keystone case is user_id:project_id.
So if you don't know user/project (but you can know it by listing the resources) you can't guess the uuid of a named resource, sure.
> "if you use client gnocchi resource show foobar, it will assume uuid first and if nothing, try uuid5(foobar, project-id) also, do we want it project scoped or user scoped? if we make it user scoped doesn't that mean i can't get everything from my project even if i'm admin?"
"foobar" is not an uuid so it will never try "foobar". Even if it does, the server will translate it to an uuid5(foobar, creator).
Same answer for the "scope", it's creator (which is user:project).
gordon chung (chungg) wrote : | #35 |
"""The UUID translation is not user nor project scoped, it's "creator" scoped (see the recent patch branch). Which in the Keystone case is user_id:project_id.
So if you don't know user/project (but you can know it by listing the resources) you can't guess the uuid of a named resource, sure."""
iirc, the original reason we had this translation was because we had some cases where our 'resource_id' had a '/' in it which broke api. the more we expand that, it seems like the translation are very hidden unless you know about it... even now i'm not entirely sure what i'd get if i put use /v1/resource/
""""foobar" is not an uuid so it will never try "foobar". Even if it does, the server will translate it to an uuid5(foobar, creator).
Same answer for the "scope", it's creator (which is user:project)."""
so the scope is what my original concern was. this seems to break (my) use case of i am admin user and i want to grab everything from my project.
Julien Danjou (jdanjou) wrote : | #36 |
"iirc, the original reason we had this translation was because we had some cases where our 'resource_id' had a '/' in it which broke api. the more we expand that, it seems like the translation are very hidden unless you know about it..."""
Resource IDs are and always have been UUID. This won't change.
In Ceilometer we realized we had resource ID which were not UUID (and some with / in it) so we added a translation layer str->uuid a while back, based on uuid5(id-
"""even now i'm not entirely sure what i'd get if i put use /v1/resource/
If you use /v1/resource/
The problem this bug is about is that when <blah> is a string "blah" it's converted to a uuid5("blah") and that is always the same, whoever you are. That's cool, but you cannot have several resources with "blah" as "original-
(or you think we should not fix the bug? :))
"""so the scope is what my original concern was. this seems to break (my) use case of i am admin user and i want to grab everything from my project."""
It actually does not. With Keystone auth, if you're admin, you can list all resources:
GET /v1/resources/
You'll get *all* instances whatever the "creator" field is – you're admin. That will return the data with all details about resources. If you want to access any resource directly, let's say one who has original_
The proposal here, is to make "foobar" translated to uuid5("foobar", "jd") rather than just uuid5("foobar"). Then everything still works as just described, but this time you can have more than one resource whose original_
gordon chung (chungg) wrote : | #37 |
"""
If you use /v1/resource/
The problem this bug is about is that when <blah> is a string "blah" it's converted to a uuid5("blah") and that is always the same, whoever you are. That's cool, but you cannot have several resources with "blah" as "original-
"""
so is this still the same assumption then? if you provide a uuid, then it automatically becomes primary resource_id and therefore no 2 projects may pass in same uuid?
Julien Danjou (jdanjou) wrote : | #38 |
No… I hope my patch will clear the misunderstanding. :)
OpenStack Infra (hudson-openstack) wrote : Fix proposed to gnocchi (master) | #39 |
Fix proposed to branch: master
Review: https:/
Changed in gnocchi: | |
status: | Triaged → In Progress |
Jake Yip (waipengyip) wrote : | #40 |
Hi Julien,
Thanks for the patch! I just reviewed it and have some thoughts about it.
> def ResourceUUID(value, creator):
Do you think it might be better to compute ResourceUUID(value, project_id) instead?
Most of OpenStack operates on the premise that resources belong to a project, not a user. A user can access the resources created by other users in the same project. E.g. a user I can do a `nova show <instance_name>` someone else created.
So, I think in gnocchi case it will be good to have the same behaviour.
Julien Danjou (jdanjou) wrote : | #41 |
Hi Jake,
The user/project is really tied to the Keystone approach, and Gnocchi trying to be generic, it's not a good idea to bake those notion deeply into it.
That being said, it does not is a problem to user value+creator as the key here. This is just about encoding the resource id, so it is unique for a creator (user+project in Keystone case). This does not implies who gets access to the resource: the Keystone auth mode still allow access to resources that belongs to a project_id that the user is auth with.
So that means you won't be able to do directly "gnocchi resource show foobar" as user2/project1 if it has been created by user1/project1 because that will be a different UUID. But you will be able to do "gnocchi resource show <uuid-of-
The trade-off of fixing this bug is that: everyone can create a "foobar" resource (it's being translated into an UUID) but it's gonna be unique per creator (which is user+project in Gnocchi).
Jake Yip (waipengyip) wrote : | #42 |
Hi Julien,
> So that means you won't be able to do directly "gnocchi resource show foobar" as user2/project1 if it has been created by user1/project1 because that will be a different UUID. But you will be able to do "gnocchi resource show <uuid-of-
Yes I understand this. I thought it might be a good idea to have the similar behaviour like nova where you can do a `nova show foobar` as any user in the project. Although nova does it another way, not by translating a name -> uuid.
But you might have a point about it to be generic. I'm fine either way, as long as it fixes the original bug.
By the way, do you have any experience on use cases that are doing create/show resources using strings instead of uuids? Perhaps with use cases we might figure which is better.
Julien Danjou (jdanjou) wrote : | #43 |
Nova does that "show instance" by doing a *search*. Which can be very slow, especially in the case of Gnocchi where it has a lot more resources in its index. Here the name->uuid transformation is O(1), compared to O(log n) in Nova (at best if indexed, or O(n) otherwise).
But in the end you can still implement a "gnocchi search-and-show resource foobar" that will do the same way that Nova does.
On the uses cases, a lot of the non-OpenStack users have systems to monitor where resources have names (e.g. hostnames) but no UUID at all. So computing those UUID without having to do a search is a big win. :)
OpenStack Infra (hudson-openstack) wrote : Fix merged to gnocchi (master) | #44 |
Reviewed: https:/
Committed: https:/
Submitter: Jenkins
Branch: master
commit ad4b851c7fbf4b9
Author: Julien Danjou <email address hidden>
Date: Mon Dec 19 12:18:09 2016 +0100
rest: string → UUID conversion for resource.id to be unique per user
This changes the UUID5 based mechanism so it depends on the user trying
to CRUD the resource. This makes sure that when using this kind of
transformation, the resource id is converted to a unique id for the
user, while preventing conflicting if every user wants to create a
"foobar" resource.
Change-Id: Iebaf3b9f8e0a19
Closes-Bug: #1617918
Changed in gnocchi: | |
status: | In Progress → Fix Released |
OpenStack Infra (hudson-openstack) wrote : Fix included in openstack/gnocchi 3.1.0 | #45 |
This issue was fixed in the openstack/gnocchi 3.1.0 release.
This is more historical than a thought design decision. The resource are supposed to be always created using an UUID, not any name. We added later the name-to-uuid transformation to simplify some use cases (for OpenStack). But it means a name can only be used once across a whole Gnocchi. I think Amazon S3 has the same kind of limitation for the bucket name, no? (just trying to justify that this may not be a problem :-)
Resource ID are supposed to be unique across a Gnocchi deployment and I don't think it's a problem, as there should not be any collision there – it's UUID, there's a large space for everyone.
But the name-to-uuid transformation indeed poses some kind of silliness in this regard.
I'm open to any suggestion.
Oh, and I think the lack of quota is completely orthogonal anyway. It's a missing feature, definitely (probably worth a different bug).