[keycloak-dev] user groups vs. client groups

Adam Young ayoung at redhat.com
Sun Nov 22 21:13:17 EST 2015


Hey guys, just catching up on the discussion.  Let me share  some 
lessons learned from the Last four years on OpenStack Keystone working 
on a very similar problem.

Keystone started off with three concepts: users, (global) roles and 
tenants.   A user was either an admin (based on a role) or assigned to a 
tenant.

Tenants were groups of resources not managed by Keystone;  Virtual 
machines, disk images, and the like.  All access control was managed by 
the user having a token scoped to the project.

Admin was a global role...but at some point, someone decided to make it 
scoped to a tenant.  And things go weird.  But it made sense: within a 
proejct, some resources were more sensitive than others, and needed an 
increased level of security.  But since all of the access control policy 
was written with global roles, things were actually just kind of 
broken.  It lead to one of the oldest bugs in Keystone, and it is still 
assigned to me.  I think we will have it licked this round...but that is 
jumping ahead.

Keystone was written with a plugable backend approach.  THe default was 
Key Value stores (memcache was heavily used) but SQL was very dominant. 
However, we realized that, for users, we needed to be able to pull them 
out of LDAP, as most companies have large, embedded user databases, and 
they want to user them, not copy them.  So, projects in Openstack mapped 
to groups in LDAP, and users had assignments to groups.

It was an uncomfortable fit.  Tenants really were OpenStack 
abstractions, and with them coming from LDAP...which was almost always 
read-only, they were not editable by OpenStack resources. This was a 
restriction that we dealt with for a while.

A couple new abstractions found their way into Keystone:  groups (of 
users) and domains.  Domains were groupings for both users and tenants.  
And this has continued to haunt us, because it confused two things. The 
above situation with LDAP showed that the users needed to be separate 
from the tenants.

Oh, and we also changed the name from  tenants to projects to keep 
consistent with the rest of OpenStack...want to piss off your users?  
Change a key term out from underneath them...


It became clear the we needed to manage users and projects in different 
ways.  Users were read only from LDAP, projects were writable from 
OpenStack.  We split the backends along these lines: Identity manages 
users, groups, and user-to-group assignments.  This was due to the4 
expectation that the group information from LDAP was going to be 
required for managing users, which has proven to be of questionable 
worth.  The assignment backend held projects, roles, and role 
assignments.  Domains were in there as well, but it was an awkward fit, 
as domains really spanned both Identity and Assignment.


We also changed how the  user to projects mapping was handled:  we use 
role assignments for everything.  Domain *owned* users, in that they 
were records under the domain object, but a user got no permissions due 
to being managed by a specific domain;  only via role assignments.

Things really got funky when we fully integrated Federation in to 
Keystone.  Now, we had two abstractions for managing users:  Domains and 
Identity Providers. Instead of making a hard relationship between the 
two...we sort of let them float.

The most hackish part is the Mapping. This is what takes the values from 
the federation assertion (SAML for the most part) and maps it to 
Keystone Identity objects (users and groups).  While we should limit 
what IdP can map to what domain,  we don't.  What this means is the 
managing the mapping must be done by an admin, and that is a 
cetrnalization I had hoped to avoid.


What do end users really need?  They  need a reusable set of role 
assignments that span mulitple (micro)services.  We are almost there, 
and a few more iterations and we can get there.  Keystone handles only 
the core OpenStack services, but it would be much more useful if we 
could open it up to the cloud in general, and make it so people could 
use the Federation mapping defined in there to provide Access control to 
applications running in the cloud.


Lessons learned:

Scope roles to your target abstraction from the beginning.  Call this 
Scoped RBAC, as opposed to what NIST does.  NIST is implicitly scoped, 
make KeyCLoack be explicit.  Call it project, tenant, target, 
application, I don't care;  but a user should have a role on 
*something*, otherwise you end up with namespacing inside the role 
names, and a second level of mapping required.


Provide rules that allow one to explicitly assign a single role, and the 
target user gets that explicit role and multiple implicit roles.   The 
end product is actually as set, not a tree, so just watch out for 
cycles.  It does not have to be a strict hierarchy, so long as it is a 
Directed Acyclic Graph, you are safe.

Namespacing of roles is a client organization thing; it does not need to 
end up in the roles shipped to the end application, so long as you have 
a global definition of what roles mean what. Regardless, the namespace 
needs to disappear when sending the assertion, or the remote side can;t 
use it.  So, knowing "who" you are getting an assertion for is 
essential.  Two different Wordpress installs mean two different role 
assignments:  admin on one, editor on the other.


You don't own the user database.  Assume it is going to be read only.  
Provide a local means to manage groups of users separate from, but on 
top of, the groups that come from the federated source of Identity.



OK, that is a lot of a brain dump from someone you all don't even know.  
PLease ask me questions about the details.


I'm pretty impressed with what I've seen of KeyCloak thus far. Looking 
forward to getting to know it better.











More information about the keycloak-dev mailing list