Encrypting Infinispan cluster transport

Hi there,

I’m trying to ensure infinispan is encrypting its traffic between Keycloak instances, as described here: Infinispan Security Guide.

But I’m not sure where I should place the <server xmlns="urn:infinispan:server:14.0"> element. I’ve tried adding it to the file I specify in the cache-config-file Keycloak config option, but that results in the following error:

2023-04-28 14:44:33,853 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (production) mode
2023-04-28 14:44:33,853 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: Failed to start caches
2023-04-28 14:44:33,853 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: org.infinispan.commons.CacheConfigurationException: ISPN000327: Cannot find a parser for element 'server' in namespace 'urn:infinispan:server:14.0' at [27,19]. Check that your configuration is up-to-date for Infinispan '14.0.7.Final' and you have the proper dependency in the classpath
2023-04-28 14:44:33,854 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) ERROR: ISPN000327: Cannot find a parser for element 'server' in namespace 'urn:infinispan:server:14.0' at [27,19]. Check that your configuration is up-to-date for Infinispan '14.0.7.Final' and you have the proper dependency in the classpath
2023-04-28 14:44:33,854 ERROR [org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler] (main) For more details run the same command passing the '--verbose' option. Also you can use '--help' to see the details about the usage of the particular command.

This is with Keycloak 21.1.1 on Linux.

I’m pasting the cache config file below for reference.
Note that I’m using the JDBC_PING with TCP, since my users network topology does not suit UDP multicast.

<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
                            urn:infinispan:server:14.0 http://www.infinispan.org/schemas/infinispan-server-14.0.xsd"
        xmlns="urn:infinispan:config:14.0">

    <jgroups>
        <stack name="jdbc-ping-tcp" extends="tcp">
            <JDBC_PING
                    connection_driver="com.microsoft.sqlserver.jdbc.SQLServerDriver"
                    connection_username="sa" connection_password="redacted"
                    connection_url="jdbc:sqlserver://sql:1644;databaseName=keycloak;trustServerCertificate=true;"
                    initialize_sql="IF NOT EXISTS (  SELECT [name] FROM sys.tables WHERE [name] = 'JGROUPSPING' ) CREATE TABLE JGROUPSPING (own_addr varchar(200) NOT NULL, cluster_name varchar(200) NOT NULL, ping_data varbinary(5000) DEFAULT NULL, 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>

    <server xmlns="urn:infinispan:server:14.0">
        <security>
            <security-realms>
                <security-realm name="cluster-transport">
                    <server-identities>
                        <ssl>
                            <keystore path="/run/secrets/infinispan_certificate_file"
                                      password="redacted"
                                      type="PKCS12"/>
                        </ssl>
                    </server-identities>
                </security-realm>
            </security-realms>
        </security>
    </server>

    <cache-container name="keycloak">
        <transport lock-timeout="60000" stack="jdbc-ping-tcp" cluster="keycloak-cluster" server:security-realm="cluster-transport"/>
        <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>