add-keycloakx/7.2.2: keycloakx 7.2.2 추가, keycloak/18.4.0 제거 (이슈 #1)

codecentric/keycloak(18.4.0, WildFly 기반, appVersion 17.0.1-legacy)이
bitnami/postgresql 서브차트를 조건부 의존성으로 포함해 bitnami 무료 배포
정책 변경 문제가 그대로 전이됐다. codecentric은 이 WildFly 차트를 더 이상
갱신하지 않고 Quarkus 기반 Keycloak(17+)용 별도 차트 keycloakx를 제공하며,
keycloakx는 서브차트 의존성이 전혀 없어(Chart.yaml에 dependencies 없음)
문제가 근본적으로 해소된다.

실제 소비자가 없어(문서 예시 표 한 줄 외 참조 없음) phased 전환 없이
keycloak/18.4.0을 같은 커밋에서 제거했다.

custom-values.yaml 작성 시 확인한 핵심 사항 — 이 차트의 http.relativePath
기본값이 구버전 WildFly Keycloak 호환용 "/auth"라, 명시적으로 "/"로
오버라이드해야 한다(안 하면 OIDC issuer/admin API 경로가 소비 앱들의
경로 접미사 없음 가정과 어긋난다). database.existingSecret/existingSecretKey
로 kubernetes.io/basic-auth 시크릿을 그대로 참조 가능함도 helm template로
확인했다.

Closes #1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wbsong111
2026-08-06 16:09:51 +09:00
parent e527131fd0
commit 611e971295
99 changed files with 1805 additions and 7432 deletions
@@ -0,0 +1,61 @@
***********************************************************************
* *
* Keycloak.X Helm Chart by codecentric AG *
* *
***********************************************************************
{{- if .Values.ingress.enabled }}
Keycloak was installed with an Ingress and an be reached at the following URL(s):
{{ range $unused, $rule := .Values.ingress.rules }}
{{- range $rule.paths }}
- http{{ if $.Values.ingress.tls }}s{{ end }}://{{ tpl $rule.host $ }}{{ .path }}
{{- end }}
{{- end }}
{{- else if eq "NodePort" .Values.service.type }}
Keycloak was installed with a Service of type NodePort.
{{ if .Values.service.httpNodePort }}
Get its HTTP URL with the following commands:
export NODE_PORT=$(kubectl get --namespace {{ include "keycloak.namespace" . }} service {{ include "keycloak.fullname" . }}-http --template='{{"{{ range .spec.ports }}{{ if eq .name \"http\" }}{{ .nodePort }}{{ end }}{{ end }}"}}')
export NODE_IP=$(kubectl get nodes --namespace {{ include "keycloak.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo "http://$NODE_IP:$NODE_PORT"
{{- end }}
{{ if .Values.service.httpsNodePort }}
Get its HTTPS URL with the following commands:
export NODE_PORT=$(kubectl get --namespace {{ include "keycloak.namespace" . }} service {{ include "keycloak.fullname" . }}-http --template='{{"{{ range .spec.ports }}{{ if eq .name \"https\" }}{{ .nodePort }}{{ end }}{{ end }}"}}')
export NODE_IP=$(kubectl get nodes --namespace {{ include "keycloak.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo "http://$NODE_IP:$NODE_PORT"
{{- end }}
{{- else if eq "LoadBalancer" .Values.service.type }}
Keycloak was installed with a Service of type LoadBalancer
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ include "keycloak.namespace" . }} service -w {{ include "keycloak.fullname" . }}'
Get its HTTP URL with the following commands:
export SERVICE_IP=$(kubectl get service --namespace {{ include "keycloak.namespace" . }} {{ include "keycloak.fullname" . }}-http --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo "http://$SERVICE_IP:{{ .Values.service.httpPort }}"
Get its HTTPS URL with the following commands:
export SERVICE_IP=$(kubectl get service --namespace {{ include "keycloak.namespace" . }} {{ include "keycloak.fullname" . }}-http --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo "http://$SERVICE_IP:{{ .Values.service.httpsPort }}"
{{- else if eq "ClusterIP" .Values.service.type }}
Keycloak was installed with a Service of type ClusterIP
Create a port-forwarding with the following commands:
export POD_NAME=$(kubectl get pods --namespace {{ include "keycloak.namespace" . }} -l "app.kubernetes.io/name={{ include "keycloak.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o name)
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ include "keycloak.namespace" . }} port-forward "$POD_NAME" 8080
{{- end }}
@@ -0,0 +1,94 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "keycloak.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "keycloak.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "keycloak.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "keycloak.labels" -}}
helm.sh/chart: {{ include "keycloak.chart" . }}
{{ include "keycloak.selectorLabels" . }}
app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | toString | trunc 63 | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "keycloak.selectorLabels" -}}
app.kubernetes.io/name: {{ include "keycloak.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "keycloak.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "keycloak.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
{{/*
Create the service DNS name.
*/}}
{{- define "keycloak.serviceDnsName" -}}
{{ include "keycloak.fullname" . }}-headless.{{ include "keycloak.namespace" . }}.svc.{{ .Values.clusterDomain }}
{{- end }}
{{/*
Namespace for all resources. Callers can override via .Values.namespaceOverride.
*/}}
{{- define "keycloak.namespace" -}}
{{- default .Release.Namespace .Values.namespaceOverride -}}
{{- end }}
{{- define "keycloak.databasePasswordEnv" -}}
{{- if or .Values.database.password .Values.database.existingSecret -}}
- name: KC_DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.database.existingSecret | default (printf "%s-database" (include "keycloak.fullname" . ))}}
key: {{ .Values.database.existingSecretKey | default "password" }}
{{- end }}
{{- end -}}
{{/*
Renders a complete tree, even values that contains template.
*/}}
{{- define "keycloak.render" -}}
{{- if typeIs "string" .value }}
{{- tpl .value .context }}
{{ else }}
{{- tpl (.value | toYaml) .context }}
{{- end }}
{{- end -}}
@@ -0,0 +1,14 @@
{{- if .Values.startupScripts }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "keycloak.fullname" . }}-startup
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.startupScripts }}
{{ $key }}: |
{{- tpl $value $ | nindent 4 }}
{{- end }}
{{- end -}}
@@ -0,0 +1,12 @@
{{- if and .Values.database.password (not .Values.database.existingSecret) -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "keycloak.fullname" $ }}-database
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" $ | nindent 4 }}
type: Opaque
stringData:
password: {{ .Values.database.password | quote }}
{{- end }}
@@ -0,0 +1,4 @@
{{- range .Values.extraManifests }}
---
{{ include "keycloak.render" (dict "value" . "context" $) }}
{{- end }}
@@ -0,0 +1,23 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := .Values.autoscaling.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: StatefulSet
name: {{ include "keycloak.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- toYaml .Values.autoscaling.metrics | nindent 4 }}
behavior:
{{- toYaml .Values.autoscaling.behavior | nindent 4 }}
{{- end }}
@@ -0,0 +1,99 @@
{{- $httpRoute := .Values.httpRoute -}}
{{- if $httpRoute.enabled -}}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := $httpRoute.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- with $httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- with $httpRoute.parentRefs }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with $httpRoute.hostnames }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range $httpRoute.rules }}
{{- with .matches }}
- matches:
{{- range . }}
{{- if .path }}
- path:
type: {{ .path.type }}
value: {{ tpl .path.value $ }}
{{- end }}
{{- else }}
{{ . | toYaml | nindent 8 }}
{{- end }}
{{- end }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ include "keycloak.fullname" $ }}-http
port: {{ $httpRoute.servicePort }}
{{- end }}
{{- end }}
---
{{- if $httpRoute.console.enabled }}
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: {{ include "keycloak.fullname" . }}-console
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := $httpRoute.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- range $key, $value := $httpRoute.console.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- with $httpRoute.console.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
{{- with pluck "parentRefs" $httpRoute.console $httpRoute | first }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with pluck "hostnames" $httpRoute.console $httpRoute | first }}
hostnames:
{{- toYaml . | nindent 4 }}
{{- end }}
rules:
{{- range $httpRoute.console.rules }}
{{- with .matches }}
- matches:
{{- range . }}
{{- if .path }}
- path:
type: {{ .path.type }}
value: {{ tpl .path.value $ }}
{{- end }}
{{- else }}
{{ . | toYaml | nindent 8 }}
{{- end }}
{{- end }}
{{- with .filters }}
filters:
{{- toYaml . | nindent 8 }}
{{- end }}
backendRefs:
- name: {{ include "keycloak.fullname" $ }}-http
port: {{ $httpRoute.servicePort }}
{{- end }}
{{- end }}
@@ -0,0 +1,116 @@
{{- $ingress := .Values.ingress -}}
{{- if $ingress.enabled -}}
{{- $apiVersion := "networking.k8s.io/v1" -}}
{{- $fullName := ( include "keycloak.fullname" . ) -}}
apiVersion: {{ $apiVersion }}
kind: Ingress
metadata:
name: {{ $fullName }}
namespace: {{ include "keycloak.namespace" . }}
{{- with $ingress.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := $ingress.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
{{- if $ingress.ingressClassName }}
ingressClassName: {{ $ingress.ingressClassName }}
{{- end }}
{{- if $ingress.tls }}
tls:
{{- range $ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ tpl . $ | quote }}
{{- end }}
{{- with .secretName }}
secretName: {{ tpl . $ }}
{{- end }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.rules }}
- host: {{ tpl .host $ | quote }}
http:
paths:
{{- range .paths }}
- path: {{ tpl .path $ | quote }}
pathType: {{ .pathType }}
backend:
service:
name: {{ default (printf "%s-http" $fullName) (.serviceName) }}
port:
name: {{ default ($ingress.servicePort) (.servicePort) }}
{{- end }}
{{- end }}
{{- if $ingress.console.enabled }}
---
apiVersion: {{ $apiVersion }}
kind: Ingress
metadata:
name: {{ $fullName }}-console
namespace: {{ include "keycloak.namespace" . }}
{{- with $ingress.console.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := $ingress.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- range $key, $value := $ingress.console.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
{{- if $ingress.console.ingressClassName }}
ingressClassName: {{ $ingress.console.ingressClassName }}
{{- end }}
{{- if $ingress.console.tls }}
tls:
{{- range $ingress.console.tls }}
- hosts:
{{- range .hosts }}
- {{ tpl . $ | quote }}
{{- end }}
{{- with .secretName }}
secretName: {{ tpl . $ }}
{{- end }}
{{- end }}
{{ else if $ingress.tls }}
tls:
{{- range $ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ tpl . $ | quote }}
{{- end }}
{{- with .secretName }}
secretName: {{ tpl . $ }}
{{- end }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.console.rules }}
- host: {{ tpl .host $ | quote }}
http:
paths:
{{- range .paths }}
- path: {{ tpl .path $ | quote }}
pathType: {{ .pathType }}
backend:
service:
name: {{ default (printf "%s-http" $fullName) (.serviceName) }}
port:
name: {{ default ($ingress.servicePort) (.servicePort) }}
{{- end }}
{{- end }}
{{- end -}}
{{- end -}}
@@ -0,0 +1,52 @@
{{- if .Values.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: {{ include "keycloak.fullname" . | quote }}
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := .Values.networkPolicy.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
policyTypes:
- Ingress
{{- if .Values.networkPolicy.egress }}
- Egress
{{- end}}
podSelector:
matchLabels:
{{- include "keycloak.selectorLabels" . | nindent 6 }}
ingress:
{{- with .Values.networkPolicy.extraFrom }}
- from:
{{- toYaml . | nindent 8 }}
ports:
- protocol: TCP
port: 8080
- protocol: TCP
port: 8443
{{ range $.Values.extraPorts }}
- protocol: {{ default "TCP" .protocol }}
port: {{ .containerPort }}
{{- end }}
{{- end }}
- from:
- podSelector:
matchLabels:
{{- include "keycloak.selectorLabels" . | nindent 14 }}
ports:
- protocol: TCP
port: 8080
- protocol: TCP
port: 8443
{{ range .Values.extraPorts }}
- protocol: {{ default "TCP" .protocol }}
port: {{ .containerPort }}
{{- end }}
{{- if .Values.networkPolicy.egress }}
egress:
{{- .Values.networkPolicy.egress | toYaml | nindent 4 }}
{{- end }}
{{- end }}
@@ -0,0 +1,14 @@
{{- if .Values.podDisruptionBudget -}}
apiVersion: {{ ternary "policy/v1" "policy/v1beta1" (semverCompare ">=1.21.0-0" .Capabilities.KubeVersion.Version) }}
kind: PodDisruptionBudget
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "keycloak.selectorLabels" . | nindent 6 }}
{{- toYaml .Values.podDisruptionBudget | nindent 2 }}
{{- end -}}
@@ -0,0 +1,29 @@
{{- with .Values.prometheusRule -}}
{{- if .enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: {{ include "keycloak.fullname" $ }}
{{- with .namespace }}
namespace: {{ . }}
{{- else }}
namespace: {{ include "keycloak.namespace" $ }}
{{- end }}
{{- with .annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" $ | nindent 4 }}
{{- range $key, $value := .labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
groups:
- name: {{ include "keycloak.fullname" $ }}
rules:
{{- toYaml .rules | nindent 8 }}
{{- end }}
{{- end -}}
@@ -0,0 +1,27 @@
{{- if and .Values.rbac.create .Values.rbac.rules }}
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
rules:
{{- toYaml .Values.rbac.rules | nindent 2 }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ include "keycloak.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ include "keycloak.serviceAccountName" . }}
namespace: {{ include "keycloak.namespace" . | quote }}
{{- end }}
@@ -0,0 +1,39 @@
{{- $route := .Values.route -}}
{{- if $route.enabled -}}
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
{{- with $route.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := $route.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
{{- if $route.host }}
host: {{ tpl $route.host $ | quote }}
{{- end }}
path: {{ $route.path }}
port:
{{- if or (not $route.tls.enabled) (eq $route.tls.termination "edge") }}
targetPort: http
{{- else}}
targetPort: https
{{- end}}
to:
kind: Service
name: {{ include "keycloak.fullname" $ }}-http
weight: 100
{{- if $route.tls.enabled }}
tls:
insecureEdgeTerminationPolicy: {{ $route.tls.insecureEdgeTerminationPolicy }}
termination: {{ $route.tls.termination }}
{{- end }}
{{- end -}}
@@ -0,0 +1,30 @@
{{- range $nameSuffix, $values := .Values.secrets }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "keycloak.fullname" $ }}-{{ $nameSuffix }}
namespace: {{ include "keycloak.namespace" $ }}
{{- with $values.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" $ | nindent 4 }}
{{- range $key, $value := $values.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
type: {{ default "Opaque" $values.type }}
{{- with $values.data }}
data:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with $values.stringData }}
stringData:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 2 }}
{{- end }}
{{- end }}
{{- end -}}
@@ -0,0 +1,30 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "keycloak.fullname" . }}-headless
namespace: {{ include "keycloak.namespace" . }}
{{- with .Values.serviceHeadless.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := .Values.serviceHeadless.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
app.kubernetes.io/component: headless
spec:
type: ClusterIP
clusterIP: None
ports:
- name: http
port: {{ .Values.service.httpPort }}
targetPort: http
protocol: TCP
{{- with .Values.serviceHeadless.extraPorts }}
{{- toYaml . | nindent 4 }}
{{- end }}
selector:
{{- include "keycloak.selectorLabels" . | nindent 4 }}
@@ -0,0 +1,65 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "keycloak.fullname" . }}-http
namespace: {{ include "keycloak.namespace" . }}
{{- with .Values.service.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := .Values.service.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
app.kubernetes.io/component: http
spec:
type: {{ .Values.service.type }}
{{- if and (eq "LoadBalancer" .Values.service.type) .Values.service.loadBalancerIP }}
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}
{{- if and (eq "LoadBalancer" .Values.service.type) .Values.service.loadBalancerSourceRanges }}
loadBalancerSourceRanges:
{{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
{{- end }}
{{- if or (eq "LoadBalancer" .Values.service.type) (eq "NodePort" .Values.service.type) }}
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
{{- end }}
{{- if .Values.service.internalTrafficPolicy }}
internalTrafficPolicy: {{ .Values.service.internalTrafficPolicy }}
{{- end }}
{{- if .Values.service.sessionAffinity }}
sessionAffinity: {{ .Values.service.sessionAffinity }}
{{- with .Values.service.sessionAffinityConfig }}
sessionAffinityConfig:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
ports:
- name: '{{ .Values.http.internalPort }}'
port: 9000
protocol: TCP
targetPort: '{{ .Values.http.internalPort }}'
- name: http
port: {{ .Values.service.httpPort }}
targetPort: http
{{- if and (or (eq "NodePort" .Values.service.type) (eq "LoadBalancer" .Values.service.type) ) .Values.service.httpNodePort }}
nodePort: {{ .Values.service.httpNodePort }}
{{- end }}
protocol: TCP
{{- if .Values.service.httpsPort }}
- name: https
port: {{ .Values.service.httpsPort }}
targetPort: https
{{- if and (or (eq "NodePort" .Values.service.type) (eq "LoadBalancer" .Values.service.type) ) .Values.service.httpsNodePort }}
nodePort: {{ .Values.service.httpsNodePort }}
{{- end }}
protocol: TCP
{{- end }}
{{- with .Values.service.extraPorts }}
{{- toYaml . | nindent 4 }}
{{- end }}
selector:
{{- include "keycloak.selectorLabels" . | nindent 4 }}
@@ -0,0 +1,47 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "keycloak.serviceAccountName" . }}
namespace: {{ include "keycloak.namespace" . }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := .Values.serviceAccount.labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- with .Values.serviceAccount.imagePullSecrets }}
imagePullSecrets: {{ toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- if .Values.serviceAccount.allowReadPods }}
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jgroups-kubeping-pod-reader-{{ include "keycloak.namespace" . }}
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: jgroups-kubeping-api-access-{{ include "keycloak.namespace" . }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: jgroups-kubeping-pod-reader-{{ include "keycloak.namespace" . }}
subjects:
- kind: ServiceAccount
name: {{ include "keycloak.serviceAccountName" . }}
namespace: {{ include "keycloak.namespace" . }}
{{- end }}
{{- end }}
@@ -0,0 +1,54 @@
{{- range $key, $serviceMonitor := dict "keycloakx" .Values.serviceMonitor "extra" .Values.extraServiceMonitor }}
{{- with $serviceMonitor }}
{{- if .enabled }}
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "keycloak.fullname" $ }}-{{ $key }}
{{- with .namespace }}
namespace: {{ . }}
{{- else }}
namespace: {{ include "keycloak.namespace" $ }}
{{- end }}
{{- with .annotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" $ | nindent 4 }}
{{- range $key, $value := .labels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
{{- with .namespaceSelector }}
namespaceSelector:
{{- toYaml . | nindent 4 }}
{{- end }}
selector:
matchLabels:
{{- include "keycloak.selectorLabels" $ | nindent 6 }}
app.kubernetes.io/component: http
endpoints:
- port: {{ tpl .port $ | quote }}
path: {{ tpl .path $ | quote }}
scheme: {{ coalesce .scheme $.Values.http.internalScheme | lower }}
interval: {{ .interval }}
scrapeTimeout: {{ .scrapeTimeout }}
{{- with .relabelings }}
relabelings:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .metricRelabelings }}
metricRelabelings:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .tlsConfig }}
tlsConfig:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
@@ -0,0 +1,242 @@
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ include "keycloak.fullname" . }}
namespace: {{ include "keycloak.namespace" . }}
{{- with .Values.statefulsetAnnotations }}
annotations:
{{- range $key, $value := . }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
{{- end }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
{{- range $key, $value := .Values.statefulsetLabels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
{{- include "keycloak.selectorLabels" . | nindent 6 }}
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicas }}
{{- end }}
serviceName: {{ include "keycloak.fullname" . }}-headless
podManagementPolicy: {{ .Values.podManagementPolicy }}
updateStrategy:
type: {{ .Values.updateStrategy }}
{{- if not (eq (.Values.revisionHistoryLimit | toString) "") }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
{{- end }}
template:
metadata:
annotations:
checksum/config-startup: {{ include (print .Template.BasePath "/configmap-startup.yaml") . | sha256sum }}
checksum/secrets: {{ tpl (toYaml .Values.secrets) . | sha256sum }}
{{- range $key, $value := .Values.podAnnotations }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 8 }}
{{- end }}
labels:
{{- include "keycloak.selectorLabels" . | nindent 8 }}
{{- range $key, $value := .Values.podLabels }}
{{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 8 }}
{{- end }}
spec:
{{- if not .Values.skipInitContainers }}
{{- if or .Values.dbchecker.enabled .Values.extraInitContainers }}
initContainers:
{{- if and .Values.dbchecker.enabled }}
- name: dbchecker
image: "{{ .Values.dbchecker.image.repository }}{{- if (.Values.dbchecker.image.digest) -}}@{{ .Values.dbchecker.image.digest }}{{- else -}}:{{ .Values.dbchecker.image.tag }} {{- end }}"
imagePullPolicy: {{ .Values.dbchecker.image.pullPolicy }}
securityContext:
{{- toYaml .Values.dbchecker.securityContext | nindent 12 }}
command:
- sh
- -c
- |
echo 'Waiting for Database to become ready...'
until printf "." && nc -z -w 2 {{ required ".Values.database.hostname is required if dbchecker is enabled!" .Values.database.hostname }} {{ required ".Values.database.port is required if dbchecker is enabled!" .Values.database.port }}; do
sleep 2;
done;
echo 'Database OK ✓'
resources:
{{- toYaml .Values.dbchecker.resources | nindent 12 }}
{{- end }}
{{- with .Values.extraInitContainers }}
{{- tpl . $ | nindent 8 }}
{{- end }}
{{- end }}
{{- end }}
containers:
- name: keycloak
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}{{- if (.Values.image.digest) -}}@{{ .Values.image.digest }}{{- else -}}:{{ .Values.image.tag | default .Chart.AppVersion }} {{- end }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
{{- if .Values.command }}
command:
{{- toYaml .Values.command | nindent 12 }}
{{- end }}
{{- if .Values.args }}
args:
{{- toYaml .Values.args | nindent 12 }}
{{- end }}
{{- with .Values.lifecycleHooks }}
lifecycle:
{{- tpl . $ | nindent 12 }}
{{- end }}
env:
{{- if and (.Values.http.relativePath) (eq .Values.http.relativePath "/") }}
- name: KC_HTTP_RELATIVE_PATH
value: {{ tpl .Values.http.relativePath $ }}
{{ else }}
- name: KC_HTTP_RELATIVE_PATH
value: {{ tpl .Values.http.relativePath $ | trimSuffix "/" }}
{{- end }}
{{- if eq .Values.cache.stack "default" }}
- name: KC_CACHE
value: "ispn"
- name: KC_CACHE_STACK
value: "jdbc-ping"
{{- end }}
{{- if .Values.proxy.enabled }}
- name: KC_PROXY_HEADERS
value: {{ .Values.proxy.mode }}
{{- end }}
{{- if .Values.proxy.http.enabled }}
- name: KC_HTTP_ENABLED
value: "true"
{{- end }}
{{- if .Values.database.vendor }}
- name: KC_DB
value: {{ .Values.database.vendor }}
{{- end }}
{{- if .Values.database.hostname }}
- name: KC_DB_URL_HOST
value: {{ .Values.database.hostname }}
{{- end }}
{{- if .Values.database.port }}
- name: KC_DB_URL_PORT
value: {{ .Values.database.port | quote }}
{{- end }}
{{- if .Values.database.database }}
- name: KC_DB_URL_DATABASE
value: {{ .Values.database.database }}
{{- end }}
{{- if .Values.database.username }}
- name: KC_DB_USERNAME
value: {{ .Values.database.username }}
{{- end }}
{{- if or .Values.database.password .Values.database.existingSecret -}}
{{- include "keycloak.databasePasswordEnv" . | nindent 12 }}
{{- end }}
{{- if .Values.metrics.enabled }}
- name: KC_METRICS_ENABLED
value: "true"
{{- end }}
{{- if .Values.health.enabled }}
- name: KC_HEALTH_ENABLED
value: "true"
{{- end }}
{{- with .Values.extraEnv }}
{{- tpl . $ | nindent 12 }}
{{- end }}
envFrom:
{{- with .Values.extraEnvFrom }}
{{- tpl . $ | nindent 12 }}
{{- end }}
ports:
- name: http
containerPort: 8080
protocol: TCP
- name: '{{ .Values.http.internalPort }}'
containerPort: 9000
protocol: TCP
{{- if .Values.service.httpsPort }}
- name: https
containerPort: 8443
protocol: TCP
{{- end }}
{{- with .Values.extraPorts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- if .Values.health.enabled }}
{{- with .Values.livenessProbe }}
livenessProbe:
{{- tpl . $ | nindent 12 }}
{{- end }}
{{- if .Values.metrics.enabled }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- tpl . $ | nindent 12 }}
{{- end }}
{{- end}}
{{- with .Values.startupProbe }}
startupProbe:
{{- tpl . $ | nindent 12 }}
{{- end }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
{{- with .Values.extraVolumeMounts }}
{{- tpl . $ | nindent 12 }}
{{- end }}
{{- with .Values.extraContainers }}
{{- tpl . $ | nindent 8 }}
{{- end }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "keycloak.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
{{- with .Values.hostAliases }}
hostAliases:
{{- toYaml . | nindent 8 }}
{{- end }}
enableServiceLinks: {{ .Values.enableServiceLinks }}
restartPolicy: {{ .Values.restartPolicy }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- tpl . $ | nindent 8 }}
{{- end }}
{{- with .Values.topologySpreadConstraints }}
topologySpreadConstraints:
{{- tpl . $ | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.priorityClassName }}
priorityClassName: {{ . }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
volumes:
{{- with .Values.startupScripts }}
- name: startup
configMap:
name: {{ include "keycloak.fullname" $ }}-startup
defaultMode: 0555
items:
{{- range $key, $value := . }}
- key: {{ $key }}
path: {{ $key }}
{{- end }}
{{- end }}
{{- with .Values.extraVolumes }}
{{- tpl . $ | nindent 8 }}
{{- end }}
{{- with .Values.volumeClaimTemplates }}
volumeClaimTemplates:
{{- tpl . $ | nindent 4 }}
{{- end }}
@@ -0,0 +1,67 @@
{{- if .Values.test.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "keycloak.fullname" . }}-test
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
annotations:
helm.sh/hook: test
helm.sh/hook-delete-policy: hook-succeeded
data:
test.sh: |
#!/usr/bin/env bash
set -eu
if ! python3 -c 'import selenium' &> /dev/null; then
echo 'Installing selenium module...'
python3 -m venv /tmp/test-venv
/tmp/test-venv/bin/pip install -q selenium
exec /tmp/test-venv/bin/python "$(dirname "$0")/test.py"
fi
python3 "$(dirname "$0")/test.py"
test.py: |
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support import expected_conditions
print('Creating chrome driver in headless mode')
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(options=chrome_options)
base_url = 'http://{{ include "keycloak.fullname" . }}-http{{ if ne 80 (int .Values.service.httpPort) }}:{{ .Values.service.httpPort }}{{ end }}'
print('Opening Keycloak...')
driver.get('{0}{{ tpl .Values.http.relativePath . | trimSuffix "/" }}/admin/'.format(base_url))
username = os.environ['KEYCLOAK_USER']
password = os.environ['KEYCLOAK_PASSWORD']
username_input = WebDriverWait(driver, 30).until(expected_conditions.presence_of_element_located((By.ID, "username")))
password_input = WebDriverWait(driver, 30).until(expected_conditions.presence_of_element_located((By.ID, "password")))
login_button = WebDriverWait(driver, 30).until(expected_conditions.presence_of_element_located((By.ID, "kc-login")))
print('Entering username...')
username_input.send_keys(username)
print('Entering password...')
password_input.send_keys(password)
print('Clicking login button...')
login_button.click()
WebDriverWait(driver, 30).until(lambda driver: '{{ tpl .Values.http.relativePath . | trimSuffix "/" }}/admin/master/console/' in driver.current_url)
print('Admin console visible. Login successful.')
driver.quit()
{{- end }}
@@ -0,0 +1,45 @@
{{- if .Values.test.enabled }}
apiVersion: v1
kind: Pod
metadata:
name: {{ include "keycloak.fullname" . }}-test
namespace: {{ include "keycloak.namespace" . }}
labels:
{{- include "keycloak.labels" . | nindent 4 }}
app.kubernetes.io/component: test
annotations:
helm.sh/hook: test
helm.sh/hook-delete-policy: {{ .Values.test.deletionPolicy }}
spec:
securityContext:
{{- toYaml .Values.test.podSecurityContext | nindent 4 }}
containers:
- name: keycloak-test
image: "{{ .Values.test.image.repository }}{{- if (.Values.test.image.digest) -}}@{{ .Values.test.image.digest }}{{- else -}}:{{ .Values.test.image.tag }} {{- end }}"
imagePullPolicy: {{ .Values.test.image.pullPolicy }}
securityContext:
{{- toYaml .Values.test.securityContext | nindent 8 }}
command:
- bash
args:
- /tests/test.sh
env:
- name: KEYCLOAK_USER
valueFrom:
secretKeyRef:
name: {{ include "keycloak.fullname" . }}-admin-creds
key: user
- name: KEYCLOAK_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "keycloak.fullname" . }}-admin-creds
key: password
volumeMounts:
- name: tests
mountPath: /tests
volumes:
- name: tests
configMap:
name: {{ include "keycloak.fullname" . }}-test
restartPolicy: Never
{{- end }}