-
Notifications
You must be signed in to change notification settings - Fork 278
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
Proposal: Support ABAC dynamically without hard code criteria in relation caveat, or provide caveat context in authn call #1966
Comments
Hi, before really diving into solution ideation, I think we need to clarify the problem to solve.
It's a tradeoff. One of the important aspects of caveat design is that it is safely typed. When an auditor reads the schema, they can understand what the behaviour is. As you can see in the blog post, we discussed a completely dynamic caveat versus the current implementation, and we though the latter is safer. We understand not all use-cases can be implemented when you don't know ahead of time the set of attributes. This is why we implemented So I don't necessarily agree this is "not a good idea" nor "weird". SpiceDB was designed from the ground up to be "safe" and hard to make mistakes in the schema language, and the current caveat design follows that philosophy.
I think that's understandable if you have an unbounded set of restrictions that you cannot predict upfront, hence the alternative idea of dynamic caveats. The idea is to basically provide a CEL expression as caveat argument, but you still need to define arguments based on the type system. We use this approach in some of our commercial features, but the functionality is not available upstream.
I'm confused by the usage of "auth" and "authn" in the context of authorization operations. are you talking about authentication here? I also don't agree with this take. A service has to talk to SpiceDB, you need to provide arguments, so there is already a level of trust established, regardless there are caveats involved or not. You cannot invoke authorization operations without providing arguments, whether that's caveat context or the rest of the RPC payload. And it's important to call out that nothing prevents the client application from completely ignoring what SpiceDB says and make their own authorization decisions. So you need to consider what your threat model is, and if you don't trust your own application, your probably need to look into a different strategy.
This is categorically stating that things should be one way. I don't think the reality is like that. The reality is that not all data can be stored because it's dynamic. Think of all the metadata that comes as part of an HTTP request, you could make authorization decisions based on the HTTP verb, the IP, time of the day, geolocation, etc. Caveats was designed to handle dynamic data like that. |
Hi Victor, thanks for your reply. First of all, I might need to clarify some terms:
And I might have different opinions about:
Yes arguments should be provided to SpiceDB when you talks to it, but here's a question, can callers provide these arguments?
Sure we can add a wrapper or adapter to SpiceDB which is responsible to provide attrs in caveat context during authz call, then define caveats like Netflix's case, then we go back to
For example, for SRE colleagues, they can access all services in the same region, while developers can only access servers which in environment developers are assigned. With current SpiceDB features, I must define two caveats, one takes expected and actual env®ion as parameter, another one takes expected and actual region as parameter. Or one complex caveat like:
Neither defining two caveats nor one complex looks like an elegant solution to clients, not to mention relation must be adjusted when attribute on server changes.
I totally agree with you about this. Context info should be provided in caveat context, while about attr-like persistent data, anyway they should be stored somewhere. Given that these attributes are quite close to authorization, and resources might inherit/override attributes from related resources, so I think store attributes in SpiceDB is reasonable, to enhance SpiceDB's capabilities in ABAC. SpiceDB is a great implementation of Google Zanzibar model, what I'm trying to do is provide embedded attribute fetching capabilities, to encapsulate authentication details as much as possible, keep caveat definitions and relations as stable as possible, as simple as possible when community developers want to implement ABAC model based on it. |
I don't have enough context about your business domain to be able to provide more feedback. But what the things that I think I gather from your comment are:
If the information is not dynamic at all and is not provided at request time because it can be stored, then caveats is not the right tool for the job here: the core SpiceDB's relationship-based paradigm should be used to model your business domain, which means introduce all those tags as first-class The problem with caveats is that it's very easy to pattern-match with previous experiences (e.g. if you are using a "descendant of XACML" - anything that looks like a traditional policy engine), and folks may miss the powerful relationship-based paradigm at the core of SpiceDB. I'm not saying you requirements can be definitely implemented here, but I'd probably start there and see if there is anything in the core language (i.e. everything but caveats) that can be augmented to support your use-case before jumping to caveats. I certainly recall working with other community members in relatively similar domains that didn't have to resource to caveats. |
Hi Victor,
One possible solution would be running auth check with SpiceDB, then run additional attribute check in wrapper system. Sounds possible, while in my case, resources could "inherit" attributes from its related resources, relationships are stored in SpiceDB, I have to do sth similar as SpiceDB does, to iterate relation paths and get values I want. I just couldn't help to have a feeling that sth is not done in SpiceDB properly, so I have to finish its job somewhere else.
I do respect the philosophy of the project and agree with the importance of subproblem decomposing, I just don't see why introducing attr k/v would harm that. Now I can create a relation tuple in SpiceDB even if the entity don't exist at all, still I can create attr k/v for non-exist entity. I can delete one entity from its source system, then notify SpiceDB to delete relevant relations (or just do nothing, leave them there), so as attr k/v! Attr kv's can be handled in the same way as relations did. I just don't see any conflicts/differences between these two concepts. Providing suck solutions (sorry to use it but just as you state) to ABAC scenarios to keep relation as the only one first class citizen doesn't sound like a wise choice. And by the way we are even discussing about node entity lifecycle management internally to avoid updating all affected relations when an entity node is deleted. By saving "entity deleted at zedtoken/transactions" info internally, then in relation searching process we can check relation's created transaction against subject&object's delete transaction, relations with lower transaction are filtered cuz they are not valid anymore.
I'm not suggesting "evaluate caveats at any point in the graph" either, it is still evaluated at the very end of check function call. Get attrs for origin input subject&objects then run value comparison accordingly. There's no need to care about attr kv's or caveats when solving subproblem, just like before.
ReBAC auth model has its own beauty, I don't think people who choose Spicedb would ignore that paradigm and just use it to build traditional auth engine. But still, some tricks could be taken from traditional engines to make SpiceDB always easy to use, not only when you use it carefully and laboriously right? At least duplicate attrs in in relation tuple is not good enough. If possible, I would like to join your further discussion with other community members about this topic (or similar topics) |
Can you clarify what you mean with auth check here? I'm not sure if you mean authentication or authorization. I don't understand enough of your business domain to be able to help. Based on some of the information you wrote in the discussion body, I created this playground example:
I am not saying it compromises that, but it requires carefully thinking about how to fit it to retain the system's scaling properties.
I talk from my experience as a maintainer. I don't know anything about the person on the other end so I can only try to take a step back and see what problem they are trying to solve, just like I'm doing here. |
Hi Victor, Thank you for showing me that example, relation-based attr maintenance does work perfectly for that simple case, while in my case:
Besides I'm afraid schema definition like that is not intuitive enough, at least it might take me a while to come up with a schema like
Maybe it should not be a problem I guess? (Please correct me if I'm wrong or something I don't see) I fully understand as a project maintainer, you need to think carefully before introducing something new, definitely as a developer using SpiceDB I should thank you for that. :) About the requirement we're discussing about, I guess both of us could have some take-aways. Anyway I do hope we can have native solutions to such requirement in SpiceDB in the future lol, let's keep in touch if any idea pops up. |
I understand that a relationship-based model takes a while to get used to, but I believe there is a payoff to the investment. I'm probably not the most representative user of the system, since I maintain it, I get that, but after some training, it comes naturally. Your use case seems to heavily lean into policy and ABAC and it's not fitting well with the currently supported set of features, although there are things we could do to address that, I'm wondering what drove you to start with a relationship-based access control model in the first place. What specific aspects of the model do you think were a good fit for the problems you are facing? Perhaps you were looking into the ability scale across the globe like Zanzibar, or have tunable consistency parameters because your application demands it? Perhaps the ability to scale horizontally?
Stored caveat context is part of the relationship, so as the graph is traversed, relationships and their context are loaded. It flows naturally with the execution engine and the way problems are decomposed. To load the data, we probably want to eagerly load the additional data as part of the relationship load, and we need to do it on a single round-trip, so we'd need to JOIN the relationships resource and subject type/ID pars with another table to enrich the context with data coming from the "entity context storage". SpiceDB does not do any JOINs at the moment, and that could be problematic with distributed databases like CockroachDB and Spanner (SpiceDB has to support multiple databases) where JOIN may require cross-node coordination and would almost certainly add latency. The alternative to piggybacking into the current relationship queries is to do follow-up queries, and you can either do that on every relationship query (probably a bad idea) or at the time the collected composed CEL expression is evaluated in the entry-point node with the API call input context. This would add just one additional roundtrip, but one of Zanzibar's core design principles is to avoid as much database access as possible doing all sorts of tricks, but mostly reusing work that has been already done. At that point we've lost information on the relationships that have been evaluated - all we have is a "smushed/flattened" composed CEL expression, and we've lost information on the relationships whose "centralized context" you should have loaded in the first place. Turning that into internal API dispatch metadata will also be problematic, adding more overhead to dispatching API. I hope this sheds some light on the complex machinery inside. There is a reason caveats were designed to be stored along the relationships, as it fits well with the core design principles. I think adding a centralized caveat context store for entities is an interesting idea to explore and could make some use cases simpler to manage. I appreciate the discussion and the insight into the problems you are trying to solve. I'll open a feature request to gather more feedback from the community. EDIT: Opened #1981 |
Hi Victor, Thanks for the clarifications above.
I fully agree table join is not a good idea in such a latency-sensitive system.
Yes loading entity attribute data would definitely increase API latency, but if we take a look at the whole auth check system call chain, someone, either client or auth system has to get it loaded. The time cost is inevitable from end-to-end point of view, but only if authorization grantor uses ABAC-like features. I understand caveat evaluation with attributes causes one addition relation graph traversal for attr data, but again, only ABAC-like-auth-check-enabled cases are affected. Pure ReBAC and "static caveat" cases are not touched at all. (My humble opinion just as an application developer: if something has to be done, then just pick the right guy to do it. With attr features encapsulated in auth system, auth check callers/attr maintainers/authorization grantors could be decoupled completely from each other, that's a win-win solution in my case) |
Problem Statement
I'm implementing ABAC auth check with caveat feature, like "only employees with [env=prod,region=sg] can access servers in Singapore production environment". In Netflix sample case, resource attributes to be checked are specified in relation caveat, while user attributes are provided via caveat context in CheckPermission endpoint. But I have some concerns when defining auth check caveats.
Suppose we have a hierarchical server structure and organization structure scenario like this:
Where:
Then:
Authz check related attributes vary from case to case, I don't want to define several caveats for several cases.
I think it's inappropriate to run auth check based on input attribute values in caveat context, cuz authz caller doesn't know (or even doesn't care) what attribute the server to be checked is carrying. Besides, provided context might not be trustworthy, authz system should work as a standalone system which only depends on authn truth stored internally or verified data.
Solution Brainstorm
I have an idea about problems above:
resource_type:resource_id
can have tag KV pairs associatedpseudocode for
is_any_tag_matched
:This function is provided is provide by a cel library loaded at run time, which carries subject and object info in function closure.
getObjectTag
,getSubjectTag
andisAnyIn
functions are exposed for caveat usage as well.Then authn caller would just need to call
check permission server:srv1 access user:user1
, without fetching resource tags and passing them via caveat context param.Besides, we can tell other fancy stories based on this, for example:
role_binding
is assigned tospanner_database
, bound withuser
androle
. With features mentioned above, authn admin can assign auth statically specifically, by maintain tags onrole_binding
, or assign auth generally like usually, without change any schema definitionNow the development is done, and I'm running tests against it locally, I would like to share this idea with you and contribute if it's useful to the community as well. If you have any suggestions/questions/concerns, please just let me know.
The text was updated successfully, but these errors were encountered: