Skip to content

Instantly share code, notes, and snippets.

@xgp
Last active June 23, 2024 06:52
Show Gist options
  • Save xgp/768eea11f92806b9c83f95902f7f8f80 to your computer and use it in GitHub Desktop.
Save xgp/768eea11f92806b9c83f95902f7f8f80 to your computer and use it in GitHub Desktop.
Keycloak 17 example using JGroups JDBC_PING discovery protocol for Infinispan
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:11.0 http://www.infinispan.org/schemas/infinispan-config-11.0.xsd"
xmlns="urn:infinispan:config:11.0">
<!-- custom stack goes into the jgroups element -->
<jgroups>
<stack name="jdbc-ping-tcp" extends="tcp">
<JDBC_PING connection_driver="org.postgresql.Driver"
connection_username="${env.KC_DB_USERNAME}" connection_password="${env.KC_DB_PASSWORD}"
connection_url="jdbc:postgresql://${env.KC_DB_URL_HOST}/${env.KC_DB_URL_DATABASE}"
initialize_sql="CREATE TABLE IF NOT EXISTS JGROUPSPING (own_addr varchar(200) NOT NULL, cluster_name varchar(200) NOT NULL, ping_data BYTEA, constraint PK_JGROUPSPING PRIMARY KEY (own_addr, cluster_name));"
info_writer_sleep_time="500"
remove_all_data_on_view_change="true"
stack.combine="REPLACE"
stack.position="MPING" />
</stack>
</jgroups>
<cache-container name="keycloak">
<!-- custom stack must be referenced by name in the stack attribute of the transport element -->
<transport lock-timeout="60000" stack="jdbc-ping-tcp"/>
<local-cache name="realms">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<local-cache name="users">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<distributed-cache name="sessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="authenticationSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="clientSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="loginFailures" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<local-cache name="authorization">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<replicated-cache name="work">
<expiration lifespan="-1"/>
</replicated-cache>
<local-cache name="keys">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="3600000"/>
<memory max-count="1000"/>
</local-cache>
<distributed-cache name="actionTokens" owners="2">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="-1" lifespan="-1" interval="300000"/>
<memory max-count="-1"/>
</distributed-cache>
</cache-container>
</infinispan>
version: '3'
volumes:
postgres_data:
driver: local
services:
postgres:
image: postgres:11
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
ports:
- 5433:5432
keycloak:
build:
context: "./keycloakx"
dockerfile: "./Dockerfile"
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB_URL_HOST: postgres
KC_DB_URL_DATABASE: keycloak
KC_DB_SCHEMA: public
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: password
KC_HOSTNAME_STRICT: false
KC_HTTP_ENABLED: true
KC_LOG_LEVEL: INFO,org.infinispan:DEBUG,org.jgroups:DEBUG
ports:
- 8080:8080
- 8443:8443
depends_on:
- postgres
FROM quay.io/keycloak/keycloak:17.0.0 as builder
ENV KC_METRICS_ENABLED=true
ENV KC_FEATURES=preview
ENV KC_DB=postgres
ENV KC_HTTP_RELATIVE_PATH=/auth
# specify the custom cache config file here
ENV KC_CACHE_CONFIG_FILE=cache-ispn-jdbc-ping.xml
# copy the custom cache config file into the keycloak conf dir
COPY ./cache-ispn-jdbc-ping.xml /opt/keycloak/conf/cache-ispn-jdbc-ping.xml
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:17.0.0
COPY --from=builder /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/
WORKDIR /opt/keycloak
# for demonstration purposes only, please make sure to use proper certificates in production instead
RUN 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 conf/server.keystore
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start"]
@chrisz2012
Copy link

This worked for me for my docker-compose.yml. I had to run JDBC_PING on two docker-compose VMs on VMWare with docker-compose to use JDBC_PING. Without in my cache configuration file I could not get two separate hosts to communicate together with my Keycloak Database. Hopefully this helps someone in the future.

