[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