Keycloak 17 Admin Console shows only the top navigation bar

[I’m upgrading from a previous Wildfly version of Keycloak to the Quarkus-powered v17]

When I log in to the Admin console, the browser goes to /admin/master/console/#/ but the displayed page only has the top navigation bar visible.

Browser developer tools reveal that this is because /realms/master/protocol/openid-connect/login-status-iframe.html/init has returned zero content.

My setup uses Docker; the Keycloak container is accessed via an OpenResty front end; the database is MariaDB. All non-admin functions of my setup work fine, by the way (configurations excluded from the OpenResty section below).

Dockerfile

ARG IMAGE_BASE="quay.io/keycloak/keycloak"
ARG IMAGE_TAG="17.0.1"
FROM ${IMAGE_BASE}:${IMAGE_TAG} as builder
RUN /opt/keycloak/bin/kc.sh build --db=mariadb
FROM ${IMAGE_BASE}:${IMAGE_TAG}
COPY --from=builder /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/
WORKDIR /opt/keycloak
ENV KEYCLOAK_ADMIN=kcadmin
ENV KC_DB_URL_DATABASE=keycloak
ENV KC_DB_URL_HOST=keycloakdb
ENV KC_DB_USERNAME=keycloak
ENV KC_HOSTNAME_PORT=443
ENV KC_HOSTNAME_STRICT=false
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start"]

Docker Compose setup service definition (run once as part of scripts to establish the MariaDB database)

version: "3.8"
services:
    keycloakdb:
        environment:
            - MARIADB_ROOT_PASSWORD=${MARIADB_ROOT}
            - MARIADB_DATABASE=keycloak
            - MARIADB_USER=keycloak
            - MARIADB_PASSWORD=${MARIADB_PASSWORD}
        hostname: keycloakdb
        image: "mariadb:10.7.3-focal"
        networks:
            - keycloakdb
        security_opt:
            - no-new-privileges:true
        volumes:
            - keycloakdb:/var/lib/mysql
    keycloak:
        depends_on:
            - keycloakdb
        environment:
            - KC_DB=mariadb
            - KC_DB_PASSWORD=${MARIADB_PASSWORD}
            - KEYCLOAK_ADMIN_PASSWORD=${KEYCLOAK_PASSWORD}
        entrypoint: ["/opt/keycloak/bin/kc.sh", "start-dev"]
        hostname: keycloak
        image: "local/keycloak:17.0.1.1"
        networks:
            - keycloakdb
            - keycloak
        security_opt:
            - no-new-privileges:true
volumes:
    keycloakdb:
networks:
    keycloakdb:
    keycloak:

Docker Compose runtime service definition

version: "3.8"
services:
    keycloakdb:
        hostname: keycloakdb
        image: "mariadb:10.7.3-focal"
        restart: unless-stopped
        networks:
            - keycloakdb
        security_opt:
            - no-new-privileges:true
        volumes:
            - keycloakdb:/var/lib/mysql
    keycloak:
        depends_on:
            - keycloakdb
        environment:
            - KC_DB=mariadb
            - KC_DB_PASSWORD=${MARIADB_PASSWORD}
            - KC_HOSTNAME=server-auth.something
            - KC_HOSTNAME_PORT=443
            - KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/redacted
            - KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/certs/redacted
            - KC_PROXY=passthrough
        hostname: keycloak
        image: "local/keycloak:17.0.1.1"
        restart: unless-stopped
        networks:
            - keycloakdb
            - keycloak
        security_opt:
            - no-new-privileges:true
        volumes:
            - ssl:/etc/pki/tls/certs/:ro
    openresty:
        depends_on:
        - keycloak
        hostname: openresty
        image: "local/openresty:1.19.3.2-3.0"
        restart: unless-stopped
        networks:
        - keycloak
        ports:
        - "443:8443"
        security_opt:
        - no-new-privileges:true
        volumes:
        - /usr/local/etc/openresty/conf.d/:/etc/nginx/conf.d/:ro
        - /usr/local/etc/openresty/html/:/usr/local/openresty/nginx/html/:ro
        - /usr/local/etc/openresty/nginx.conf:/usr/local/openresty/nginx/conf/nginx.conf:ro
        - ssl:/usr/local/etc/ssl/:ro
volumes:
    keycloakdb:
    ssl:
networks:
    keycloakdb:
    keycloak:

OpenResty server definition for “server-auth.something” endpoint

