Where to store ZedToken if the resources are in a tree structure? #1530
-
We have a hierarchical resource structure similar to a folder tree. Let's say we have a similar setup to google drive, where resources are files and they are in folders. Folders could have folders in them. You can assign permissions for users on folders which will give them access to any of the files in that folder or any of its subfolders transitively. You can assign a single user or a group of users to a folder where a group of users could also contain other groups of users. The question is: Where should I store my ZedTokens after I write a relationship? The documentation says that I should store the returned ZedToken in the parent resource. But there is a full chain of parents in this case. Which parent? Should I store in with the top most folder? That I think would be the safest option, because that would mean any change in any of the relationships would result in a new ZedToken for the whole tree. Although it would also be a bottleneck because I would have to store it with proper locking in place. Also it would not add much performance gain compared to a fully consistent read when performing lookup resources. But if I consider storing it with any other folder down the tree, I could potentially miss a permission change that was happening upper in the tree. What would be the best practice in this case? |
Beta Was this translation helpful? Give feedback.
Replies: 15 comments 3 replies
-
The general rule of thumb is the immediate resource for the relationship being changed: the document itself if its permission is being modified, the folder if a document is added/removed, the group if a member is being added/removed. You can certainly do so at the top level, but as you mentioned you'd need some (basic) form of locking or to have some slight staleness. Ultimately, a ZedToken is most important for preventing the New Enemy Problem (https://authzed.com/blog/new-enemies/), and in that case, the most important place is the document itself. Otherwise, some staleness is typically a valid outcome for permission checks. |
Beta Was this translation helpful? Give feedback.
-
But let's say I add a user to a group, so I save the returned ZedToken to the group in my database. Which would result in a transitive permission change to a lot of files as permissions are being inherited through the folder hierarchy downwards. Then I want to issue let's say a LookupSubjects request to find out who has access to a certain file, so I grab the ZedToken from the file itself or from its immediate parent folder, but that was saved way before I added that user to a group, so I would not see the new user having permission to this file unless I use the ZedToken saved in the group. But how should I know which ZedToken I should use that would be the newest? |
Beta Was this translation helpful? Give feedback.
-
You only won't see the new user having permission to the file until the caches expire; this is by default ~5s on SpiceDB. ZedTokens/Zookies are intended to address the case where you explicitly need to guarantee freshness because, if you do not, someone who may have had access to the document's contents may be able to see the new contents added after their permission was revoked. In your case, unless you need to guarantee against the New Enemy problem, its not necessary to have a "transitive" ZedToken. You can, of course, do so if you want to guarantee freshness at all times, but as stated above that does mean keeping an "overall" ZedToken at, say, the organization level, which we've seen users do also. |
Beta Was this translation helpful? Give feedback.
-
Oh, interesting. I did not know about the 5s cache. |
Beta Was this translation helpful? Give feedback.
-
Just issue a check for a permission to edit the document (which I imagine you'd want to do anyway to verify the caller can change the document), and then store the returned ZedToken next to the Document, not its folder |
Beta Was this translation helpful? Give feedback.
-
I think it is an interesting problem that affects the Zanzibar zookie concept as a whole for transitive permissions. Imagine you have some document D that group G is allowed to edit. If user U is in G, and then gets removed, the logical place to store the zookie is in G, but if you do a permissions check for U on D, it would pass, as the zookie you would provide would be for D. Its not obvious how to guard against the new enemy problem if you have transitive permissions. I'm not sure there is a good solution, but would love to hear thoughts on it. |
Beta Was this translation helpful? Give feedback.
-
Yes, but that permission check result is fine unless the contents of the document have changed since the permission was removed, in which case, you'll (hopefully) have stored the updated Zookie/ZedToken on the document itself. If the contents of the document have not changed, the user no longer having access (within the cache latency window) should be fine: they previously had access, so the contents have already been "seen" by that user. Consider the following scenario:
ZedTokens/Zookies are designed to handle this explicit case: the expectation that its the content of the document that matters: if it was available to the user before, leaving them access within the cache window is fine, because they could have already downloaded that information previously. In other words, they are a new enemy, not a previous one. |
Beta Was this translation helpful? Give feedback.
-
That makes sense. If the document content was edited, there should be a new zedtoken written to it. The zanzibar paper even says as much, guess I need some more caffeine this morning ☕ |
Beta Was this translation helpful? Give feedback.
-
These are great explanations! You helped me a lot to wrap my head around ZedTokens! Makes a lot of sense. Somehow I thought I could potentially get very old permission results if I don't use the proper ZedTokens, and that made me a bit nervous. Thank you so much @josephschorr ! |
Beta Was this translation helpful? Give feedback.
-
@henkosch My pleasure :) Do you think it would be worth having another document or even a YouTube video describing some of this? |
Beta Was this translation helpful? Give feedback.
-
Thank you for the explanation @josephschorr! A document or video would be wonderful, I think this is quite an important concept and would help newcomers immensely. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the explanation. As far as I understand, your advice is to store the ZedToken with the new version of the document this way within the 5~30s window the user which is removed from a parent folder or a group will stil have access to that particular revision but not to new versions of the document ? What's your advice for the case where you store only the newest version of a document (no versionning), in this case the user will still be able to access the document even if the document is modified ? One more question, I'd really like to understand what's the performance impact of using |
Beta Was this translation helpful? Give feedback.
-
They will have access to the document so long as its content (and therefore ZedToken) has not changed, which is okay, since they previously had access to it
Update the ZedToken when the document's contents change; there isn't a need to store different versions of the document
No caching will be used at all, which means all load will hit the datastore at all time |
Beta Was this translation helpful? Give feedback.
-
It's clear now, thanks a lot ! |
Beta Was this translation helpful? Give feedback.
-
How would the inverse scenario work out where I add a user |
Beta Was this translation helpful? Give feedback.
Yes, but that permission check result is fine unless the contents of the document have changed since the permission was removed, in which case, you'll (hopefully) have stored the updated Zookie/ZedToken on the document itself.
If the contents of the document have not changed, the user no longer having access (within the cache latency window) should be fine: they previously had access, so the contents have already been "seen" by that user.
Consider the following scenario: