In this blog, I am going to explain how we can implement the centralized authorization strategy for all our endpoints using the keycloak tool. All reference and links have been taken from the official Keycloak documentation, which can be accessed from keycloak website.
Before seeing how to configure the keycloak Customers to be able to implement this authorization strategy, we are going to name and explain first some basic concepts related with this strategy and that are explained in the standard specification of the protocol UMA 2.0 (User-Managed Access). Or also on the official Keycloak page about the service that implements this protocol called Authorization Service. I am going to focus exclusively on the entities that we must configure in Keycloak in order to control access to our endpoints (resources) from the Keycloak admin platform.
- Resource: A resource is part of the assets of an application and the organization. It can be a set of one or more endpoints, a classic web resource like an HTML page, etc. In authorization policy terminology, a resource is the object that is to protects.
- Scope: The scope of a resource is a limited extent of access that is possible to perform on a resource. In the terminology of authorization policy, a scope is one of many verbs that can be logically applied to a resource.
- Policy: A policy defines the conditions that must be met to grant access to an object. Unlike permissions, no specifies the object being protected, but rather the conditions that must be met to access a particular object (for example, resource, scope or both).
- Permission: A permission associates the object being protected with policies that must be evaluated to determine whether the permission is granted access.
- Development savings: The casuistry around authorization with permissions is very broad and complex to implement. Keycloak not only implements, it complying with all the possible casuistry as well it also complies with a standard called UMA 2.0 as it happens with the authentication/authorization OpenId/Outh 2.1. Likewise, all the services implemented in whatever language, will take advantage of this implementation managed and decoupled from any service that requires it.
- Visibility: The ability to delegate the authorization strategy to Keycloak allows access control to our endpoints to be transparent and dynamic, not having to reprogram and deploy our backend services.
- Integration with external systems: likewise, the UMA 2.0 standard offers endpoints that can be consulted by any service to collect all the roles and permissions associated with a user and validate that he can access all the resources that are assigned to him have been assigned.
First of all we are going to define a use case or example through the following table of permissions that we want to implement using the Keycloak’s centralized strategy. But let us first understand the keycloak as per our workflow: –
- Role: The role associated with the user who wants to access a specific system endpoint (resource)
- Resource: The endpoint on which we want to apply an access policy (Policy)
- Scope: Represents under what context the user is going to access this resource
- Permission: Represents if this user with a certain role can access the resource (resources) under a scope (scopes).
Now that we have defined which permissions table we want to implement, we are going to explain the steps to follow when implementing this authorization strategy.
First of all, we must create the Customer that implements this authorization strategy under the realm that represents our Organization. This Customer must meet a condition and that is it must be of the confidential type, since only this type of Customer allows configuring this type of authorization strategy.
Once this type of Customer has been defined, we must activate the option called Authorization Enabled. This active flag will make a new tab under our Customer called Authorization, from where we can configure this authorization strategy for this Customer.
STEP 02: Identify the resources to protect and the scopes for each of them
Once we have created our Customer, with the configurations described above, we can now configure this strategy from this new tab enabled to effect. First of all we must define what resources of our application and under what scopes are going to be used by our identities (users, services). This diagram shows the steps to follow.
In the example that we are going to show, we are going to configure this access strategy for two endpoints, which the standard calls resources. A statement could be this:
“We are going to control access to two endpoints that each represent the entities: Product and Customer and on which we have implemented a CRUD in our backend, to be able to: view, create, edit and delete each one of them”.
With this statement we are going to configure this authorization strategy.
First of all, it tells us that these endpoints implement a CRUD, therefore we can access them in four different ways, which represent the four verbs of all RESTfull service: GET, PUT, POST and DELETE. Therefore we are going to create the scopes, which as we have already explained in the previous section. They represent the way in which we want to access our resources (endpoints). For it we access the Authorization scopes tab located within the activated Authorization tab. The configuration we want implement can be seen in the following table:
When creating a scope, we simply give it the name before described in the table, knowing the context that each of them has. We repeat this process four times, one for each of the verbs that our endpoints implement.
You can see in the image below how we have created the four scopes mentioned above. As we can see the fields that we filled in when creating a role are:
Name: Unique name associated with our scope. We will use this identifier later when we want to check if a user with a specific role may or may not access a resource under a selected scope
Display name: brief description of our scope, to be able to select or list it easily.
Now that we have the scopes of our all the scopes implemented by our two resources, let’s create these resources and associate the scopes implemented by each of them. We can see in the image below the fields that we must fill in some mandatory and other optional but recommended when it comes to listing them. The two most important are:
Name: represents the unique name associated with the resource that we want to protect and will be used later when we do evidence against them
Display Name: brief description of the resource to be able to select or list it easily.
Type: URD or unique ID associated with the resource
URI: url associated with the resource, represents the endpoint implemented in our API
Scopes: represent the scopes that this resource implements and as we have said in the statement, the two resources: product and Customer implement a CRUD, so we’ll add these scopes to the two resources created: Customer-resource and product-resource.
Here we can see the list of all the resources that we have created to be able to manage all the resources of the statement.
Once we have created the resources that we want to protect along with the scopes that each of them implements, we are going to move on to this third phase where we are going to configure the policies and finally the permissions that bring together the previous objects created: scopes, resources and policies.
In this diagram you can see the steps to follow in this third phase described above
First we are going to create the access policies to the resources, which as we have explained previously represent the conditions that are must comply to access the resources. In our case we are going to create role-based policies (RBAC) since these objects are the ones that we are going to use to segregate our users within the application at the authorization level, but keep in mind that there are many others types of policies that we can configure within the Policies tab. A table that could define these role-type policies:
Let’s create realm-type global role with name admin, operator and user.
We can see how we have created a resource access policy for each of the roles that we have defined when creating our realm, in this case, realm-type roles global to all Customers of our realm.
To create a policy of this type we must select the Role type and fill in:
- Name: Unique name of our policy
- Description: Brief description of the policy, to be able to filter it in a list.
Roles: Set of roles to which it should be applied
Here we can see the policies that we have created for the two resources
Now that we have defined all the necessary objects to create the permissions: scopes, resources and permissions, we can start to create permits with the necessary granulometry, fulfilling the conditions of the permit table described above:
We are going to visualize some examples that implement this table of permissions.
For example, access permissions to the Customer resource for editing (PUT). We can see how the parameters to fill in are:
- Name: Unique name of the permission
- Description: Description of the permission to be able to filter it in a list
- Resource: On which resource the permission is applied
- Scope: So that scopes of all those that the Resource accepts, the permission will be applied
- Policy: Which are the policies that will control that the permission is accepted.
- Strategy Decision: which strategy will be applied when executing the policy. We will choose the Affirmative, which indicates that at At least one policy must be met to accept the permission.
Finally we can see all the permissions that we have configured to implement the permissions table described above.
Now we must create a user attached to these roles with this usernames and password test.
The Keycloak Authorization tool has a tab called Evaluate, from where we can test if the configuration that we have created complies with the permissions table described above.
In it we can select many combinations to be able to test many casuistry.
For example, we are going to test how a user with the Operator role can create Products but not Customers. We start by checking the creation of products for a user of type operator
Now lets change the request from Product to Customer
As you saw in above screen that Operator role has the edit permission for Customer, so let’s verify it.
With this we learn how the permissions can be aplied using RBAC, please share your thoughts on this blog and leave a review comment.