JGroups icon indicating copy to clipboard operation
JGroups copied to clipboard

allow to configure dns_record_type with a system property

Open cpesch opened this issue 1 year ago • 9 comments

My setup is a set of Keycloak 18.0.2 clusters in an environment with nomad and consul. We're using DNS_PING with SRV records for a long time now and the JGroups setup is pretty simple:

JGROUPS_DISCOVERY_PROTOCOL=dns.DNS_PING
JGROUPS_DISCOVERY_PROPERTIES="dns_query="${dns_query}",dns_record_type="SRV""
JGROUPS_TRANSPORT_STACK="tcp"

When migrating this to Keycloak 23.0.7, I found that the dns_record_type separated with a comma is not supported anymore. With the documentation I found on the internet and discussions and issue in the JGroups, Infinispan, Keycloak github projects, I failed to get SRV records running with something straight-forward like this:

<infinispan ...>

    <jgroups>
        <stack name="dns-ping">
            <dns.DNS_PING dns_record_type="SRV"
                          dns_query="${dns_query}"/>
            <TCP diag.enabled="true"
                 bind_addr="GLOBAL"
                 external_addr="{{ env "NOMAD_IP_jgroupscluster" }}"
                 external_port="{{ env "NOMAD_HOST_PORT_jgroupscluster" }}"/>
        </stack>
    </jgroups>

    <cache-container name="keycloak">
        <transport stack="dns-ping"...

When looking at org.jgroups.protocols.dns.DNS_PING I found that only a tiny tweak is necessary to reduce all this down to

KC_CACHE=ispn
KC_CACHE_STACK=kubernetes
JAVA_OPTS_APPEND="-Djgroups.dns.dns_query=${dns_query} -Djgroups.dns.dns_record_type=SRV

This works fine for me since some days.

@belaban I'd be really happy if you include this in an upcoming 5.2.x release

cpesch avatar Mar 07 '24 12:03 cpesch

Hmm... adding the system property should not be required, although it certainly works, so no objections. This could be done in the XML config directly: JGroups parses comma-deparated attributes and tries to substitute both system properties and environment variables.

belaban avatar Mar 07 '24 14:03 belaban

In other words, no change and no release should be required...

belaban avatar Mar 07 '24 14:03 belaban

Hmm... adding the system property should not be required, although it certainly works, so no objections. This could be done in the XML config directly: JGroups parses comma-deparated attributes and tries to substitute both system properties and environment variables.

IIUC well, no - the whole point is so that you do not have to edit the XML as that's way more convoluted in a container rather than adding a property (this PR) and then simply adding -Djgroups.dns.dns_record_type=SRV to the start options.

rhusar avatar Mar 07 '24 14:03 rhusar

Christian is already using a system prop (JGROUPS_DISCOVERY_PROPERTIES) to change the config, so it could be done there (IMO)... BTW: a JIRA would be nice, so we can assign this change to a version

belaban avatar Mar 07 '24 14:03 belaban

IIUC well, no - the whole point is so that you do not have to edit the XML as that's way more convoluted in a container rather than adding a property (this PR) and then simply adding -Djgroups.dns.dns_record_type=SRV to the start option

@rhusar well said. I fully agree.

Christian is already using a system prop (JGROUPS_DISCOVERY_PROPERTIES) to change the config, so it could be done there (IMO)...

I'm confused: that was the Keycloak 18 legacy configuration.

Wait. Is there a way to set org.jgroups.protocols.dns.DNS_PING#dns_record_type without touching the XML? Just with a system property or environment variable?

cpesch avatar Mar 07 '24 14:03 cpesch

Yes, in the config (XML or programmatic):

<dns.DNS dns_record_type="${dns.record_type,RECORD_TYPE:A}".../>

Default is A. System property dns.record_type or env var RECORD_TYPE overrird this.

belaban avatar Mar 07 '24 15:03 belaban

Ok, that's exactly the config I was struggeling with. I spent two days reading and experimenting – and couldn't even see this in the logs:

2024-03-07 11:36:59,929 TRACE [org.jgroups.protocols.dns.DefaultDNSResolver] (jgroups-13,040f8502066a-48384) resolving DNS query: labs-keycloak-playground..... of a type: SRV

It might be caused by JGroups being integrated to Infinispan, and Infinispan being integrated in Keycloak. I've tried to find people who were successful with this. Could you spot, what's wrong here in my config?

<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">

<jgroups>
    <stack name="dns-ping">
        <dns.DNS_PING dns_record_type="SRV"
                      dns_query="${dns_query}"
                      stack.combine="REPLACE"
                      stack.position="MPING"/>
        <TCP diag.enabled="true"
             bind_addr="GLOBAL"
             external_addr="{{ env "NOMAD_IP_jgroupscluster" }}"
             external_port="{{ env "NOMAD_HOST_PORT_jgroupscluster" }}"/>
    </stack>
</jgroups>

<cache-container name="keycloak">
    <transport lock-timeout="60000" stack="dns-ping"/>
    <local-cache name="realms" simple-cache="true">
        <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" simple-cache="true">
        <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" simple-cache="true">
        <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" simple-cache="true">
        <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>

It looks simple but with this config, I don't see any output from the org.jgroups.protocols.dns.DefaultDNSResolver and I've tried a lot of variants. What am I missing?

cpesch avatar Mar 07 '24 16:03 cpesch

You need to extend the kubernetes stack:

      <stack name="dns-ping" extends="kubernetes">
         <dns.DNS_PING dns_record_type="SRV"/>
      </stack>

pruivo avatar Mar 07 '24 19:03 pruivo

Finally, I've found the road blocker for my efforts: the distributed cache configuration in Keycloak is part of the build time configuration and not the run time configuration. After putting this cache configuration file

<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">

    <jgroups>
        <stack name="dns-ping" extends="kubernetes">
            <dns.DNS_PING dns_query="${jgroups.dns.query}"
                          dns_record_type="${jgroups.dns.record:A}"
            />
        </stack>
    </jgroups>

    <cache-container name="keycloak">
        <transport lock-timeout="60000" stack="dns-ping"/>
...same as above...

into the docker image, running kc.sh build, I could configure it with

JAVA_OPTS_APPEND="-Xmx${kc_xmx}m -Djgroups.bind_addr=GLOBAL -Djgroups.external_addr={{ env "NOMAD_IP_jgroupscluster" }} -Djgroups.external_port={{ env "NOMAD_HOST_PORT_jgroupscluster" }} -Djgroups.dns.query=${dns_query} -Djgroups.dns.record=SRV"

at run time like for Keycloak 18 – and it works. This was the discussion that finally helped me.

cpesch avatar Mar 11 '24 14:03 cpesch

Sorry to let this one slip! Is this issue still relevant? Or would a change from JGroups' side be needed to make this less complicated?

belaban avatar Aug 20 '24 07:08 belaban

@belaban the change would remove some hours of researching and creating a custom XML configuration file in Keycloak/Infinispan to use SRV records for DNS lookup. IMHO it's still relevant as this is small change from JGroups' side would make this less complicated

cpesch avatar Aug 26 '24 09:08 cpesch