Keycloak configuration setup could use a 'KISS'
Keycloak is not a new kid on the block, it has been around since 2014. The product changed over the years and like most software products/languages also adapted the way changes are released. From 2021 onwards versions are released in shorter cycles, probably to create short feedback loops and smaller migrations. It could be said that Keycloak's release process nowadays is a result of operational project management changes companies have had in these years. Changes like Agile development, DevOps methodology, Continuous Integration & Continuous Delivery (CI/CD) and Scrum, which all promote short feedback loops. If you agree it could be a good example of Conway's law, which states that the communication structures of a company influences the systems they design.
So, in theory it all works together fine using the same release strategies and small migrations. In reality Identity and Access Management (IAM) solutions like Keycloak are very complex systems where customers demand a resilient and trustworthy performance. It is interwoven in the complete landscape of the software that is developed as it provides authentication/authorisation. Depending on the size of the landscape, Conway's law can also be imagined in reverse; stakeholders and their interests with IAM solutions are also interwoven through the whole organisation. Making it even more complex.
With this reality in mind, the article tries to show a Keycloak configuration that is KISS (keep it simple, stupid) in order to bring complexity down. It provides an easy-to-run example to start from, but more importantly, a trigger to think about how your IAM solution is configured. Both during development and within the organisation in new projects or existing ones.
Keycloak makes it look easy
When you start with Keycloak and see their great UI and walk through the first tutorials you feel ready to start. Your use-case of user-management may be simple, though as any use-case, the real work starts when it is in production. Every 2-3 months Keycloak is releasing a new major version, making changes that do not consider your use-case or feelings (just joking). As explained in the introduction, this more frequent release cycle is understandable due to how most projects are managed. Nonetheless, the workload of maintenance is there.
People familiar with Keycloak in enterprise environments almost all have heard of release stories where companies are afraid to release new versions of their company IAM solution. While often not explicitly referred to as 'afraid', a lengthy release process involving navigating numerous hoops can evoke a sense of fear, often leading to cascading issues in the future. A mistake easily made, by both managers and teams, is to react to those issues with new processes. Instead, no new reaction is required when your working process is already build on continuous improvement, more beautiful explained as kaizen.
This is where testability pops around the corner because we want a set of tests we can trust, run fast and automatically. Then,with each unfortunate event of a bug or mistake we stop daily work and improve the tests so this mistake can not happen again. We want to test our custom configuration as well as each new Keycloak release. Therefore, next, we investigate the options Keycloak provides to manage IAM configurations.
Keycloak's options to manage configuration
[HINT] For people less familiar with the Keycloak and its configuration would be best adviced to follow a quick guide on the platform of your choosing to get an idea of the functionality it offers for configuring authentication and authorisation. After the guide you have a working Keycloak instance and then can easily click around the UI it automatically offers. The UI is a great tool to quickly learn the functionality Keycloak offers.
Keycloak offers four different options to manage the IAM solution :
Keycloak UI: 'Clicking it together' is an option. Here you develop skill in making configuration via the UI. But what if you scale and have 20+ realms to manage in multiple deploy environments, how would you test this? Documentation like 'how to configure a realm' instantly becomes more important than it should be. All of it constantly subject to the accuracy of the developer (caffeine in his/her system). Lastly, the configuration could be visually rearranged with each new release. Searching for that one token example you always look at is not fun.
Import/export JSON files: The benefits of using the UI to set up configuration and being able to export/import the configuration as a JSON feels much better from the start. However, at scale, JSON configuration changes are just as error-prone as the UI. Testability is better with JSON, so automated tests could help, but not with new releases. These can turn into a nightmare because one change in the JSON format could easily mean looking at a large diff of a file. When a mistake is made, the test is often 'fixed' according to the mistake.
Keycloak CLI: Often a good choice to automate configuration. Not surprisingly, we also want to test this. Testing automation code for complex configurations is just hard and requires skill. 'KISS' does not have a large fan base here.
Although the three options work in your small or starting projects, the costs of maintenance starts to weigh in when it scales or complexity grows. This leaves us with the fourth option, the Keycloak Admin REST API, which we dive into next.
(A)mazingly (P)ragmatic (I)interface
Most of the time, API life cycle management (LCM) is handled with care and is often less subject to breaking changes. When changes happen, they can be handled by developers like it is part of their everyday job (which it probably is already). The fact that there is already a better toolbox at hand to do high standard LCM makes this approach automatically more pragmatic to choose.
To make Keycloak Admin REST API (server side) even more interesting, with each new version of Keycloak there is also client side implementation provided: a
keycloak-admin-client dependency for Java and a package for Nodejs. For developers this means less specific knowledge about the API itself and tests break when they should break if something changes during LCM work like updating dependencies. Having a client-side library makes configuring and testing Keycloak much more intuitive. With readable code version control also improves greatly e.g. not looking a bracket JSON structures but looking how a realm is created. By having the configuration in separate code, Keycloak remains a stateless image. The Keycloak base image can be bundled with the configuration as a custom image and has its own release cycle. This could also be done automatically in the pipeline after the test ran successfully and the image is instantly released in the DTAP stream. This makes it ideal for CI/CD environments and the DevOps methodology.
This whole combination of configuration as code being testable and easily deployed makes it increasingly maintainable. Furthermore, it keeps it as KISS as possible and this is the love a develop environment needs in order to deliver the quality IAM solutions need. For now, let us focus on fewer words and a bit more code, as this often gives statements like the above much more clarity.
Keycloak Admin Client makes it easy
In order to show you how intuitively it is to develop IAM configuration, using the API, a small Java example is added with elaboration on what it does. For comparison reasons, it is also the same Keycloak UI end result that is done in one of the Keycloak guides
1 2 3 4 5 6 7 8
Keycloak keycloak = KeycloakBuilder.builder() .serverUrl("http://keycloak:8080") .realm("master") .clientId("admin-cli") .grantType("password") .username("admin") .password("admin") .build();
In this snippet we create a
Keycloak instance with a
KeycloakBuilder, all provided from the
keycloak-admin-client dependency. Here we create the bare minimum to set up Keycloak admin configuration and a master realm.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
//Create Realm RealmRepresentation realmRepresentation = new RealmRepresentation(); realmRepresentation.setRealm("myRealm"); realmRepresentation.setDisplayName("Example Realm"); realmRepresentation.setEnabled(true); keycloak.realms().create(realmRepresentation); RealmResource myRealm = keycloak.realm("myRealm"); //Create Client ClientRepresentation clientRepresentation = new ClientRepresentation(); clientRepresentation.setClientId("myclient"); clientRepresentation.setName("Example Client"); clientRepresentation.setEnabled(true); clientRepresentation.setRedirectUris(List.of("https://www.keycloak.org/app/*")); clientRepresentation.setWebOrigins(List.of("https://www.keycloak.org")); myRealm.clients().create(clientRepresentation); //Create Password CredentialRepresentation credentialRepresentation = new CredentialRepresentation(); credentialRepresentation.setType(CredentialRepresentation.PASSWORD); credentialRepresentation.setValue("test"); //Create User and add password UserRepresentation userRepresentation = new UserRepresentation(); userRepresentation.setUsername("myuser"); userRepresentation.setEmail("email@example.com"); userRepresentation.setEnabled(true); userRepresentation.setCredentials(List.of(credentialRepresentation)); myRealm.users().create(userRepresentation);
According to the guide, we created a realm
myrealm, a user
myuser with password credentials
test and added it all to the realm. When this code is put in a Java application we can then execute it against a running Keycloak instance running on the port we configured above. Resulting in the same IAM configuration as in the guide mentioned above. We can then test it with the SPA testing application which Keycloak provides.
For a working Keycloak 23.0.1 simple docker compose setup please go to my github
What happens next
As with any 'best' solution, opinions differ. With that in mind, the best outcome for this blog would be that Keycloak Admin REST API solutions, such as this, are tried. Through shared experiences the API could become more commonly used, making quality of the solutions evolve over time.
In the GitHub example a direct enhancement could be made as the configuration application isn't packaged with the Keycloak image. Furthermore, you could also start thinking about environment configuration. E.g. do I store certain configuration in
YAML for Kubernetes/Docker to pick up? Plenty of improvements or decisions to think of. This is good because we are continuous improving our solution to deliver that quality we and our stakeholders want.
[TIP] Hopefully the blog underlines the importance of testability enough. It is certainly a cornerstone of a smooth running IAM solution with Keycloak. It not only minimizes human error, if test scenarios are understandable for non-developers, it can also be part of your proven documented quality when bugs or system failures do turn up (and people with pitchforks start walking through the hallways). Effort here is not wasted.
So think about it and maybe when your Keycloak configuration setup is so KISS, you start preaching that Keycloak was made for lovin' you. Certainly organisations love you when a Keycloak solution runs without much error.
The inspiration of writing this blog came from a great Devoxx presentation. There is a live demo and goes into more depth with ideas of how to support dynamic configuration changes to keycloak.