server {
listen              8443 ssl;
set                 $session_check_ssi off;
set                 $session_secret redacted;
ssl_certificate     /usr/local/etc/ssl/redacted;
ssl_certificate_key /usr/local/etc/ssl/redacted;
ssl_verify_client   off;
ssl_protocols       TLSv1.2 TLSv1.3;
ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_dhparam         /etc/nginx/conf.d/dhparam;
server_name         server-auth.something;
include             /etc/nginx/conf.d/locations/auth/*.conf;
}

OpenResty location for the “server-auth.something” endpoint

location / {
proxy_set_header Host                $host;
proxy_set_header X-Real-IP           $remote_addr;
proxy_set_header X-Forwarded-For     $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto   $scheme;
proxy_set_header X-Forwarded-Port    443;
proxy_pass https://keycloak:8443;
}

OpenResty logs for signing on to the Keycloak Admin console

[01/Apr/2022:03:22:56 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/ HTTP/1.1 302 upstream_response_time 0.640 msec 1648783376.709 request_time 0.640
[01/Apr/2022:03:22:56 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/master/console/ HTTP/1.1 200 upstream_response_time 0.256 msec 1648783376.982 request_time 0.256
[01/Apr/2022:03:22:57 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/master/console/config HTTP/1.1 200 upstream_response_time 0.076 msec 1648783377.311 request_time 0.077
[01/Apr/2022:03:22:57 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /realms/master/protocol/openid-connect/3p-cookies/step2.html HTTP/1.1 200 upstream_response_time 0.036 msec 1648783377.416 request_time 0.037
[01/Apr/2022:03:22:58 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /realms/master/protocol/openid-connect/auth?client_id=security-admin-console&redirect_uri=https%3A%2F%2Fserver-auth.something%2Fadmin%2Fmaster%2Fconsole%2F&state=645e0d5e-233d-4ca3-af90-c5f4629a3708&response_mode=fragment&response_type=code&scope=openid&nonce=51bb6e1b-e094-45f9-987c-7573d1d73fee&code_challenge=2snq1kPAqxEtYySr6uW5LQLklmMo69PC2-_mAiTJeWs&code_challenge_method=S256 HTTP/1.1 200 upstream_response_time 0.660 msec 1648783378.138 request_time 0.662
[01/Apr/2022:03:23:31 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: POST /realms/master/login-actions/authenticate?session_code=jqVPFL039sU_aqykn75X8nHrQXzKehuoRl1FTP0EhzM&execution=5ec21d77-c6a7-4128-9dc6-e78d7a7fcdee&client_id=security-admin-console&tab_id=EF9f4IXRqGQ HTTP/1.1 302 upstream_response_time 0.660 msec 1648783411.312 request_time 0.664
[01/Apr/2022:03:23:31 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/master/console/ HTTP/1.1 200 upstream_response_time 0.028 msec 1648783411.362 request_time 0.031
[01/Apr/2022:03:23:31 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/master/console/config HTTP/1.1 200 upstream_response_time 0.012 msec 1648783411.544 request_time 0.016
[01/Apr/2022:03:23:31 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /realms/master/protocol/openid-connect/3p-cookies/step2.html HTTP/1.1 200 upstream_response_time 0.008 msec 1648783411.623 request_time 0.014
[01/Apr/2022:03:23:32 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: POST /realms/master/protocol/openid-connect/token HTTP/1.1 200 upstream_response_time 0.236 msec 1648783412.096 request_time 0.237
[01/Apr/2022:03:23:32 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/master/console/whoami HTTP/1.1 200 upstream_response_time 0.296 msec 1648783412.405 request_time 0.296
[01/Apr/2022:03:23:32 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /admin/master/console/messages.json?lang=en HTTP/1.1 200 upstream_response_time 0.056 msec 1648783412.486 request_time 0.058
2022/04/01 03:23:32 [info] 12#12: *1 epoll_wait() reported that client prematurely closed connection, so upstream connection is closed too while SSL handshaking to upstream, client: 192.168.1.5, server: server-auth.something, request: "GET /resources/ah1gz/admin/keycloak/partials/menu.html HTTP/1.1", upstream: "https://192.168.22.2:8443/resources/ah1gz/admin/keycloak/partials/menu.html", host: "server-auth.something"
[01/Apr/2022:03:23:32 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /resources/ah1gz/admin/keycloak/partials/menu.html HTTP/1.1 499 upstream_response_time 0.000 msec 1648783412.578 request_time 0.000
[01/Apr/2022:03:23:32 +0000] 192.168.1.5 - - - - - server-auth.something to: 192.168.22.2:8443: GET /realms/master/protocol/openid-connect/login-status-iframe.html/init?client_id=security-admin-console&origin=https%3A%2F%2Fserver-auth.something HTTP/1.1 204 upstream_response_time 0.028 msec 1648783412.633 request_time 0.028

Keycloak logs for signing on to the Keycloak Admin console

2022-04-01 14:22:15,503 INFO  [org.keycloak.quarkus.runtime.hostname.DefaultHostnameProvider] (main) Hostname settings: FrontEnd: server-auth.something, Strict HTTPS: true, Path: <request>, Strict BackChannel: false, Admin: <request>, Port: 443, Proxied: true
2022-04-01 14:22:16,774 WARN  [org.infinispan.CONFIG] (keycloak-cache-init) ISPN000569: Unable to persist Infinispan internal caches as no global state enabled
2022-04-01 14:22:16,780 WARN  [org.infinispan.PERSISTENCE] (keycloak-cache-init) ISPN000554: jboss-marshalling is deprecated and planned for removal
2022-04-01 14:22:16,808 INFO  [org.infinispan.CONTAINER] (keycloak-cache-init) ISPN000556: Starting user marshaller 'org.infinispan.jboss.marshalling.core.JBossUserMarshaller'
2022-04-01 14:22:16,995 INFO  [org.infinispan.CONTAINER] (keycloak-cache-init) ISPN000128: Infinispan version: Infinispan 'Triskaidekaphobia' 13.0.6.Final
2022-04-01 14:22:17,103 INFO  [org.infinispan.CLUSTER] (keycloak-cache-init) ISPN000078: Starting JGroups channel `ISPN`
2022-04-01 14:22:17,103 INFO  [org.infinispan.CLUSTER] (keycloak-cache-init) ISPN000088: Unable to use any JGroups configuration mechanisms provided in properties {}. Using default JGroups configuration!
2022-04-01 14:22:17,180 WARN  [org.jgroups.protocols.UDP] (keycloak-cache-init) JGRP000015: the send buffer of socket MulticastSocket was set to 1.00MB, but the OS only allocated 212.99KB
2022-04-01 14:22:17,180 WARN  [org.jgroups.protocols.UDP] (keycloak-cache-init) JGRP000015: the receive buffer of socket MulticastSocket was set to 20.00MB, but the OS only allocated 212.99KB
2022-04-01 14:22:17,181 WARN  [org.jgroups.protocols.UDP] (keycloak-cache-init) JGRP000015: the send buffer of socket MulticastSocket was set to 1.00MB, but the OS only allocated 212.99KB
2022-04-01 14:22:17,181 WARN  [org.jgroups.protocols.UDP] (keycloak-cache-init) JGRP000015: the receive buffer of socket MulticastSocket was set to 25.00MB, but the OS only allocated 212.99KB
2022-04-01 14:22:19,196 INFO  [org.jgroups.protocols.pbcast.GMS] (keycloak-cache-init) keycloak-15933: no members discovered after 2003 ms: creating cluster as coordinator
2022-04-01 14:22:19,214 INFO  [org.infinispan.CLUSTER] (keycloak-cache-init) ISPN000094: Received new cluster view for channel ISPN: [keycloak-15933|0] (1) [keycloak-15933]
2022-04-01 14:22:19,219 INFO  [org.infinispan.CLUSTER] (keycloak-cache-init) ISPN000079: Channel `ISPN` local address is `keycloak-15933`, physical addresses are `[192.168.22.2:41631]`
2022-04-01 14:22:19,806 INFO  [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: keycloak-15933, Site name: null
2022-04-01 14:22:20,557 INFO  [io.quarkus] (main) Keycloak 17.0.1 on JVM (powered by Quarkus 2.7.5.Final) started in 8.937s. Listening on: https://0.0.0.0:8443
2022-04-01 14:22:20,557 INFO  [io.quarkus] (main) Profile prod activated.
2022-04-01 14:22:20,558 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-h2, jdbc-mariadb, jdbc-mssql, jdbc-mysql, jdbc-oracle, jdbc-postgresql, keycloak, narayana-jta, reactive-routes, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, smallrye-metrics, vault, vertx]

I hope someone can point out whatever silly configuration mistake I am making.

I am not sure if it is related, but there might be issues with forwarded http headers:

If that does not work, can you try with version 17.0.0 and see the behaviour is different from 17.0.1.

Update 4/Apr

Thank you for the suggestion to drop back to 17.0.0 … This now works perfectly. For the record, my running Docker Compose service definition for the Keycloak container is

    keycloak:
        depends_on:
            - keycloakdb
        environment:
            - KC_DB=mariadb
            - KC_DB_PASSWORD=${MARIADB_PASSWORD}
            - KC_HOSTNAME=server-auth.something
            - KC_HOSTNAME_PORT=443
            - KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/redacted
            - KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/certs/redacted
        hostname: keycloak
        image: "local/keycloak:17.0.0.1"
        restart: unless-stopped
        networks:
            - keycloakdb
            - keycloak
        security_opt:
            - no-new-privileges:true
        volumes:
            - ssl:/etc/pki/tls/certs/:ro

KC_PROXY is not used.

I will allow the dust to settle on issue #10997, perhaps wait for a 17.0.2. In the meantime I can get on with my work.

Thanks again.

I am glad it worked.

Who does the ssl termination? Keycloak? Or do you have a reverse proxy / load balancer doing that before the Keycloak?

All browser traffic flows to an Nginx reverse proxy implemented in an OpenResty container; the Nginx server is configured with TLS certificates. Internal Nginx traffic to the Keycloak container is also TLS in this case.

Anyone else encountering only the top nav header rendering when using 17.0.1, try setting the proxy value to edge or none in your config, regardless of whether you are using a proxy. For some folks, this has resolved it. Hopefully a fix is coming in the next release.

1 Like