version: "3.8"

services:

keycloak:
environment:
KC_DB: postgres
KC_DB_URL: 'jdbc:postgresql://:/'
KC_DB_USERNAME: ""
KC_DB_PASSWORD: ""
KC_DB_SCHEMA: ""
KC_HTTPS_CERTIFICATE_FILE: "/etc/x509/https/tls.crt"
KC_HTTPS_CERTIFICATE_KEY_FILE: "/etc/x509/https/tls.key"
KEYCLOAK_ADMIN: "admin"
KC_HTTPS_PORT: 443
KEYCLOAK_ADMIN_PASSWORD: ""
KC_HOSTNAME_ADMIN_URL: "https:///"
KC_HOSTNAME_URL: "https:///"
KC_HTTPS_TRUST_STORE_FILE: "/etc/x509/https/keycloak-ca.jks"
KC_TRUSTSTORE_PATHS: "/etc/x509/https/keycloak-ca.jks"
KC_HTTPS_TRUST_STORE_PASSWORD: ""
KC_LOG_LEVEL: "info"
KC_LOG: "console,file"
KC_CACHE: "ispn"
KC_METRICS_ENABLED: "true"
KC_BIND_PORT: 7600
KC_BIND_ADDR: "192.168.x.x"
KC_EXTERNAL_ADDR: "192.168.x.x"
QUARKUS_TRANSACTION_MANAGER_ENABLE_RECOVERY: "true"
JGROUPS_DISCOVERY_PROPERTIES : initial_hosts="192.168.x.1[7600],192.168.x.2[7600]"
JGROUPS_DISCOVERY_EXTERNAL_IP: "192.168.x.1"
JGROUPS_DISCOVERY_PROTOCOL: "JDBC_PING"
JGROUPS_DISCOVERY_PROPERTIES: "datasource_jndi_name=java:jboss/datasources/KeycloakDS"
KC_CACHE_CONFIG_FILE: "cache-ispn-jdbc-ping.xml"

image: ${IMAGE_ID}
ports:
  - 8443:8443
  - 443:443
  - 7600:7600
restart: always
command:
  - "start"
volumes:
  - keycloak-storage:/opt/keycloak/data/
  - ./ssl/your-cert.crt:/etc/x509/https/tls.crt
  - ./ssl/your-key.key:/etc/x509/https/tls.key
  - ./ssl/your-jks-security.jks:/etc/x509/https/keycloak-ca.jks
  - ./configs/cache-ispn-jdbc-ping.xml:/opt/keycloak/conf/cache-ispn-jdbc-ping.xml

volumes:
keycloak-storage:
driver: local
driver_opts:
type: none
o: bind
device: /var/log/keycloak

My cache file was like this for running two VMs running docker-compose I had to set my External IP in each docker-compose file correctly to the host IP for the JGROUPS_DISCOVERY_EXTERNAL_IP. The cache file references the docker-compose.yml file variable JGROUPS_DISCOVERY_EXTERNAL_IP.

<stack name="jdbc-ping-tcp" extends="tcp">
  <TCP external_addr="${env.JGROUPS_DISCOVERY_EXTERNAL_IP}" bind_port="7600" />
  <JDBC_PING connection_driver="org.postgresql.Driver"
             connection_username="id_kc_stg" connection_password="g9kEyD6sn0"
             connection_url="jdbc:postgresql://<db-port>:<db-port>/<db-schema>"
             initialize_sql="CREATE TABLE IF NOT EXISTS JGROUPSPING (own_addr varchar(200) NOT NULL, cluster_name varchar(200) NOT NULL, ping_data BYTEA, constraint PK_JGROUPSPING PRIMARY KEY (own_addr, cluster_name));"
             info_writer_sleep_time="500"
             remove_all_data_on_view_change="true"
             stack.combine="REPLACE"
             stack.position="MPING" />
</stack>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment