How to change fronend URL in Keycloak behind NGINX ingress?

7/13/2021

There are many questions like this I can find in the internet but none of the solutions provided worked.

I am using jboss/keycloak:14.0.0 docker image. The following properties are set in my ConfigMap:

KEYCLOAK_FRONTEND_URL: /mycontext/access-management
PROXY_ADDRESS_FORWARDING: "true"

Please note that, change the KEYCLOAK_FRONTEND_URL to an absolute URL like this https://mycompany.com/mycontext/access-managemen makes no difference.

Now the ingress has been defined as below:

Path: /mycontext/access-management(/|$)(.*)
Rewrite To: /$2
Annotations:
    ingress.kubernetes.io/ssl-redirect: "False"
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Request-ID $request_id;
      proxy_set_header X-Trace-ID $request_id;
      gzip off;
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "180"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "180"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "180"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/server-snippet: |
      add_header X-Request-ID $request_id;
      add_header X-Trace-ID $request_id;
    nginx.org/redirect-to-https: "True"

What happens is very strange. See below it shows you where it takes me when I hit a URL:

Go to [server]/mycontext/access-management =takes you to=> [server]/auth
Go to [server]/mycontext/access-management/auth =takes you to=> [server]/mycontext/access-management/auth (works fine)

As you can see the second link works fine and you can see the Keycloak Welcome page with a number of links in it. One of the links is Administration Console that is broken. If you hover your mouse the link is [server]/mycontext/access-management/admin instead of [server]/mycontext/access-management/auth/admin (comparing it with my local Keycloak server). Now if we ignore the link and put the right path in the address bar as [server]/mycontext/access-management/auth/admin another strange thing happens and that changes the URL to [server]/auth/mycontext/access-management/admin/master/console/.

I really don't understand what is happening here. Setting KEYCLOAK_FRONTEND_URL on my local also breaks the links.

I have tried to change the rewrite annotation of the ingress to /mycontext/access-management/$2 but this configuration doesn't work at all.

In the Keycloak documentation here it talks about a property named adminUrl, however, setting -DadminUrl or -Dkeycloak.adminUrl seems to be ignored completely by the docker image when using JAVA_OPTS_APPEND according to JBoss documentation page.

What have I missed here? Is there anything that I have missed in my configuration?

Please note that, we have no choice other than exposing it under a context-path followed by the name (i.e. /mycontext/access-management). This is because of both our client requirements as well as the fact that we have many micro-services deployed under /mycontext each of which has its own ingress configuration.

Any help is appreciated.

-- xbmono
keycloak
kubernetes
nginx-ingress

1 Answer

7/14/2021

Okay I managed to get this working by gathering all the solutions that are mentioned out there.

So basically, web-context needs to be set and that's something that is not mentioned anywhere in any documentation except word of mouth.

To set that, you can write a cli script:

set CONTEXT=${env.KEYCLOAK_WEB_CONTEXT}
echo $CONTEXT
embed-server --server-config=standalone-ha.xml --std-out=echo
/subsystem=keycloak-server/:write-attribute(name=web-context,value=$CONTEXT)
stop-embedded-server

embed-server --server-config=standalone.xml --std-out=echo
/subsystem=keycloak-server/:write-attribute(name=web-context,value=$CONTEXT)
stop-embedded-server

This is mentioned here but the important things are 1. you need to start embed server otherwise there is no server to connect to and second you should change both standalone.xml and standalone-ha.xml unless you know which one exactly you are running.

See this answer here on how to copy custom scripts to your docker image.

However, there is one important point here! Although Keycloak documentation says that you can change the front-end URL to whatever you want, you actually HAVE TO add /auth at the end of your new URL. It seems many pages in Keycloak are hardcoded to that path

Now you need to set these two properties in your ConfigMap:

#ConfigMap
# Has to end with /auth and has to be absolute URL
KEYCLOAK_FRONTEND_URL: https://your.website.address/mycontext/access-management/auth
PROXY_ADDRESS_FORWARDING: "true"
# The following is our own env var that will be used by the above cli
# Note that it SHOULD NOT start with / and it must END with /auth
KEYCLOAK_WEB_CONTEXT: mycontext/access-management/auth

This is a bit annoying because KEYCLOAK_FRONTEND_URL cannot be relative path and has to be full absolute URL. The issue is you constructing that makes things not nice and elegant. Luckily we have a host property in global and is shared across the Helm's subcharts, so I could use it but really this makes the design a bit nasty.

But that's not just this, because of all these crap settings, now you have to change your liveness and readiness probes to GET /mycontext/access-management And even worst, if you have micro-services, which is nearly 20 for us, you'll need to change all the auth server URLs that was previously as simple as http://access-management:8080/auth to http://access-management:8080/mycontext/access-management/auth.

Now make sure your ingress also includes this new path plus another important property proxy-buffer-size. If you don't have a large buffer size Keycloak requests may not work and you will get Bad Gateway error:

Path: /mycontext/access-management(/|$)(.*)
Rewrite To: /mycontext/access-management/$2
nginx.ingress.kubernetes.io/proxy-buffer-size: 8k 

I really wished we could manage this with ingress without having to touch all these things but it seems not possible. I hope Keycloak.X will solve all these bad coding.

-- xbmono
Source: StackOverflow