Howdy all - I'm (re)trying to create a
# spicedb
d
Howdy all - I'm (re)trying to create a schema setup with users and 'permission profiles'. These profiles can be assigned to the user (only one per user). The profile havea bunch of permissions attached, so to do anything we will need to consult the user's profile to check that it has the correct permission. In this schema example I am trying to introduce the rule that a user's management page can only be accessed by users with the correct admin profile permissions https://play.authzed.com/s/nHmuQb-gxtXT/schema
Copy code
yaml
definition user {
    relation team: user_team
    relation profile: profile_binding

    // You can access a user's page if you are the admin of all users, or this user is in your team
    permission access_management_page = profile->admin_all_users + (profile->admin_team_users & team->same_team)
}

definition user_team {
    relation member: user
    permission same_team = member
}

definition profile {
    // Possible permissions each profile could have enabled
    // user:* => “any user who holds this profile will have this permission”
    relation admin_all_users: user:*
    relation admin_team_users: user:*
    permission admin_all_users_enabled = admin_all_users
    permission admin_team_users_enabled = admin_team_users
}

// This is acting as a synthetic relation (not needed once nested -> is a thing)
definition profile_binding {
    relation bound_user: user
    relation bound_profile: profile

    // Check that user has the profile AND the profile has the permission
    permission admin_all_users = bound_user & bound_profile->admin_all_users_enabled
    permission admin_team_users = bound_user & bound_profile->admin_team_users_enabled
}
It works... BUT the issue I have is when I setup the relationships - now every user needs to know about every profile binding...
E.g.
Copy code
user:admin_laurence#profile@profile_binding:laurence_is_profile_admin_all_users
user:basic_ben#profile@profile_binding:laurence_is_profile_admin_all_users
user:admin_jaram#profile@profile_binding:laurence_is_profile_admin_all_users
user:admin_laurence#profile@profile_binding:jaram_is_profile_admin_only_team
user:basic_ben#profile@profile_binding:jaram_is_profile_admin_only_team
user:admin_jaram#profile@profile_binding:jaram_is_profile_admin_only_team
This feels wrong and like I'm missed something? I based my approach off the google iam role example.
I believe this example is tricky due to the 'resource' being the user object itself...
y
> now every user needs to know about every profile binding can you elaborate on that? and i'm not entirely sure that it applies here, but if the idea is that a user either has the permission on all resources or on no resources, it's usually better not to reference the resource in the permission
if that makes sense
at my last job we used a singleton
platform
object
and to say whether an admin had a permission that was effectively binary all/nothing, we wrote the permission as referencing that platform object and then checked the platform object instead of the resource
does that make sense?
d
> can you elaborate on that? What I mean is, when I define the user relationships (see my second message) I have to map every 'profile_binding' to the 'profile' (poorly named) attribute of the user. This is so the user can access the profile binding directly for the access permission check e.g.
profile->admin_all_users
> and to say whether an admin had a permission that was effectively binary all/nothing, we wrote the permission as referencing that platform object and then checked the platform object instead of the resource I think so - we could instead store the profile_binding on a higher level? Something like this? https://play.authzed.com/s/fYsm5HTEBXvB/schema
y
yeah, the usual model for a google cloud iam-style permission is that you tie the resource (in this case the user) to the role_binding in addition to the role and the subject (also a user)
so what you're doing there makes sense
> // This is acting as a synthetic relation (not needed once nested -> is a thing) to clarify - i'm not sure this is true, because there's intersection logic happening on the binding
the binding is where you tie together what a user can do (the role) and the object on which the user can do it (the resource)
d
Ah my mistake - im still very much a spice noob
y
and lemme give you an example of what i'm talking about with a platform object
d
Thanks for the help!
y
no worries! i still feel like i'm wrapping my head around schema modeling and i've been doing it for a while ^.^
so if a user is either going to be able to view all of the access management pages or none of them, you'd check on the
platform
object rather than the
user
object
and as a general rule, it can help to make a check as granular as makes sense from the perspective of writing and maintaining fewer relationships
so like if a user is either going to be able to view all of the `access_management_page`s or none of them for (say) an organization or a team, you'd check on the organization or the team, not on the user
d
Your example makes sense thank you - in our case its not as simple as 'user has access to all `access_management_page`s or none. It's more - we have profiles (essentially roles) and the profile can have either - allow access too all
access_management_page
permission enabled OR allow access to
access_management_page
of only users in your team. I have attempted to follow your approach here - using organisation as our singleton - https://play.authzed.com/s/xS8FUsgtpmeX/schemae
Im trying to get spice to match our legacy profile system approach - where a profile can have many different permissions enabled or disabled. A user can only have one profile assigned. So we need to always get the user's profile to check if they have a certain permission enabled. Not sure if this can gel with the proper spice approach or not.
y
> a user can only have one profile assigned there isn't a way to enforce this at the SpiceDB level currently. we've got a propoosal in the works that would allow you to enforce a 1:m structure on a given relation, but i'm not sure that would help in this case because the profile bindings obscure things. if a user only has a single set of perms across all objects, you could collapse the role_binding and role definitions together. that may fit the semantics of your system better. the reason that it might not be desirable is that if you want to change the definition of a role, you have to touch all of the roles that all users have in order to update them. but again, that may match what you're trying to do
4 Views