The popular open-source IAM solution Keycloak (see project page ) is undergoing a major technology change. As part of the Keycloak.X efforts , the underlying platform is to be changed from Wildfly/Undertow to Quarkus/Vertx. This platform change has been ongoing for quite a while now and the project recently announced that it is about to release a production grade version of Keycloak.X soon. Once it’s ready, we can use the new Keycloak.X distribution in production.
This announcement was pretty exciting for us as we use Keycloak on a daily basis to implement IAM solutions for our customers. Many customer projects have shown that a classic Wildfly-based Keycloak system poses major challenges for development teams: the configuration is very complex, the resource footprint is relatively high and the server is not optimized for operation in modern cloud environments.
Customers who are eagerly following the latest Keycloak developments regularly ask us what Keycloak.X is, what benefits it provides and when it will be ready for prime time. This is a good opportunity to take a look at Keycloak.X. To explain this, we provide an overview of Keycloak.X, show some of its features, and demonstrate a simple project setup.
The version of Keycloak used throughout this article is 15.1.1.
Keycloak.X
The Keycloak Server is effectively a large JAX-RS web application deployed in an application server platform that is either Wildfly (Keycloak Community) or JBoss EAP (Red Hat SSO). The web application is served via the embedded Undertow HTTP server. Keycloak.X changes the Wildfly/Undertow platform to Quarkus and Vertx while keeping the JAX-RS application infrastructure. This allows it to keep using the same APIs while leveraging many of the platform features provided by Quarkus, such as flexible configuration, build time optimizations, lower resource consumption as well as faster startup times and a container-optimized runtime.
Keycloak.X umbrella project
Keycloak.X theme is not only about changing the platform of the Keycloak server, but it also incorporates other efforts that have different timelines. One notable example is the new storage model , which will enable Keycloak to support true zero-downtime upgrades, which is currently only possible in rare cases with the current Keycloak storage model.
The new map-based storage model has been in development for quite some time already, but is not yet ready for prime time at the moment. Other topics, like splitting up the monolithic server into smaller, more narrowly focused services, are also part of the long-term Keycloak.X effort.
Faster startup time
One of the noteworthy differences between the classic Wildfly-based Keycloak and Keycloak.X is the startup time. Due to many optimizations that went into the Quarkus platform, the Keycloak Server can now start within a few seconds in contrast to potentially minutes as we’ve observed in some customer projects.
Startup times of a plain Keycloak docker container vs. starting a Keycloak.X .
Lower resource consumption
At the present stage, Keycloak.X already consumes significantly less resources for the same work as Keycloak. For one, the lightweight Quarkus / Vertx runtime has much less overhead for request processing than the Wildfly / Undertow runtime and does not need to carry the application server baggage in the JVM process.
Memory usage of plain Keycloak vs. Keycloak.X Docker Container .
Simpler configuration
The classic Keycloak server supports configuration from multiple sources like system properties, environment variables, properties files and Wildfly-specific configuration files like standalone.xml
and standalone-ha.xml
. However, each mechanism works differently and cannot be easily combined. Additionally there is no concept to denote different configuration stages. In contrast to that, Keycloak.X uses the Quarkus configuration support which provides a homogenous way to configure values in simple properties files that can be overridden with corresponding system properties or environment variables. Additionally, support for profiles or environment / staging-based configuration is provided from the get-go as well.
Modern libraries and faster upgrade cycles
Keycloak.X leverages the best-of-breed library composition that is provided by the underlying Quarkus platform. This means that we can use much more modern libraries out of the box compared to what used to be available in the Wildfly base installation. This also allows for faster library upgrades for CVE fixes. There were also some major library upgrades, which might require you to update your extensions. For example, the JAX-RS implementation Resteasy 3.x was replaced with its binary incompatible successor Resteasy 4.x.
Will my existing extensions and themes still work?
Short answer: very likely yes.
As the underlying Keycloak API stays the same, you can expect your custom extensions to work just fine. If you integrate with the Wildfly infrastructure or explicitly use Resteasy 3 components, then you might need to adapt your code accordingly or recompile your extension against the new Resteasy version.
Your custom themes will also continue to work.
Getting started with Keycloak.X
This chapter focuses on the usual first steps with Keycloak.X. In contrast to the existing description in Keycloak.X Blogpost from keycloak.org, we use the Keycloak.X Docker image in our examples.
Image version and working directory
Start with defining the Keycloak image and a working directory. In the following, keycloak-x in the current user’s home directory is used. As before, the default Keycloak.X Docker image requires a user with an id=1000 to work properly with Docker volume mounts.
1KC_HOME=~/keycloak-x 2 KC_IMAGE=quay.io/keycloak/keycloak-x:15.1.1 3 4 # Create base directory and data folder 5 mkdir -p $KC_HOME/data 6 7 cd $KC_HOME
Using Keycloak.X in dev mode
The easiest way to start a Keycloak.X instance is by running a Docker container with the following command:
1# Start in Dev Mode 2 docker run \ 3 -it \ 4 --rm \ 5 --name kcx \ 6 -e KEYCLOAK_ADMIN=admin \ 7 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 8 -p 8080:8080 \ 9 -v $PWD/data:/opt/keycloak/data:z \ 10 $KC_IMAGE \ 11 start-dev
This starts Keycloak.X in development mode with HTTP enabled and theme caches disabled by default.
Keycloak will be ready after a few seconds on http://localhost:8080. Use admin / admin to log into the Admin Console.
As shown above, the Keycloak admin user credentials can be specified via the environment variables KEYCLOAK_ADMIN
and KEYCLOAK_ADMIN_PASSWORD
.
A noticeable difference is the missing jboss
-subfolder when mounting the data
-folder.
Another noticeable difference one notices when trying to access the Keycloak admin-console is the missing /auth
context-path prefix. The admin console is available at http://localhost:8080/admin instead of http://localhost:8080/auth/admin.
Note that the start-dev
parameter is intended for non-productive usage to speed up development time. Without start-dev
, kc.sh
just prints a usage-hint. By adding --help
to start Keycloak, some possible parameters are printed. Note that you can show even more command-line options if you use the --help-all
flag instead.
The first recommendation from this usage-hint is to employ the start command for using Keycloak.X in production. If start is used without additional parameters, the startup fails with remarks about missing configuration, but that will be covered later on.
How to configure Keycloak.X
The server configuration is now centralized in a single configuration file named keycloak.properties
instead of a keycloak-server.json
or standalone.xml
/standalone-ha.xml
file. In the running Docker container, the file is located at: /opt/keycloak/conf/keycloak.properties
and for the current version of the container (15.1.1) the contents look like this:
1# Default and non-production grade database vendor 2 db=h2-file 3 db.username = sa 4 db.password = keycloak 5 6 # Insecure requests are disabled by default 7 http.enabled=false 8 9 # Metrics and healthcheck are disabled by default 10 metrics.enabled=false 11 12 # Basic settings for running in production. Change accordingly before deploying the server. 13 # Database 14 #%prod.db=postgres 15 #%prod.db.username=keycloak 16 #%prod.db.password=password 17 #%prod.db.url=jdbc:postgresql://localhost/keycloak 18 # Observability 19 #%prod.metrics.enabled=true 20 # HTTP 21 #%prod.spi.hostname.frontend-url=https://localhost:8443 22 #%prod.https.certificate.file=${kc.home.dir}conf/server.crt.pem 23 #%prod.https.certificate.key-file=${kc.home.dir}conf/server.key.pem 24 #%prod.proxy=reencrypt 25 #%prod.hostname=myhostname 26 27 # Default, and insecure, and non-production grade configuration for the development profile 28 %dev.http.enabled=true 29 %dev.hostname.strict=false 30 %dev.hostname.strict-https=false 31 %dev.cache=local 32 %dev.spi.theme.cache-themes=false 33 %dev.spi.theme.cache-templates=false 34 %dev.spi.theme.static-max-age=-1 35 36 # The default configuration when running in import or export mode 37 %import_export.http.enabled=true 38 %import_export.hostname.strict=false 39 %import_export.hostname.strict-https=false 40 %import_export.cluster=local 41 42 # Logging configuration. INFO is the default level for most of the categories 43 #quarkus.log.level = DEBUG 44 quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN 45 quarkus.log.category."org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup".level=WARN
The properties style configuration file contains one setting per line. Configuration keys can contain prefixes which allow grouping settings with a common name. Quarkus also provides an easy way to express profile-specific configurations. In the example above, the %dev.
prefix describes settings that are only applied in the dev
profile. Settings without a prefix are considered prod
profile settings, if not explicitly marked with another profile prefix.
The current configuration can be printed to the console by running Keycloak with the show-config
all command.
1docker run \ 2 -it \ 3 --rm \ 4 $KC_IMAGE \ 5 show-config all
Example output for show-config
all looks like this:
1Current Profile: none 2 Runtime Configuration: 3 kc.config.args = show-config;;all (KcSysPropConfigSource) 4 kc.db = h2-file (PropertiesConfigSource[source=keycloak.properties]) 5 kc.db.password = ******* (PropertiesConfigSource[source=keycloak.properties]) 6 kc.db.username = sa (PropertiesConfigSource[source=keycloak.properties]) 7 kc.home.dir = /opt/keycloak/bin/../ (KcSysPropConfigSource) 8 kc.http.enabled = false (PropertiesConfigSource[source=keycloak.properties]) 9 kc.metrics.enabled = false (PropertiesConfigSource[source=keycloak.properties]) 10 kc.show.config = all (KcSysPropConfigSource) 11 kc.version = 15.1.1 (KcSysPropConfigSource) 12 Profile "dev" Configuration: 13 %dev.kc.cache = local (PropertiesConfigSource[source=keycloak.properties]) 14 %dev.kc.hostname.strict = false (PropertiesConfigSource[source=keycloak.properties]) 15 %dev.kc.hostname.strict-https = false (PropertiesConfigSource[source=keycloak.properties]) 16 %dev.kc.http.enabled = true (PropertiesConfigSource[source=keycloak.properties]) 17 %dev.kc.spi.theme.cache-templates = false (PropertiesConfigSource[source=keycloak.properties]) 18 %dev.kc.spi.theme.cache-themes = false (PropertiesConfigSource[source=keycloak.properties]) 19 %dev.kc.spi.theme.static-max-age = -1 (PropertiesConfigSource[source=keycloak.properties]) 20 Profile "import_export" Configuration: 21 %import_export.kc.cluster = local (PropertiesConfigSource[source=keycloak.properties]) 22 %import_export.kc.hostname.strict = false (PropertiesConfigSource[source=keycloak.properties]) 23 %import_export.kc.hostname.strict-https = false (PropertiesConfigSource[source=keycloak.properties]) 24 %import_export.kc.http.enabled = true (PropertiesConfigSource[source=keycloak.properties]) 25 Quarkus Configuration: 26 quarkus.log.category."org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup".level = WARN (PropertiesConfigSource[source=keycloak.properties]) 27 quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level = WARN (PropertiesConfigSource[source=keycloak.properties])
Keycloak.X supports the creation of a new and optimized server image based on the configuration options provided by dynamically generating bytecode. Once created, the configuration will be persisted and read during startup without having to process them over again, which improves startup time.
Therefore some configuration options require the build command to be executed in order to actually change a configuration. This applies for options like
- Change database vendor
- Enable/disable features
- Enable/Disable providers or set a default
The Keycloak team recommends running the build command before running the server in production for an optimal runtime experience.
kc.sh
build [OPTIONS], e.g.:
Dockerfile:
1FROM quay.io/keycloak/keycloak-x:15.1.1 2 RUN /opt/keycloak/bin/kc.sh build --metrics-enabled=true
Build the Docker image:
1docker build -t mykeycloakx . 2 3 docker run \ 4 -it \ 5 --rm \ 6 --name kcx \ 7 -e KEYCLOAK_ADMIN=admin \ 8 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 9 -p 8080:8080 \ 10 -v $PWD/data:/opt/jboss/keycloak/data:z \ 11 mykeycloakx \ 12 start --http-enabled=true
Run the custom Docker image:
1docker run \ 2 -it \ 3 --rm \ 4 --name kcx \ 5 -e KEYCLOAK_ADMIN=admin \ 6 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 7 -p 8080:8080 \ 8 -v $PWD/data:/opt/keycloak/data:z \ 9 mykeycloakx \ 10 start --http-enabled=true --http-port=8080 --http-host=0.0.0.0 --hostname=localhost:8080 --hostname-strict-https=false
Note that, due to a bug in Keycloak 15.1.1, we need to specify the hostname together with port for the --hostname
parameter. In later versions of Keycloak you just need to configure the plain hostname.
How to adjust the context-path
As mentioned above, Keycloak.X uses an empty context-path
AKA relative-path
setting. If you want to use the old context path /auth
, which is used in Wildfly-based Keycloak distributions, you need to provide the build option –-http-relative-path=auth
.
Alternatively you can also use the environment variable KC_HTTP_RELATIVE_PATH or the Keycloak configuration setting kc.http.relative-path.
Adjusting the context-path to the old value might make it easier to migrate to Keycloak.X in existing Keycloak environments.
The above show-config
all command reveals this as one of many settings.
Besides the configuration via file, settings can be provided via command-line parameter or environment variables. The Keycloak.X documentation regarding configuration options can be found here .
1# Start in Dev Mode with custom context-path 2 docker run \ 3 -it \ 4 --rm \ 5 --name kcx \ 6 -e KEYCLOAK_ADMIN=admin \ 7 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 8 -p 8080:8080 \ 9 -v $PWD/data:/opt/keycloak/data:z \ 10 $KC_IMAGE \ 11 start-dev --http-relative-path=auth
Now Keycloak should be accessible on http://localhost:8080/auth.
How to enable TLS
As described in the previous section, the dev
-profile works out of the box using HTTP and a local h2 database setting preset. To move on to a more production-like setup, it is strongly recommended to use HTTPS. To configure this, the following steps are required.
Hostname
For a local setup, put the hostname for accessing Keycloak in the hosts file of your system. On Linux or OSX the hosts file can be found in /etc/hosts
and C:\Windows\System32\Drivers\etc\hosts
on Windows.
For this example we want to use the domain name id.keycloak.test, hence we configure the following hosts entry:
1127.0.0.1 id.keycloak.test
Self-signed certificate
In order to use HTTPS, we need to create a certificate and private key. For testing purposes we use a self-signed certificate. Create and install self-signed certificates for that hostname, e.g. with a tool like mkcert by running the following command:
mkcert -install id.keycloak.test 127.0.0.1
This will generate two files: The certificate is at "./id.keycloak.test+1.pem"
and the key at "./id.keycloak.test+1-key.pem"
.
Running with prod profile
The following command shows how to run with HTTPS enabled using the created certificates.
1docker run \ 2 -it \ 3 --rm \ 4 --name kcx \ 5 -e KEYCLOAK_ADMIN=admin \ 6 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 7 -e KC_DB_USERNAME=sa \ 8 -e KC_DB_PASSWORD=keycloak \ 9 -p 8080:8080 \ 10 -p 8443:8443 \ 11 -v $PWD/data:/opt/keycloak/data:z \ 12 -v $PWD/id.keycloak.test+1.pem:/etc/x509/https/tls.crt:z \ 13 -v $PWD/id.keycloak.test+1-key.pem:/etc/x509/https/tls.key:z \ 14 $KC_IMAGE \ 15 start \ 16 --auto-build \ 17 --hostname=id.keycloak.test:8443 \ 18 --https-certificate-file=/etc/x509/https/tls.crt \ 19 --https-certificate-key-file=/etc/x509/https/tls.key
Note that the Keycloak.X version 15.1.0 introduced the --auto-build
feature, which dynamically detects new extensions in the /provider
and dynamically generates build-time configuration. This comes at the expense of additional startup time. If you want a fast startup, then you can run the command
bin/kc.sh build
to index the provided extensions as shown in the Dockerfile example above. After running the build command, you can start the server via kc.sh start
without the --auto-build
flag.
Default database settings and verbosity are also added in comparison to the previous start command to get rid of the dev
-profile.
The output should show something like:
1<TIMESTAMP> INFO [io.quarkus] (main) Keycloak 15.1.1 on JVM (powered by Quarkus 2.5.1.Final) started in 7.014s. Listening on: https://0.0.0.0:8443 2 <TIMESTAMP> INFO [io.quarkus] (main) Profile prod activated.
Keycloak should be available at: https://id.keycloak.test:8443/ without complaints about untrusted certificates. Note that as mentioned above, the hostname parameter currently needs to contain the hostname+port, however in later Keycloak versions this will change.
How to add custom themes
Keycloak.X still supports folder and JAR-based custom themes. Folder-based custom themes must be placed in the /opt/keycloak/themes
directory. Custom themes provided as .jar
-files need to be copied to the /opt/keycloak/providers
folder.
Note that nothing has changed in regards to the theme engine itself.
For theme development the dev
-profile conveniently disables caching as most Keycloak theme developers might already have seen in the configuration section:
1%dev.spi.theme.cache-themes=false 2 %dev.spi.theme.cache-templates=false 3 %dev.spi.theme.static-max-age=-1
How to add custom extensions
Custom extensions must be placed in /opt/keycloak/providers
as .jar
-files.
Regarding extensions and its SPIs, no change is expected comparing Keycloak and Keycloak.X. Needless to say, the seamless migration of extensions depends on the written code in areas beside Keycloak’s SPIs too. When we migrated our project example and extensions playground, we found issues related to Resteasy version 3.x vs 4.x, but nothing serious. After a small refactoring everything works for both worlds. We would like to hear the story about your migration!
How to remote-debug Keycloak.X
To enable remote debugging for the Keycloak.X container, you need to configure the DEBUG_PORT
environment variable. To restrict the remote debugging to a specific network interface, one can use DEBUG_PORT='127.0.0.1:8787'
.
An example execution with enabled debugging that allows for connecting a remote debugger via multiple endpoints looks like this:
1docker run \ 2 -it \ 3 --rm \ 4 --name kcx \ 5 -e KEYCLOAK_ADMIN=admin \ 6 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 7 -e KC_DB_USERNAME=sa \ 8 -e KC_DB_PASSWORD=keycloak \ 9 -e DEBUG_PORT='*:8787' \ 10 -p 8443:8443 \ 11 -p 8787:8787 \ 12 -v $PWD/data:/opt/keycloak/data:z \ 13 -v $PWD/id.keycloak.test+1.pem:/etc/x509/https/tls.crt:z \ 14 -v $PWD/id.keycloak.test+1-key.pem:/etc/x509/https/tls.key:z \ 15 $KC_IMAGE \ 16 start \ 17 --auto-build \ 18 --hostname=id.keycloak.test:8443 \ 19 --https-certificate-file=/etc/x509/https/tls.crt \ 20 --https-certificate-key-file=/etc/x509/https/tls.key \ 21 --debug
Once the container has started, one can attach the debugger to the JVM process via localhost:8787 with the IDE of your choice. Note that the classpath for the debugger must contain the relevant JARs to be able to set breakpoints.
How to add JVM Options
Keycloak.X accepts JVM settings via JAVA_OPTS
and JAVA_TOOLING_OPTS
.
If nothing is given the default JAVA_OPTS
contain:
1JAVA_OPTS="-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true"
If JAVA_OPTS
is given as a parameter, the default is overwritten. This hint is also printed to the log during startup. Note that you can use the JAVA_TOOLING_OPTS
to configure additional JVM settings like JMX configuration etc. Note that since Keycloak 16.0.0 the environment variable JAVA_OPTS_APPEND
can be used to append custom JVM options without overriding default settings.
For production, a lot of things might be worth considering which is beyond the scope of this article.
How to use the JMX with Keycloak.X
Since Keycloak.X is a normal Java application, we can also use classic tools like VisualVM or Java Mission Control to manage the application. To do so, we need to add the following JAVA_TOOLING_OPTS
together with exposed port 8790 to our container invocation.
1docker run \ 2 -it \ 3 --rm \ 4 --name kcx \ 5 -e KEYCLOAK_ADMIN=admin \ 6 -e KEYCLOAK_ADMIN_PASSWORD=admin \ 7 -e KC_DB_USERNAME=sa \ 8 -e KC_DB_PASSWORD=keycloak \ 9 -e JAVA_TOOL_OPTIONS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8790 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dquarkus-log-max-startup-records=10000" \ 10 -p 8443:8443 \ 11 -p 8790:8790 \ 12 -v $PWD/data:/opt/keycloak/data:z \ 13 -v $PWD/id.keycloak.test+1.pem:/etc/x509/https/tls.crt:z \ 14 -v $PWD/id.keycloak.test+1-key.pem:/etc/x509/https/tls.key:z \ 15 $KC_IMAGE \ 16 start \ 17 --auto-build \ 18 --hostname=id.keycloak.test:8443 \ 19 --https-certificate-file=/etc/x509/https/tls.crt \ 20 --https-certificate-key-file=/etc/x509/https/tls.key
Once the container is started, one can start e.g. VisualVM or Java Mission Control and connect via JMX to localhost:8790 and explore the runtime of Keycloak.X as usual.
Summary
This blog post highlighted a few new features of the Quarkus-based Keycloak.X server distribution and gave examples of configuring Keycloak.X for various purposes.
In a recent post in the Keycloak team blog, a concrete Roadmap for Keycloak.X was announced that we and our customers read with great interest. The roadmap is challenging, but in our eyes a big step forward to mitigate or review problematic areas of the current Keycloak server. In our opinion, Keycloak.X still has some rough edges, but can already be used for testing in dev environments. As we have shown in the keycloak-project-template , migrating a modest-size custom Keycloak project can be done with little effort. We are looking forward to the upcoming stable releases of Keycloak.X and will continue investigating. Our next blog post will probably focus on a production-grade Keycloak.X setup with clustering.
More articles
fromSebastian Rose & Thomas Darimont
Your job at codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog authors
Sebastian Rose
IT Consultant
Do you still have questions? Just send me a message.
Thomas Darimont
Principal IAM Consultant
Do you still have questions? Just send me a message.
Do you still have questions? Just send me a message.