-
Notifications
You must be signed in to change notification settings - Fork 24.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add cache for application privileges #54317
Comments
Pinging @elastic/es-security (:Security/Authorization) |
It is probably obvious. My overall approach will be like the follows. Please raise any concerns before I commit deeply into the changes. Thanks.
|
I don't think it's necessary to use the ListenableFuture stuff from the CUPR, a simpler cache is probably sufficient. The tricky bit to think through will be what you cache by. The main method on NPS is
With special cases of:
So we could have two approaches to caching
The former will be more efficient for repeated searches on the same values, but by useless when the query is slightly different. E.g. If we have an up to date cache Caching-by-id will mean that a wildcard search will populate the cache so that a future request to get a named privilege will be fast, but it would not really help with caching of the original wildcard query. Cache-by-query is trickier to keep in sync with updates to privileges. You'd either
I suspect it might be worth having both caches, but we'd need to think it through. |
@tvernum Thanks a lot for the discussion. Here is my analysis. TL;DR The
For use case 1 ( For use case 2 (GetPrivileges), it can only take a single application name, which can be wildcard. But this wildcard is enforced to be at the end of the string, i.e. For use case 3, it always pass Based on above analysis, I'd propose that the cache should be keyed by the application name (literal name, no wildcard) and the values are a set of With this design, use case 3 is easily covered. If a single application is required, it is a direct retrieval from the cache. If mulitple appliations are required and some of them are not available in cache, we can fetch for the unavailable applications only. Use case 2 can also be catered reasonablly. If the application name is not a wildcard, e.g. If the application name does contain wildcard, e.g. The cache will be invalidated when there are chanegs to the privilege documents. We can invalidate everything whenever there is a change. But it should be relative easy to just invalidate the applications that have been updated and leave others untouched. |
My above analysis has two oversights: First oversight A simple solution is to always fetch all privileges for an application regardless of what the request asks. This makes things simple to handle but has the downside to retrieve more than what is actually need. Or an even simpler solution is to not cache the "get privileges" use case. From Kibana's perspective, it is probably not too bad since it calls "has privileges" all the time. Another solution might be cahcing the incomplete list and then explicity mark these cached entries to be excluded from subsequently retrieval. This however adds additional complexity. Second oversight A simple and crude solution is to set a upper limit for number of ApplicationPrivilegeDescriptor that an application can have. If the number is exceeded, we don't cache it. Another possibility is to have the cache limited by actual resource it consumes (e.g. Lucene's Accountable classes). But not sure how feasible it is. Alternatively , The first "query" cache could suffer from the same problem of potentially unbounded value entry (list of matched documents IDs). But since it is a list of simple strings, the issue is not as bad. It also has the problem of duplication since two sets of document IDs from two different queries could overlap, e.g. query of "*" compared to query of "Kibana". There is no simple solution for this and a complex solution is unlikely worth the effort. Another alterntively is to have the cache keyed by In summary,
They both have pros and cons. I personally feel the first option is overall more attractive. But I am open to suggestions. |
Is this true for API Keys? Since we currently have a per-API-key role, and know that we may have many API keys with the same role descriptors (but unique cache-ids) it feels like some caching here would be useful.
I don't think that's unreasonable given that has_privileges needs it. It would greatly simplify the code in the
This is easy to do. You pass a
That's my gut feel also. |
I think Improving pseudo role caching is a better way of handling this. In addition, even without it, the price to pay here is one call per API key at its first authentication. This is a known initial cost and not ongoing. So I think it is affordable. If we get role caching thrashing, then we have a bigger problem not just additional round-trip for application privileges.
If we do make this change across the board, the caching mechanism will work for
Awesome! Thanks for the discussions. I think I am ready to get some hands-on now. I'll proceed with option 1 and cover usage 2 and 3 (get and has privileges calls). |
When we added Application Privileges we intentionally didn't cache them because the semantics of a distributed cache can be tricky (we've had to tweak the user & roles caching logic several times) and we weren't sure how necessary it would be
We've recently seen a few places where that lack of caching had an impact, and it's probably time to bring it in.
The text was updated successfully, but these errors were encountered: