I have setup Keyclock v21.x on Kubernetes along with Infinispan v14.x.
In Infinispan, I have created distributed caches named sessions
, offlineSessions
, offlineClientSessions
, actionTokens
,loginFailures
, authenticationSessions
, clientSessions
and replicated cache named work
.
I have configured encoding media-type as "application/x-jboss-marshalling"
for all caches.
Eg. of sessions cache.
"sessions": {
"distributed-cache": {
"owners": "2",
"mode": "SYNC",
"statistics": true,
"encoding": {
"media-type": "application/x-jboss-marshalling"
},
"locking": {
"isolation": "REPEATABLE_READ"
}
}
}
}
This worked ok in Keycloak v20.0. In that I faced different issues so switch to Keyclock v21.x.
In Keyclock 21,x we get transcoding error as below
2023-05-04 04:03:29,630 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: org.infinispan.commons.dataconversion.EncodingException: ISPN000492: Cannot find transcoder between 'application/x-protostream' to 'application/x-jboss-marshalling'
This states that Cache is using jboss-marshelling but getting data x-protostream from keycloak.
So after this tried updating sessions
cache encoding as x-protostream
, however I got below error:
javax.security.sasl.SaslException: ELY05087: Client selected realm not offered by server (AllowScriptManager)
So what kind of cache encoding, I should configure in infinispan?
Also in cache-ispn-remote.xml
, configured remote store for all caches.
Eg.
<distributed-cache name="sessions" owners="2">
<expiration lifespan="-1"/>
<remote-store cache="sessions" xmlns="urn:infinispan:config:store:remote:13.0"
fetch-state="false"
purge="false"
preload="false"
shared="true" segmented="false"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
<property name="rawValues">true</property>
<property name="marshaller">org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory</property>
</remote-store>
</distributed-cache>
And keycloak-values.yaml
content
logging:
level: DEBUG
replicaCount: 2
image:
registry: docker.io
repository: bitnami/keycloak
tag: 21.0.2-debian-11-r0
production: true
resources:
limits:
cpu: 700m
memory: 2048Mi
requests:
cpu: 700m
memory: 2048Mi
tls:
enabled: true
autoGenerated: true
extraVolumeMounts: |
- name: quarkus
mountPath: /opt/bitnami/keycloak/conf/quarkus.properties
subPath: quarkus.properties
- name: keycloak
mountPath: /opt/bitnami/keycloak/conf/cache-ispn.xml
subPath: cache-ispn-remote.xml
extraVolumes: |
- name: quarkus
configMap:
name: quarkus
defaultMode: 0777
- name: keycloak
configMap:
name: keycloak
defaultMode: 0777
extraEnvVars:
- name: KC_CACHE_STACK
value: kubernetes
- name: KC_PROXY
value: edge
- name: KEYCLOAK_PROXY
value: edge
- name: KEYCLOAK_PROXY_ADDRESS_FORWARDING
value: "true"
- name: QUARKUS_INFINISPAN_CLIENT_SERVER_LIST
value: infinispan.keycloak.svc.cluster.local:11222
- name: INFINISPAN_SERVER
value: infinispan.keycloak.svc.cluster.local
- name: KC_DB
value: postgres
- name: KC_DB_URL_HOST
value: <RDS endpoint>
- name: KC_DB_URL_DATABASE
value: keycloak
- name: KC_DB_USERNAME
value: postgres
- name: KC_DB_PASSWORD
value: <RDS Password>
- name: KEYCLOAK_REMOTE_ISPN_USERNAME
value: developer
- name: KEYCLOAK_REMOTE_ISPN_PASSWORD
value: <Infinispan developer password>
- name: KC_CACHE
value: ispn
- name: JAVA_OPTS_APPEND
value: -Djboss.site.name=site1 -Djgroups.dns.query=keycloak-headless.keycloak.svc.cluster.local -Dinfinispan.deserialization.allowlist.classes=org.keycloak.cluster.infinispan.WrapperClusterEvent -Dinfinispan.deserialization.allowlist.regexps=.*
- name: KEYCLOAK_PRODUCTION
value: "true"
- name: KEYCLOAK_ENABLE_HTTPS
value: "false"
- name: KC_CACHE_CONFIG_FILE
value: cache-ispn.xml
cache:
enabled: true
postgresql:
enabled: false
externalDatabase:
host: <RDS endpoint>
port: 5432
user: postgres
password: <RDS Password>
database: keycloak
auth:
adminUser: admin
adminPassword: admin
service:
type: ClusterIP
ingress:
enabled: true
ingressClassName: "alb"
pathType: "Prefix"
hostname: "kcauth.example.com"
annotations:
#kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/target-type: 'ip'
alb.ingress.kubernetes.io/certificate-arn: "<ARN of ACM>"
alb.ingress.kubernetes.io/subnets: <SUBNETS IDs>
alb.ingress.kubernetes.io/conditions.keycloak: |
[{"Field":"host-header","HostHeaderConfig":{"Values":["*.example.com"]}}]
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS-1-1-2017-01
Found fix for this. Ref: https://github.com/keycloak/keycloak/issues/20031
Now Keycloak version 21 is working with Infinispan cache.
Now my cache-ispn-remote.xml looks like:
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd"
xmlns="urn:infinispan:config:14.0">
<cache-container name="keycloak">
<transport lock-timeout="60000" site="site1"/>
<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>
<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>
<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>
<distributed-cache name="sessions" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="sessions"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<distributed-cache name="authenticationSessions" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="authenticationSessions"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="offlineSessions"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<distributed-cache name="clientSessions" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="clientSessions"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="offlineClientSessions"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<distributed-cache name="loginFailures" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="loginFailures"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<distributed-cache name="actionTokens" owners="2">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="actionTokens"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</distributed-cache>
<replicated-cache name="work">
<remote-store xmlns="urn:infinispan:config:store:remote:14.0"
cache="actionTokens"
purge="false"
preload="false"
segmented="false"
shared="true"
raw-values="true"
marshaller="org.keycloak.cluster.infinispan.KeycloakHotRodMarshallerFactory"
connect-timeout="${env.KEYCLOAK_REMOTE_ISPN_CONN_TIMEOUT:2000}">
<remote-server host="${env.INFINISPAN_SERVER}" port="${infinispan.bind.port:11222}"/>
<security>
<authentication>
<digest username="${env.KEYCLOAK_REMOTE_ISPN_USERNAME:keycloak}"
password="${env.KEYCLOAK_REMOTE_ISPN_PASSWORD:password}"
realm="default"/>
</authentication>
</security>
</remote-store>
</replicated-cache>
</cache-container>
</infinispan>