I have the situation that I run Keycloak 18.0.0 behind a reverse proxy that is terminating the secure (https) connection. Therefore I would like to build a Docker image that configures Keycloak to only listen on http (e.g. port 8080).
I have adjusted the Dockerfile from the Keycloak documentation. It uses
- MariaDB as database
- Enables Health and Metrics Endpoints
- Since I'm terminating the TLS connection in the reverse proxy I additionally make use of the
--proxy=edgeoption, when starting Keycloak (see Proxy Mode).
FROM quay.io/keycloak/keycloak:18.0.0 as builder
ENV KC_HEALTH_ENABLED=true
ENV KC_METRICS_ENABLED=true
ENV KC_DB=mariadb
# Install custom providers
RUN curl -sL https://github.com/aerogear/keycloak-metrics-spi/releases/download/2.5.3/keycloak-metrics-spi-2.5.3.jar -o /opt/keycloak/providers/keycloak-metrics-spi-2.5.3.jar
RUN /opt/keycloak/bin/kc.sh build
FROM quay.io/keycloak/keycloak:18.0.0
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh", "start"]
I then build my Docker image using
docker build --no-cache . -t ghcr.io/saw303/zscsupporter-be/keycloak-18.0.0:0.0.1
and start the image within my Docker Composition.
version: "3.9"
services:
proxy:
image: caddy:2.5.1-alpine
ports:
- "${PROXY_IP}:80:80"
- "${PROXY_IP}:443:443"
volumes:
- ${BASE_PATH:-.}/docker-volume/caddy/Caddyfile:/etc/caddy/Caddyfile:Z
- ${BASE_PATH:-.}/docker-volume/caddy/caddy_data:/data:Z
- ${BASE_PATH:-.}/docker-volume/caddy/caddy_config:/config:Z
keycloak:
image: ghcr.io/saw303/zscsupporter-be/keycloak-18.0.0:0.0.1
ports:
- "127.0.0.1:9001:8080"
- "127.0.0.1:9443:8443"
environment:
KC_HOSTNAME: localhost
KC_HOSTNAME_PORT: 80
KC_HOSTNAME_STRICT_BACKCHANNEL: true
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB_URL: jdbc:mariadb://keycloakdb:3306/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: secret
KC_LOG_LEVEL: info
KC_PROXY: edge
keycloakdb:
image: mariadb:10.7.3-focal
environment:
MYSQL_ROOT_PASSWORD: root_secret
MYSQL_DATABASE: keycloak
MYSQL_USER: keycloak
MYSQL_PASSWORD: secret
TZ: "Europe/Zurich"
tmpfs:
- /var/lib/mysql:rw
ports:
- "127.0.0.1:3307:3306"
When I then start the Docker composition using
docker compose up -d && docker compose logs -f keycloak
I get the following log statement that clearly states that it uses Strict HTTPS.
backend-keycloak-1 | 2022-05-29 17:37:46,922 INFO [org.keycloak.quarkus.runtime.hostname.DefaultHostnameProvider] (main) Hostname settings: FrontEnd: localhost, Strict HTTPS: true, Path: <request>, Strict BackChannel: false, Admin: localhost, Port: 8,080, Proxied: true
And when I access the administration console
http://localhost:9001/admin/master/console/
I get a blank page and the admin console sends only one request to
http://localhost:9001/admin/master/console/config
which returns wrong URLs https:.
{
"realm": "master",
"auth-server-url": "https://localhost:8080/",
"ssl-required": "external",
"resource": "security-admin-console",
"public-client": true,
"confidential-port": 0
}
Is there a way to change the protocol in field value auth-server-url from https to http?
Update 1: Proxy configuration
I use Caddy Server 2.0 as a reverse proxy. In this test setup caddy is part of the Docker composition and simply redirects all request on port 80 to the keycloak container on port 8080.
{
admin off
}
localhost:80
reverse_proxy /* keycloak:8080
log
Please note that the behaviour is the same whether I access the Keycloak admin console through the reverse proxy localhost:80 or directly localhost:9001. When accessing it through the proxy I, of course change the port value KC_HOSTNAME_PORT: 80.
Update 2: Set KC_PROXY in docker-compose.yml
The KC_PROXY env variable is now set in the docker-compose.yml but the behaviour is the same. When I jump into the running keycloak container I see the following active configuration
ā docker compose exec keycloak bash
WARN[0000] The "PROXY_IP" variable is not set. Defaulting to a blank string.
WARN[0000] The "PROXY_IP" variable is not set. Defaulting to a blank string.
bash-4.4$ bin/kc.sh show-config
Current Mode: none
Runtime Configuration:
kc.cache = ispn (PersistedConfigSource)
kc.config.args = show-config (SysPropConfigSource)
kc.db = mariadb (PersistedConfigSource)
kc.db.password = secret (EnvConfigSource)
kc.db.url = jdbc:mariadb://keycloakdb:3306/keycloak (EnvConfigSource)
kc.db.username = keycloak (EnvConfigSource)
kc.health-enabled = true (PersistedConfigSource)
kc.home.dir = /opt/keycloak/bin/../ (SysPropConfigSource)
kc.hostname = localhost (EnvConfigSource)
kc.hostname.port = 80 (EnvConfigSource)
kc.hostname.strict.backchannel = true (EnvConfigSource)
kc.http-enabled = false (PropertiesConfigSource[source=jar:file:///opt/keycloak/lib/lib/main/org.keycloak.keycloak-quarkus-server-18.0.0.jar!/META-INF/keycloak.conf])
kc.http-relative-path = / (PersistedConfigSource)
kc.log-console-output = default (PropertiesConfigSource[source=jar:file:///opt/keycloak/lib/lib/main/org.keycloak.keycloak-quarkus-server-18.0.0.jar!/META-INF/keycloak.conf])
kc.log-file = /opt/keycloak/bin/../data/log/keycloak.log (PropertiesConfigSource[source=jar:file:///opt/keycloak/lib/lib/main/org.keycloak.keycloak-quarkus-server-18.0.0.jar!/META-INF/keycloak.conf])
kc.log.level = info (EnvConfigSource)
kc.metrics-enabled = true (PersistedConfigSource)
kc.provider.file.keycloak-metrics-spi-2.5.3.jar.last-modified = 1653899384311 (PersistedConfigSource)
kc.proxy = edge (EnvConfigSource)
kc.quarkus-properties-enabled = false (PersistedConfigSource)
kc.show.config = none (SysPropConfigSource)
kc.version = 18.0.0 (SysPropConfigSource)
The interesting part is that it indicates that http is disabled.
kc.http-enabled = false (PropertiesConfigSource[source=jar:file:///opt/keycloak/lib/lib/main/org.keycloak.keycloak-quarkus-server-18.0.0.jar!/META-INF/keycloak.conf])