This repository contains a project setup for keycloak based projects.
This setup serves as a starting point to support the full lifecycle of development in a keycloak based project. This may include develop and deploy a set of Keycloak extensions, custom themes and configuration into a customized keycloak docker container (or tar-ball).
The project also shows how to write integration tests via Keycloak-Testcontainers. After successful test-run package all extensions and themes as a custom docker image. This image is meant to be the project base image fulfilling the projects requirements in contrast to the general keycloak image.
These requirements work in different contextes, roles and use-cases:
a) Developer for keycloak themes, extensions and image
- build and integration-test with test-containers (uses standard keycloak image)
- run external keycloak with hotdeploy (theme, extension, ...), run integrationtest, e2e testing
a) Developer publishing an image:
- Standard keycloak docker image with extensions, themes und server config.
- Slim custom docker image with extensions, themes und server config (basis alpine) chose jdk version, base-os image version, base keycloak version.
c) Tester/Developer acceptance/e2e-testing with cypress
d) Operator configuring realm and server for different stages
- Extensions: SMS Authenticator, Backup-Codes, Remote Claim Mapper, Audit Event Listener, and Custom REST Endpoint the can expose custom endpoints:
CustomResource
- Support for deploying extensions to a running Keycloak container
- Support for instant reloading of theme and extension code changes
- Support Keycloak configuration customization via CLI scripts
- Examples for Integration Tests with Keycloak-Testcontainers
- Example for End-to-End Tests with Cypress
- Realm configuration as Configuration as Code via keycloak-config-cli
- Multi-realm setup example with OpenID Connect and SAML based Identity Brokering
- LDAP based User Federation backed by Docker-OpenLDAP
- Mail Server integration backed by MailHog
- TLS Support
- Support for exposing metrics via smallrye-metrics
- Examples for running a cluster behind a reverse proxy with examples for HAProxy, Apache, nginx, caddy
- Examples for running a Keycloak cluster with an external infinispan cluster with remote cache store and hotrod cache store.
- Example for Keycloak with Graylog for log analysis, dashboards and alerting.
- Example for metrics collection and dashboards with Prometheus and Grafana.
Tool | Version |
---|---|
Java | 11 |
mvn | 3.6 |
docker | 20.10 |
docker-compose | 1.29 |
The project can be build with the following maven command:
mvn clean verify
The example can be build with integration tests by running the following maven command:
mvn clean verify -Pwith-integration-tests
We provide a platform agnostic single-file source-code Java launcher start.java to start the Keycloak environment.
To speed up development we can mount the keycloak/extensions class-folder and keycloak/themes folder into a Keycloak container that is started via docker-compose (see below). This allows for quick turnarounds while working on themes and extensions.
The default Keycloak admin username is admin
with password admin
.
You can start the Keycloak container via:
java start.java
Keycloak will be available on http://localhost:8080/auth.
The example environment can be configured with https via the --https
flag.
Generate a certificate and Key for the example domain acme.test
with mkcert.
java bin/createTlsCerts.java
This will generate a TLS certificate and key file in .pem
format in config/stage/dev/tls
.
Register map the following host names in your hosts file configuration, e.g. /etc/hosts
on linux / OSX or c:\Windows\System32\Drivers\etc\hosts
on Windows:
127.0.0.1 acme.test id.acme.test apps.acme.test admin.acme.test ops.acme.test
java start.java --https
Keycloak will be available on https://id.acme.test:8443/auth.
Note that after changing extensions code you need to run the java bin/triggerDockerExtensionDeploy.java
script to trigger a redeployment of the custom extension by Keycloak.
The example environment can be configured with OpenLDAP via the --openldap
flag.
java start.java --openldap
The example environment can be configured to use PostgreSQL as a database via the --database=postgres
flag to override the default h2
database.
java start.java --database=postgres
The example environment includes an smallrye-metrics and eclipse-metrics integration for wildfly.
Metrics are exposed via the wildfly management interface on http://localhost:9990/metrics
Realm level metrics are collected by a custom EventListenerProvider
called metrics
.
The example environment can be configured to send Keycloak's logout output to Graylog via the --logging=graylog
option.
Note that you need to download the logstash-gelf
wildfly module
and unzip the libraries into the deployments/local/dev/graylog/modules folder.
cd deployments/local/dev/graylog/modules
wget -O logstash-gelf-1.14.1-logging-module.zip https://search.maven.org/remotecontent?filepath=biz/paluch/logging/logstash-gelf/1.14.1/logstash-gelf-1.14.1-logging-module.zip
unzip -o logstash-gelf-1.14.1-logging-module.zip
rm *.zip
java start.java --logging=graylog
Prometheus can scrape0 metrics from configured targets and persists the collected data in a time series database. The metrics data can be used to create monitoring dashboards with tools like grafana (see Grafana).
Scrape targets configured:
System | Target | Additional Labels |
---|---|---|
keycloak | http://acme-keycloak:9990/metrics | env |
java start.java --metrics=prometheus
Grafana supports dashboards and alerting based on data from various datasources.
Note: To enable grafana with tls, a permission change is required as docker does not support a way to map users for shared files.
You need to add read permissions for the key file acme.test+1-key.pem
in config/stage/dev/tls for the group of the current user.
Access to Grafana can be configured in multiple ways, even a login with Keycloak is possible. In this example we use configured admin user account to access Grafana, but we also offer a login via Keycloak by leveraging the generic OAuth integration. Grafana is configured to not allow login as guest.
java start.java --grafana
Open Grafana
Manual steps when logged in as an Admin (Example User: devops_fallback, Password: test)
- Configure datasource
- Add e.g. prometheus as datasource (http://acme-prometheus:9090/ installed by default) (see Grafana)
- Add e.g. elastic-search as datasource (http://acme-graylog-lo:9090/) (see Graylog services)
- Import Boards of your choice from Grafana (for testing an exported board can be used)
Clustering examples can be found in the deployments/local/cluster folder.
The example environment contains several realms to illustrate the interaction of different realms.
The acme-apps
realm contains a simple demo application and provides integration with the acme-internal
, acme-ldap
and acme-saml
realm via Identity Brokering. The idea behind this setup is to provide a global
acme-apps
realm for applications that are shared between internal and external users.
The acme-internal
realm provides applications that are only intended for internal users.
The acme-ldap
realm provides applications that are only intended for employees.
The acme-internal
and acme-ldap
realms serve as an OpenID Connect based Identity Provider for the acme-apps
realm.
The acme-saml
realm provides applications is similar to the acme-internal
and serves as
a SAML based Identity Provider for the acme-apps
realm.
The acme-internal
realm contains a test users which are stored in the Keycloak database.
Users:
- Username
tester
and passwordtest
(from database) - Username
support
and passwordtest
(from database)
The support user has access to a dedicated realm scoped admin-console and can perform user and group lookups.
An example for a realm scoped admin-console URL is: https://id.acme.test:8443/auth/admin/acme-internal/console
.
The acme-ldap
realm contains a test user and is connected to a federated user store (LDAP directory) provided via openldap.
- Username
FleugelR
and passwordPassword1
(from LDAP federation)
The acme-saml
realm contains a test user and stores the users in the Keycloak database.
Users:
- Username
acmesaml
and passwordtest
(from database)
A simple demo app can be used to show information from the Access-Token, ID-Token and UserInfo endpoint provided by Keycloak.
The demo app is started and will be accessible via http://localhost:4000/?realm=acme-internal or https://apps.acme.test:4443/?realm=acme-internal.
The dockerfile for the docker image build uses the keycloak/Dockerfile.plain by default.
To build a custom Keycloak Docker image that contains the custom extensions and themes, you can run the following command:
mvn clean verify -Pwith-integration-tests io.fabric8:docker-maven-plugin:build
The dockerfile can be customized via -Ddocker.file=keycloak/Dockerfile.alpine-slim
after mvn clean verify
.
It is also possible to configure the image name via -Ddocker.image=acme/acme-keycloak2
.
To build the image with Keycloak.X use:
mvn clean package -DskipTests -Ddocker.file=keycloakx/Dockerfile.plain io.fabric8:docker-maven-plugin:build
The custom docker image created during the build can be stared with the following command:
docker run \
--name acme-keycloak \
-e KEYCLOAK_USER=admin \
-e KEYCLOAK_PASSWORD=admin \
-e KEYCLOAK_CONFIG_FILE=standalone-ha.xml \
-v $PWD/imex:/opt/jboss/imex:z \
-it \
--rm \
-p 8080:8080 \
acme/acme-keycloak:latest
The cypress based End to End tests can be found in the keycloak-e2e folder.
To run the e2e tests, start the Keycloak environment and run the following commands:
cd keycloak-e2e
yarn run cypress:open
# yarn run cypress:test
To manually check if all prequisits are fulfilled.
java bin/envcheck.java
To manually trigger an extension redeployment after extension code changes / build, you can run the following script:
java bin/deployExtensions.java
To import/export of an existing realm as JSON start the docker-compose infrastructure and run the following script.
The export will create a file like acme-apps-realm.json
in the ./keycloak/imex
folder.
java bin/realm.java --realm=acme-apps
The import would search an file acme-apps-realm.json
in the ./keycloak/imex
folder.
java bin/realm.java --realm=acme-apps --action=import
Web Interface: http://localhost:1080/# Web API: http://localhost:1080/api/v2/messages
Web Interface: http://localhost:17080 Username: cn=admin,dc=corp,dc=acme,dc=local Password: admin
Instead of running the deployment trigger script yourself, you can register it as an external tool in IntelliJ as shown below.
- Name:
kc-deploy-extensions
- Description:
Deploy Extensions to Keycloak Docker Container
- Program:
$JDKPath$/bin/java
- Arguments:
$ProjectFileDir$/bin/deployExtensions.java
- Working directory:
$ProjectFileDir$
- Only select:
Synchronize files after execution.
The extensions can now be redeployed by running Tools -> External Tools -> kc-deploy-extensions
Instead of running the Keycloak Config CLI script yourself, you can register it as an external tool in IntelliJ as shown below.
- Name:
kc-deploy-config
- Description:
Deploy Realm Config to Keycloak Docker Container
- Program:
$JDKPath$/bin/java
- Arguments:
$ProjectFileDir$/bin/applyRealmConfig.java
- Working directory:
$ProjectFileDir$
- Only select:
Synchronize files after execution.
The extensions can now be redeployed by running Tools -> External Tools -> kc-deploy-config
We use aquasec/trivy to scan the generated docker image for vulnerabilities.
java bin/scanImage.java --image-name=acme/acme-keycloak:latest