[keycloak-user] Using Keycloak for per field authorisation

Pedro Igor Silva psilva at redhat.com
Tue Aug 14 08:06:25 EDT 2018


On Tue, Aug 14, 2018 at 12:27 AM, Courtney Robinson <
courtney.robinson at hypi.io> wrote:

> On Tue, Aug 14, 2018 at 2:54 AM, Pedro Igor Silva <psilva at redhat.com>
> wrote:
>
>> Sorry for the late reply ...
>>
>
> Not at all. Thank you for the detailed response.
>
>> The other case I mentioned in my first email is where, a user in an
>>> organisation has created e.g. a "Book" record. Under default policies only
>>> they can see and manage this Book they created. They can then share this
>>> book with site 2 so that users in site 2 can also read the book, they may
>>> also share it with the whole organisation so anyone in the realm can read
>>> it. The extension to this is when members of one site could normally only
>>> see a subset of fields from Book but one one occasion a user shares a
>>> single Book with one or more members giving then the permission to "manage"
>>> this one Book. This lifts the limitation on this one instance of book
>>> enabling the user it is shared with to access a field of Book they wouldn't
>>> have been able to see before.
>>>
>>
>> Now I see, thanks. I was imagining something like that.
>>
>> In Keycloak, resource can have a type [1]. A "typed" resource is a
>> resource which owner is the resource server (when I say resource server, I
>> mean the client application you are setting up permissions). You can define
>> permissions to these typed resources [2] where these permissions will be
>> considered when deciding whether or not access should be granted to other
>> resources with the same type, where these other resources are actually
>> instances of the "typed" resource (the class example you gave). Resource
>> instances have users as resource owners, not the resource server. That is
>> the difference between a typed vs resource instance.
>>
>> Let's take the case you mentioned as an example. You have a "Book
>> Resource" with a type "book" and permissions associated with this book.
>> Where policies associated with this permission only grants access to the
>> owner of the resource. Once you have this configuration, create a resource
>> as follows:
>>
>> curl -X POST \
>>   http://localhost:8180/auth/realms/{realm}/authz/protection/resource_set
>> \
>>   -H 'Authorization: Bearer {access_token}' \
>>   -H 'Content-Type: application/json' \
>>   -d '{
>> "name":"Alice Book",
>> "type": "book",
>> "resource_scopes":["read", "manage"],
>> "owner":"alice"
>>       }'
>>
>> The command above is creating a book where user "alice" is the owner.
>> Note the "type" field defined as "book". Once you do that, if you try to
>> use the policy evaluation tool [3] to check permissions for "alice" on
>> resource "Alice Book", access should be granted. Note that we did not
>> define any permission for "Alice Book" directly, permissions are being
>> processed based on what was defined for "Book Resource".
>>
>> We also allow you to override permissions on a per resource instance
>> basis. So, suppose you want to also allow some other user to access "Alice
>> Book". You just create a permission for this resource granting access to
>> the user you want.
>>
>
> Ahhhhh! That example sheds some light on things for me. Thank you for that.
>
>
>> We also support UMA, a standard focused on privacy and resource sharing
>> requirements [4]. We have an extension to UMA (contribution from community)
>> that allows resource servers to define custom permissions for user-managed
>> resources [5]. When using UMA capabilities, your users are allowed to
>> manage their resources via Keycloak Account Service.
>>
>> [1] https://www.keycloak.org/docs/latest/authorization_servi
>> ces/index.html#typed-resources
>> [2] https://www.keycloak.org/docs/latest/authorization_servi
>> ces/index.html#_permission_typed_resource
>> [3] https://www.keycloak.org/docs/latest/authorization_servi
>> ces/index.html#_policy_evaluation_overview
>> [4] https://www.keycloak.org/docs/latest/authorization_servi
>> ces/index.html#_service_user_managed_access
>> [5] https://www.keycloak.org/docs/latest/authorization_servi
>> ces/index.html#_service_authorization_uma_policy_api
>>
>>
>>>
>>>
>>>>
>>>>
>>>> Regarding how the adapter (policy enforcer in particular) work. It
>>>> verifies permissions locally in case the client is sending a bearer token
>>>> with permissions, otherwise the adapter will query the server for
>>>> permissions associated with resource the client is trying to access
>>>> (mapping is based on URIs).
>>>>
>>>
>>> I had a feeling. One of the reasons I'm so unclear about how to achieve
>>> what we want is that it feels like a mixture of the auth policies Keycloak
>>> supports is needed.
>>> I've been thinking that for each app, default Keycloak policies are
>>> created that e.g. allowed read only within an organisation.
>>> Use Keycloak groups to represent "sites" e.g. offices in an organisation
>>> and applied default policies to the groups.
>>> Then, the key thing I thought was that I'd have to register each type
>>> and it's fields in Keycloak as resources and then have a fixed list of
>>> scopes read, write, update, delete, share etc
>>> When an entry/instance (say of a Book) is shared, the model changes from
>>> being type based to being based on the ID of the object i.e. the Book's ID
>>>
>>
>> It makes sense. However, I don't think the model needs to change. Your
>> typed resource will always be there. What you need to do is create new
>> resources (with their corresponding types) representing those
>> "entries/instances".
>>
>
> Got it.
>
>
>>
>>
>>>
>>> If I understood correctly, that means the size of the token will grow
>>> with each object shared directly with a user, surely a problem.
>>>
>>
>> Not really. It depends on how you want to enforce ermissions.
>>
>> If you don't want to evaluate permissions all the time, you can obtain a
>> token with some initial permissions. Then you can perform incremental
>> authorization to obtain more permissions in addition to those previously
>> granted. We also support limiting the number of permissions in a response
>> from the server. [4]
>>
>> In next release, we are also supporting a response_mode parameter that
>> you could use to define the format of responses from server. These formats
>> are specially useful in case you don't want to use permissions from access
>> tokens but invoke server to only obtain permissions.
>>
>> [4] https://www.keycloak.org/docs/latest/authorization_services/
>> index.html#_service_obtaining_permissions
>>
>
> We'll have to give this one some careful thought, latency is a big
> concern. Some of our customer's use cases demand low latency (automated and
> pseudo real time decisions) so in general an approach that minimised round
> trips to Keycloak would be best. It's a real mixed bag though because most
> cases are web application flows that do not have this low latency
> requirement.
>
> One of us in the team will be working on this in our next sprint so a lot
> of things should fall into place as part of this.
>

