Run Quarkus Keycloak with docker-compose

Attention: snippets in this post are intended to be used for development ONLY.

Keycloak, the powerful, open source Identity solution released its latest version (19) recently. Wildfly was previously the de-facto application server for keycloak, but this has changed. Wildfly has been dropped in favour of quarkus; and this has brought about some configuration changes, as quarkus is more than just an application server.

All files needed for this demonstration can be found here

How to run keycloak

There are two ways you can run keycloak:

  1. Head over to the downloads section of the keycloak homepage, download the appropriate binary file. Extract and launch the kc.sh script. By default, keycloak uses an in-memory Database (H2)
launch kc.sh startup script

2. Docker. With this option, you can either run the image directly or build your own image. In this post, we are interested in running keycloak with docker-compose.

a. The docker-compose.yml file: 2 services are declared in this file. postgres and keycloak. The postgres service simply pulls a postgres image from the remote docker repository and launches a container with the service exposed on the system port 5432. The content of ./initdb directory (which is a bash script) would eventually be copied into the container in the specified path /docker-entrypoint-initdb.d. As long as the database is empty, this script would get executed; ensuring it is run only once. We take advantage of this and drop our database creation scripts here. (for brevity, I won't be discussing all about docker, and docker-compose in this post)

version: '3.9'

services:

  postgres:
    image: postgres:13.2
    restart: unless-stopped
    container_name: cards_postgres
    volumes:
#      - ./db-data:/var/lib/postgresql/data/
      - ./initdb:/docker-entrypoint-initdb.d
      - ./postgres/conf:/var/lib/lib/postgresql/data
    env_file:
      - ./database.dev.env
    ports:
      - "5432:5432"
    networks:
      - backend

  keycloak:
    container_name: local_keycloak
    image: quay.io/keycloak/keycloak:latest
#    env_file:
#      - ./keycloak.dev.env
    environment:
      KC_FEATURES:
        authorization
        token-exchange
        docker
        impersonation
        scripts
        upload-scripts
        web-authn
        client-policies
        dynamic-scopes
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: password
    entrypoint: /opt/keycloak/bin/kc.sh --config-file=/opt/keycloak/conf/keycloak.conf start-dev
    volumes:
      - ./keycloak-data:/opt/keycloak/conf
    ports:
      - "8080:8080"
      - "8443:8443"
#    restart: on-failure
    networks:
      - backend
    depends_on:
      postgres:
        condition: service_started
networks:
  backend:
    name: backend
    driver: bridge
docker-compose.yml
#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
	CREATE USER keycloak with PASSWORD 'kc';
	CREATE DATABASE keycloak;
	GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;

	CREATE DATABASE db;
EOSQL
init-user-db.sh

The database environment variables are also read in from a .env file

POSTGRES_USER="postgres"
POSTGRES_PASSWORD="postgres"
PGADMIN_DEFAULT_EMAIL="user@domain.local"
PGADMIN_DEFAULT_PASSWORD="admin"
database.dev.env

Keycloak Guides section details the available configurations and how they are to be used. The all configuration section also details the features. We have chosen to enable only a subset in our docker-compose.

Notice that the other keycloak configuation properties are read in using an environment file, except KEYCLOAK_ADMIN and KEYCLOAK_ADMIN_PASSWORD. I have only been able to get these 2 configuration properties in by explicit environments inside the docker-compose, and not from a .env or .conf file.

Also, while the documentation mentions that configuration can be read via command line, environment variables, or configuration file, the configurations were only read successfully from a .conf file and environment in the docker-compose, but not from .env file.

Keycloak loads the configuration from four different configuration sources:command-line parameters, environment variables, user-created .conf file, keycloak.conf file located in the conf directory.

db=postgres
db-username=keycloak
db-password=kc
db-url=jdbc:postgresql://cards_postgres:5432/keycloak
db-schema=public
db-url-database=keycloak
db-url-host=cards_postgres
db-url-port=5432
# hostname=localhost:8080
hostname-strict=false
https-client-auth=request
https-certificate-file=/opt/keycloak/conf/server.crt.pem
https-certificate-key-file=/opt/keycloak/conf/server.key.pem
https-port=8443
https-protocols=TLSv1.3,TLSv1.2
http-enabled="true"
http-port=8080
metrics-enabled=true
proxy=edge
proxy-address-forwarding=true
postgres-user=postgres
postgres-password=postgres
pgdata=/var/lib/postgresql/data/pgdata
keycloak.conf

If you're interested in the self-signed certificate for the keycloak authorisation server, I have included the script below.

#script generates a keystore and uses this to generate a self-signed certificate to use in keycloak
keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" -keystore server.keystore

keytool -export -alias server -keystore server.keystore -file public.der

openssl x509 -inform der -in public.cert -out certificate.pem

keytool -importkeystore -srckeystore server.keystore -destkeystore keystore.p12 -deststoretype PKCS12

openssl pkcs12 -in keystore.p12  -nodes -nocerts -out server.key

And with that, we're in:

keycloak landing page
keycloak server info page

Cheers !!!