I have migrated Keycloak to Quarkus distribution.
proxy=edge is used and custom path=/bouncer/auth
On local environment it is working fine but on kubernetes i am unable to access /bouncer/auth path.
When trying to access https://myhost/bouncer/auth I am receiving 503 error from nginx Service Temporarily Unavailable
Dockerfile:
ARG KEYCLOAK_VERSION
FROM eclipse-temurin:11-jdk-alpine as javabuilder
ARG KEYCLOAK_VERSION
# build metrics spi for metrics-events
RUN apk --update add git && mkdir -p /tmp/keycloak-metrics-spi
RUN echo "Building for keycloak version $KEYCLOAK_VERSION"
RUN git clone -b 2.5.3 https://github.com/aerogear/keycloak-metrics-spi.git /tmp/keycloak-metrics-spi && cd /tmp/keycloak-metrics-spi \
&& ./gradlew -PkeycloakVersion=$KEYCLOAK_VERSION jar
FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION} as builder
COPY ./custom-keycloak-image/docker/providers/ /opt/keycloak/providers/
COPY --from=javabuilder /tmp/keycloak-metrics-spi/build/libs/* /opt/keycloak/providers/
COPY ./custom-keycloak-image/docker/conf/keycloak-build.conf /opt/keycloak/conf/keycloak.conf
COPY ./custom-keycloak-image/docker/conf/cache-ispn-jdbc-ping.xml /opt/keycloak/conf/cache-ispn-jdbc-ping.xml
COPY ./custom-keycloak-image/keycloak-themes-1.0.0.jar /opt/keycloak/providers/keycloak-themes-1.0.0.jar
RUN /opt/keycloak/bin/kc.sh build
RUN /opt/keycloak/bin/kc.sh show-config
FROM quay.io/keycloak/keycloak:${KEYCLOAK_VERSION}
COPY --from=builder /opt/keycloak/lib/quarkus/ /opt/keycloak/lib/quarkus/
COPY --from=builder /opt/keycloak/providers/ /opt/keycloak/providers/
WORKDIR /opt/keycloak
ENTRYPOINT ["./bin/kc.sh", "start"]
Build settings:
# for build options check https;//www.keycloak.org/server/all-config?f=build
# db type is a build-time configuration
db=mariadb
# metrics and health endpoints
metrics-enabled=true
health-enabled=true
# enable infinispan cache to be able to use clustering
cache=ispn
cache-stack=kubernetes
cache-config-file=cache-ispn-jdbc-ping.xml
# features if used
features=admin-fine-grained-authz,token-exchange
# set relative path to /bouncer/auth to get previous behaviour (this affects health and metrics endpoints)
http-relative-path=/bouncer/auth
Kubernetes StatefulSet file:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: keycloak
labels:
app.kubernetes.io/name: keycloak
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: keycloak
serviceName: keycloak
template:
metadata:
labels:
app.kubernetes.io/name: keycloak
spec:
imagePullSecrets:
- name: registry
# securityContext:
# fsGroup: 1000
# runAsUser: 1000
volumes:
- name: startup
configMap:
name: keycloak-startup
defaultMode: 0555
initContainers:
- name: database
image: busybox:latest
command:
- /bin/sh
- -c
- |-
printf "[%s] %-35s" "$(date -R)" "check database.. "
until printf "." && nc -z -w 5 ${KC_DB_URL_HOST} ${KC_DB_URL_PORT}; do
sleep 5;
done;
echo 'OK ✓'
env:
- name: KC_DB_URL_HOST
valueFrom:
secretKeyRef:
name: keycloak
key: KC_DB_URL_HOST
- name: KC_DB_URL_PORT
valueFrom:
secretKeyRef:
name: keycloak
key: KC_DB_URL_PORT
resources:
requests:
cpu: "0.1"
memory: "32M"
limits:
cpu: "0.1"
memory: "32M"
securityContext:
readOnlyRootFilesystem: true
containers:
- name: keycloak
image: custom-keycloak-image:latest
imagePullPolicy: IfNotPresent
args:
- "--spi-connections-jpa-default-migration-strategy=update"
volumeMounts:
- name: startup
mountPath: /opt/keycloak/conf/keycloak.conf
subPath: keycloak.conf
readOnly: true
- name: startup
mountPath: /opt/keycloak/conf/quarkus.properties
subPath: quarkus.properties
readOnly: true
env:
- name: KC_HOSTNAME
value: "myhost"
- name: KC_HOSTNAME_PATH
value: "/bouncer/auth"
- name: KC_HOSTNAME_STRICT
value: "false"
- name: TZ
value: "Europe/Berlin"
- name: KC_HTTP_ENABLED
value: "true"
- name: KC_HTTP_RELATIVE_PATH
value: "/bouncer/auth"
- name: KEYCLOAK_STATISTICS
value: "all"
- name: PROXY_ADDRESS_FORWARDING
value: "true"
- name: JDBC_PARAMS
value: "useSSL=false"
- name: JAVA_XMX
value: "1024m"
- name: JAVA_OPTS_APPEND
value: "-Djava.security.egd=file:/dev/./urandom -Xmx${JAVA_XMX} -XshowSettings:vm -Dsun.net.maxDatagramSockets=1024 -Dlogstash-gelf.buffer.size=0 -Djgroups.dns.query=keycloak-headless"
envFrom:
- secretRef:
name: keycloak
ports:
- containerPort: 8080
name: metrics
resources:
requests:
cpu: "0.1"
memory: "2048M"
limits:
cpu: "4"
memory: "2048M"
livenessProbe:
httpGet:
scheme: HTTPS
path: /bouncer/auth
port: 8443
initialDelaySeconds: 180
periodSeconds: 60
timeoutSeconds: 5
readinessProbe:
httpGet:
scheme: HTTPS
path: /bouncer/auth
port: 8443
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
enableServiceLinks: false
restartPolicy: Always
automountServiceAccountToken: false
terminationGracePeriodSeconds: 60
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 10
podAffinityTerm:
topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: keycloak
Ingress file:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: keycloak
labels:
app.kubernetes.io/name: keycloak
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
nginx.ingress.kubernetes.io/rewrite-target: "/bouncer/$2"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/configuration-snippet: |
location ~* /auth/realms/[^/]+/metrics {
return 403;
}
spec:
rules:
- host: myhost
http:
paths:
- path: /bouncer(/|$)(.*)
backend:
serviceName: keycloak
servicePort: https
tls:
- hosts:
- myhost