In the next release, we are also delivering improvements around
performance. We found places we could improve and especially the policy
evaluation engine. We have introduced some cache layers to avoid redundancy
when evaluating permissions/policies. Let us know about your experience, we
know we can still improve it. But as the first work we did around
performance tests, the results are pretty much good (and much better from
previous releases).


>
>
>>
>>
>>> In a similar vein, do I have to create an entry for every Book record in
>>> keycloak to be able to do per book permissions?
>>>
>>
>> Yes. You could use a single resource + JS policy too, but there are
>> several issues doing that.
>>
>> People suggested a Resource SPI, which could be used to fetch resources
>> from external databases ...
>>
>>
> I take that as suggested but hasn't been done yet? (Given I've not seen
> the interface in the codebase or mentioned in the docs) We'd be very
> interested in this. Our storage is centred around Apache Ignite and a great
> deal of effort's been poured into understanding and working with it. One
> outstanding concern with our proposed move to Keycloak for authorisation is
> understanding how to scale it well with the rest of our stack.
>

Not it is not and you are not the first one from community with similar
requirements. Maybe we could start discussing and including this in our
roadmap.


>
> I've had an attempt at a user SPI and concluded we'd be better off pushing
> it to Keycloak backed by Postgres. (Considered if we could write an Ignite
> drop in or something similar but the effort wasn't worth the initial
> perceived gains since users are probably going to remain relatively small
> compared to resources).
> Out of interest however, Keycloak's using Hibernate right? How pluggable
> is this so that it could be replaced with Hibernate OGM?
>

IIRC, OGM is based on JPA spec, right ? If you mean implementing User SPI
sing OGM, it should work.


>
> For resources this (scaling) is still an open question. We're Kubernetes
> based and a base line for our services is to configure it with a minimum
> number of replicas and use metrics and auto scalers to grow that based on
> usage. Some of my questions may seem odd but as well as the functional
> aspect I'm working out how/if this fits in operationally as well.
>
> We have one particular customer with an IoT use case at the moment which
> can be quite bursty their entire setup is automated including policies on
> who/what can see different pieces of data being produced by devices.
> Resource types are relatively fixed in the order of a few thousand,
> instances are however hundreds of thousands per hour and can burst to
> millions. Those numbers have been steadily growing and we're expecting more
> customers with similar or larger numbers.
>

Nice. As I mentioned before, we have been working with performance
improvements. During this work I noticed that performance is not really
related with the number of resources or scopes, but on how you design your
policies and how you obtain them from server. For instance, if you query
the server for all permissions an user has, you would not get good
throughput. However, if you can perform incremental authorization, ask for
chunks of permissions, etc, you will get a good throughput. Of course, this
is relative, I could give you numbers but that could be misleading and not
based on your real constraints.

This is an area we want to improve for now on, so, feedback is always
welcome.


>
> This is why I was particularly keen to get some answers around whether
> we'd have to register every instance in Keycloak, about token size and
> trips to Keycloak, we're comfortable scaling ignite and the rest of our
> stack but unclear exactly what that means for Keycloak, I've seen and have
> currently got an HA Keycloak and Postgres setup and just starting to look
> into doing stress tests but figuring out our auto model first since it
> doesn't make sense to stress it with one scenario and then implement
> another!
>
> At the moment some of these things aren't a concern because we use Apache
> Shiro in the service so there's no network round trip and our make shift
> "policy evaluation" uses the user defined rules that are largely based on
> patterns so doesn't need per instance permissions meaning low cardinality
> on policy/permissions. With your explanation I now understand how this can
> be done but I'm still left with some concern about permission growth for
> these automated use cases. Since they're user defined, the slightest
> mistake could lead to hundreds of millions of permission entries in
> Keycloak in a short space of time. The only solace at the moment is that
> the keycloak API isn't being exposed directly so we can probably think of a
> way to ensure the flexibility of Keycloak is available while minimising
> this explosion of permission entries.
>
> I hope this provides a little more insight and I welcome any further
> comments/suggestions on what/where to look to address some of these
> concerns or in fact any reason why the concerns are unwarranted.
>

No doubts, it is a great use case that could stress our capabilities.

Like I said, I do think it really depends on how you desing authorization.
For instance, you mentioned that you may have hundres of millions of
permissions. But you could also have a single permission to
representing/enforcing access to N resources. Take a simple "Only Owner Can
Access" policy as an example.

One of the things that I like most in Keycloak authz is that you are really
designing your authorization requirements, thinking/implementing/testing
the policies you need and re-using these policies to enforce access to
different resources.


>
> Regards,
> Courtney
>


More information about the keycloak-user mailing list