semantics of SpiceDB permissions with multiple sub...
# spicedb
c
We are having a discussion regarding definitions and relations. Is there a correct way. Here are two simple examples: definition subject_a { } definition subject_b { } definition resource { relation rel_a: subject_a relation rel_b: subject_b permission read = rel_a + rel_b permission write = rel_a } VS: definition subject { } definition resource { relation rel_a: subject relation rel_b: subject permission read = rel_a + rel_b permission write = rel_a } Is it correct the result of the above examples, is the same?
v
👋 it's not the same. - first one you have 2 different subject types. When you do an API call, you always define a subject as part of the request, so the API will ignore those types that do not match so if for example you do:
CheckPermission(resource:1#read@subject_a:2)
Then SpiceDB will evaluate your schema as, roughly speaking:
Copy code
definition resource {
  relation rel_a: subject_a
 
  permission read = rel_a
  permission write = rel_a
}
If you do
CheckPermission(resource:1#read@subject_b:2)
Then the equivalent semantics are:
Copy code
definition resource {
  relation rel_b: subject_b

  permission read = rel_b
  permission write = nil
}
- on the second example the subject type is the same so both relations will get evaluated:
CheckPermission(resource:1#read@subject:2)
becomes
Copy code
definition resource {
  relation rel_a: subject
  relation rel_b: subject

  permission read = rel_a + rel_b
  permission write = rel_a
}
c
I have made an example in playground https://play.authzed.com/schema As far as I can see, the assertion and expected relation will give me the same permission?
Maybe I have understood the difference. The end result is the same, but the operation will be more complex, with the generic subject vs the individual subject?
v
you need to export the link so I can see your schema
I just don't understand what you are trying to achieve. There are legitimate uses for multiple subject types. For example if you application has
user
types but other something like a
bot
or
service_account
or
token
The problem is we only know the subject type at creation time. Further down the line the other services only know it is a subject, so we need a more generic way to be able to distinguish the subjects. Then I was thinking to split in relation in stead of subject. It looks like the result is the same.
v
why then defining multiple subject types if at check time the application does not care about it? Feels like an incorrect mapping from the business domain into the schema
c
In our case the checks we would like do is must user with id X read document with id Y. At check time, we don't care about user type. We still care about user type, depending on relation to a document collection in between.
v
what types of users are there in your domain?
why do you need the distinction?
can you add the user "subtype" as part of the user ID?
is it a matter of ID collision between the different user types?
>We still care about user type, depending on relation to a document collection in between. can you give me an example where the user type matters?
c
In my example I sent you what is the problem with the more generic example vs the typed? I have still created a typed relation, and the check will end up with the same result?
v
there is no problem with it. It's a valid SpiceDB schema. But I don't know if it's the right solution if I don't understand the problem you are trying to solve.
c
@User If you look at this extended example. It illustrates a way we could achieve, to add typed relations, but make checks in a generic way on document level. Ex. can user x read document y. Without knowing if user X is internal or external and document y is shared and internal. With this we can make a document service where we only need Id of user and id of document, to get a document and verify if the user can read it or write. In the real live scenario, the id's will be uuid's. https://play.authzed.com/s/x2k_K5mMz6dI/schema definition user { } definition doc_col { relation intern: user relation extern: user permission read_intern = intern permission write_intern = intern permission read_shared = intern + extern permission write_shared = intern } definition doc { relation doc_intern: doc_col relation doc_shared: doc_col permission read = doc_intern->read_intern + doc_shared->read_shared permission write = doc_intern->write_intern + doc_shared->write_shared }
v
yeah this makes sense: you are qualifying the type of user via a new relation. That's the way to go 👍 I've been trying to decipher a bit of your business domain, so I'm making some assumptions and taking the liberty of renaming some things just to that it's easier for me to follow: - there are users and documents - users can be internal or external - documents can be internal or shared - documents can be read by both internal and external users, - documents can only be written by internal users I'm probably not getting it right, but hopefully you get the gist of the mental exercise by looking at the schema. I always like to start laying the business domain in plain english and then start modelling from there. I landed on something like this
Copy code
definition user{}

definition platform {
  relation internal: user
  relation external: user

  permission internal = internal
  permission all = internal + external
}

definition doc {
  relation visibility_internal: platform#internal
  relation visibility_shared: platform#all

  permission read = visibility_shared
  permission write = visibility_internal
}
If instead of top-level users you have something like an
organization
, then you can replace
platform
with
organization
and it should be mostly the same I couldn't quite infer the semantics of "internal" and "external" in your example, as it does not seem to make much a difference.
c
@vroldanbet we are going to have a meeting with Authzed today, about general principles and some reviewing of our model. So thank you very much, for your help, with the above 🙂
v
anytime! 🙇‍♂️
14 Views