Single realm, multi-tenant, tenant scoped role setup advice

Dear Keycloakers,

We are investigating Keycloak as a future IAM solution to replace an in-house developed one. we would love some input on best practices and get your thoughts on our proposed setup:

Existing setup

Our product lives on a few domains with multiple tenants, a tenant has their documents, and users have different roles to work with them.

  • Documents belong to a tenant
  • Users belong to a domain
  • Domains have a default tenant
  • Domains can have more than one tenant
  • Users have a role on a tenant

So for instance we have app1.our-company.com where we have tenantA and tenantB where I can access and work with their documents based on my roles, as well as app2.our-company.com where we only have tenantC, etc. Some of our apps share a common backend API, and some have an app specific backend API.

The main open point for us is how we deal with the tenant scoped roles and how we can put this information in the access token to be used across all our backend APIs. So in an ideal world we would get an access token like

"roles": {
  "tenantA": ["role1", "role2"],
  "tenantB": ["role2"],
  "tenantC": ["role1", "role3"]
}

Then on each of our frontend clients and backend APIs can check exactly what access the user has.

Proposed solution

  • Single keycloak realm
  • Users no longer belong to a domain (single identity in the new Keycloak realm)
  • All our frontend apps get a public client in keycloak where the users can get a token which can be used with all our backend APIs (if the user has access of course!)
  • Tenant and role mapping represented as groups and subgroups - we then create a protocol mapper to put a list of the group paths in the access token, the groups do not have any roles attached, instead we use the path.

That last point is what we are currently not completely sure about. We would use the group path as a representation of the tenant and role mapping, so a user will have instead of the above:

"roles": [
  "/tenantA/role1"
  "/tenantA/role2",
  "/tenantB/role2",
  "/tenantC/role1",
  "/tenantC/role3"
]

Is this a common practice or is this something discouraged? We would be open to any suggestions for alternative approaches. I am aware that the preview organizations feature has some multi-tenancy features but this seems geared more towards users that only belong to a single organization, so I think this is not something we can use at the moment.

Thanks in advance,
Jonas

I wouldn’t overload Roles. Roles should transcend tenants. For example, both an admin from Tenant A and an admin from Tenant B should be able to add a new user to the system.

I would use Groups which aggregate your users by Tenant. Membership is set at the user level (group assignment). You’ll use a Mapper to put this in the token. Then your application can use the tenant for need-to-know. (Tenant A cannot add a user for Tenant B).

First create a Tenant Group

Next assign the User to the Group

Finally, create a Mapper to get the User’s Group in the Access Token

The resulting Access Token looks like this

image

Note that there seems to be a bug in the Predefined Groups Mapper, so create your own as in my screen shot. The predefined mapper "groups" is predefined incorrectly ¡ Issue #14516 ¡ keycloak/keycloak ¡ GitHub

Good luck

Or, if you are brave enough :grinning:, you can try the new experimental multi-tenancy functionality [1].

[1] Support for Customer Identity and Access Management (CIAM) and Multi-tenancy - Keycloak

Hi Carl and thanks for your quick reply,

I thought about something like this where we keep the roles and tenant groups separated but I believe I will run in to issues as we need to be able to have different roles for the same user on different tenants.

So for instance userA has access to tenantA and tenantB data in our application but only read access to A but full access to B. I don’t think I can achieve this when without the subgroups as roles approach or am I off?

Cheers,
Jonas

Hi embesozzi and thanks for the reply,

I had a look at the new organizations feature, but I think that is a no-go for us as the documentation mentions a user can only be linked to a single organization, but we definitely need the option of users having access to more than one tenant: Server Administration Guide

I also confirmed this quickly in docker:

If you have got any other ideas I would be keen to hear about it!

Cheers, Jonas

There is a mature extension that the Keycloak feature is largely “inspired”/copied from that allows users to be members of multiple organizations:

You can try it using the docker image here:

(I’m definitely going to check out the organizations feature.)

For the matrix of groups and roles from the OP, I would involve the application and have it maintain privileges outside of Keycloak. In the app in front of me there are many groups and nearly 1500 privileges. I don’t stuff all that in the token.

Instead, I use coarse-grained roles. For instance, an admin role that might range over all the tenants versus a general user role. This – along with the group – form a URL security scheme.

POST https://www.example.com/TenantA/notes

For access to a user-level resource “notes” in TenantA. And an admin example

POST https://www.example.com/admin/tenants

Then, the app picks up with the specific access granted to it. In the case of “notes”, you’ll need to check whether someone assigned the user to the read or write privilege for that tenant. Take group and preferred_username to build the vector of privileges.

Good luck

Hi,

is this extention free to use or is there a plan for this needed? Is the license of this tool in any way limited?

Thanks

It’s free unless you’re reselling it with Keycloak. We did that because we had some Keycloak hosting providers and “digital transformation” companies reselling our extensions (and in some cases passing it off as their own work).

It’s the same license as Elastic Search. keycloak-orgs/COPYING at main · p2-inc/keycloak-orgs · GitHub

Okay now i understand if i want to use it and host it myself and don’t sell it, its fine?

Is there a difference beetween: Support for Customer Identity and Access Management (CIAM) and Multi-tenancy - Keycloak and p2-inc/keycloak-orgs? Or is it the same tool?

Thanks!

They are different implementations of a similar concept, but have different feature sets.

1 Like

Hi xgp, thanks for sharing that, I was aware of the two org implementations, but did not look much in to the extension.

As far as I see you can have specific roles in an organization as well as being a member of a multiple ones, so this could fit our use case:

  "organizations": {
    "5aeb9aeb-97a3-4deb-af9f-516615b59a2d" : {
      "name": "foo",
      "roles": [ "admin", "viewer" ]
    }
  }

Is it possible to set up the organizations with a configuration tool, specifically GitHub - adorsys/keycloak-config-cli: Import YAML/JSON-formatted configuration files into Keycloak - Configuration as Code for Keycloak. as this is what we plan to use to configure our instances.

Cheers, Jonas

Hi Carl,

We came to the same conclusion with the course roles in the tokens and having each app manage its role → privilege mapping. However in the scheme you suggest I think we can not have a user be an admin of one tenant but only a user on another so which we need in some edge cases.

Cheers, Jonas

That specific tool doesn’t support the extension, but we built import/export endpoints you can use programmatically.

Thanks for the clarification, we will have a look to see if it suits our use case.

Yeah I was thinking of simple Roles like admin – which would range over all tenants — and user. “tenant-admin” would be a privilege. A privilege key is a Group (“tenant”) and a User and maintained by your app. Ex, I grant Carl tenant-admin for Tenant A.

I don’t know why I remember you mentioning the restriction to a single organization. Here is the merged pull request about allowing multiple organizations. Therefore, this feature will be available soon in KC.

Ah cool, thanks for pointing that out! We will have a second look at it then.

Thanks,
Jonas

I thought groups is just a collection of roles :slightly_frowning_face:

Instead of assigning user_1 the roles: backend_dev, frontend_dev
I would just assign the user to the group fullstack_dev that contains the two roles inside it.

Why not have multiple clients in your realm act like tenants?