[PLATFORM] Add Keycloak to ONAP 78/130178/17
authorAndreas Geissler <andreas-geissler@telekom.de>
Thu, 4 Aug 2022 13:18:56 +0000 (15:18 +0200)
committerAndreas Geissler <andreas-geissler@telekom.de>
Wed, 28 Sep 2022 11:58:16 +0000 (13:58 +0200)
As part of the ServiceMesh solution Keycloak will be used
to enable a central authentication and authorization for ONAP
Service Access.
This patch delivers this based on codecentric helmcharts:
https://github.com/codecentric/helm-charts/tree/master/charts/keycloakx
and will contain predefined theme and realms

Issue-ID: OOM-2486

Signed-off-by: Andreas Geissler <andreas-geissler@telekom.de>
Change-Id: Id333b1ef709af0dca4d3e96d16b7e88c938f9111

28 files changed:
kubernetes/common/repositoryGenerator/templates/_repository.tpl
kubernetes/onap/values.yaml
kubernetes/platform/Chart.yaml
kubernetes/platform/components/keycloak/.bumpversion.cfg [new file with mode: 0644]
kubernetes/platform/components/keycloak/.helmignore [new file with mode: 0644]
kubernetes/platform/components/keycloak/Chart.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/OWNERS [new file with mode: 0644]
kubernetes/platform/components/keycloak/README.md [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/NOTES.txt [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/_helpers.tpl [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/configmap-startup.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/hpa.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/ingress.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/networkpolicy.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/poddisruptionbudget.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/prometheusrule.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/rbac.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/route.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/secrets.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/service-headless.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/service-http.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/serviceaccount.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/servicemonitor.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/statefulset.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/test/configmap-test.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/templates/test/pod-test.yaml [new file with mode: 0644]
kubernetes/platform/components/keycloak/values.schema.json [new file with mode: 0644]
kubernetes/platform/components/keycloak/values.yaml [new file with mode: 0644]

index 1b99285..206a1e6 100644 (file)
   {{- include "repositoryGenerator._repositoryHelper" (merge (dict "repoName" "dockerHubRepository") .) }}
 {{- end -}}
 
+{{/*
+  Resolve the name of the Quay.io image repository.
+
+  - .Values.global.quayRepository  : default image quayRepository for all quay.io images
+  - .Values.quayRepositoryOverride : override global quay.io repository on a per chart basis
+*/}}
+{{- define "repositoryGenerator.quayRepository" -}}
+  {{- include "repositoryGenerator._repositoryHelper" (merge (dict "repoName" "quayRepository") .) }}
+{{- end -}}
+
 {{/*
   Resolve the name of the elasticRepository image repository.
 
index 6939a87..9baebc9 100755 (executable)
@@ -48,6 +48,7 @@ global:
   elasticRepository: &elasticRepository docker.elastic.co
   googleK8sRepository: k8s.gcr.io
   githubContainerRegistry: ghcr.io
+  quayRepository: quay.io
 
   #/!\ DEPRECATED /!\
   # Legacy repositories which will be removed at the end of migration.
index 559e5fe..c9ba215 100644 (file)
@@ -31,3 +31,6 @@ dependencies:
   - name: chartmuseum
     version: ~11.x-0
     repository: 'file://components/chartmuseum'
+  - name: keycloak
+    version: ~11.x-0
+    repository: 'file://components/keycloak'
diff --git a/kubernetes/platform/components/keycloak/.bumpversion.cfg b/kubernetes/platform/components/keycloak/.bumpversion.cfg
new file mode 100644 (file)
index 0000000..d680c8b
--- /dev/null
@@ -0,0 +1,7 @@
+[bumpversion]
+current_version = 1.6.0
+commit = true
+tag = false
+message = Bump keycloakx chart version: {current_version} → {new_version}
+
+[bumpversion:file:Chart.yaml]
diff --git a/kubernetes/platform/components/keycloak/.helmignore b/kubernetes/platform/components/keycloak/.helmignore
new file mode 100644 (file)
index 0000000..cf02291
--- /dev/null
@@ -0,0 +1,25 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+ci/
+examples/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/kubernetes/platform/components/keycloak/Chart.yaml b/kubernetes/platform/components/keycloak/Chart.yaml
new file mode 100644 (file)
index 0000000..f9d9430
--- /dev/null
@@ -0,0 +1,65 @@
+#============LICENSE_START========================================================
+# ================================================================================
+# Copyright (c) 2022 Codecentric. All rights reserved.
+# Modifications Copyright © 2022 Deutsche Telekom
+# ================================================================================
+# Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+apiVersion: v2
+appVersion: 18.0.0
+version: 11.0.0
+description: Keycloak.X - Open Source Identity and Access Management for Modern Applications and Services
+home: https://www.keycloak.org/
+icon: https://www.keycloak.org/resources/images/keycloak_logo_200px.svg
+keywords:
+- sso
+- idm
+- openid connect
+- saml
+- kerberos
+- oauth
+- ldap
+- keycloakx
+- quarkus
+maintainers:
+- email: thomas.darimont+github@gmail.com
+  name: thomasdarimont
+name: keycloak
+sources:
+- https://github.com/codecentric/helm-charts
+- https://github.com/keycloak/keycloak/tree/main/quarkus/container
+
+# Keycloakx chart version: 1.6.0
+dependencies:
+  - name: common
+    version: ~11.x-0
+    repository: '@local'
+  - name: repositoryGenerator
+    version: ~11.x-0
+    repository: '@local'
+  - name: readinessCheck
+    version: ~11.x-0
+    repository: '@local'
+  - name: postgres
+    version: ~11.x-0
+    repository: '@local'
+    condition: global.postgres.localCluster
+  - name: postgres-init
+    version: ~11.x-0
+    repository: '@local'
+    condition: postgres.postgresInit
+  - name: serviceAccount
+    version: ~11.x-0
+    repository: '@local'
+
diff --git a/kubernetes/platform/components/keycloak/OWNERS b/kubernetes/platform/components/keycloak/OWNERS
new file mode 100644 (file)
index 0000000..57454a3
--- /dev/null
@@ -0,0 +1,4 @@
+approvers:
+  - thomasdarimont
+reviewers:
+  - thomasdarimont
\ No newline at end of file
diff --git a/kubernetes/platform/components/keycloak/README.md b/kubernetes/platform/components/keycloak/README.md
new file mode 100644 (file)
index 0000000..e36ea85
--- /dev/null
@@ -0,0 +1,572 @@
+# Keycloak-X
+
+[Keycloak-X](http://www.keycloak.org/) is an open source identity and access management for modern applications and services.
+
+Note that this chart is the logical successor of the Wildfly based [codecentric/keycloak](https://github.com/codecentric/helm-charts/tree/master/charts/keycloak) chart.
+
+## TL;DR;
+
+```console
+$ cat << EOF > values.yaml
+command:
+  - "/opt/keycloak/bin/kc.sh"
+  - "start"
+  - "--auto-build"
+  - "--http-enabled=true"
+  - "--http-port=8080"
+  - "--hostname-strict=false"
+  - "--hostname-strict-https=false"
+extraEnv: |
+  - name: KEYCLOAK_ADMIN
+    value: admin
+  - name: KEYCLOAK_ADMIN_PASSWORD
+    value: admin
+  - name: JAVA_OPTS_APPEND
+    value: >-
+      -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless
+EOF
+
+$ helm install keycloak codecentric/keycloakx --values ./values.yaml
+```
+Note that the default configuration is not suitable for production since it uses a h2 file database by default.
+It is strongly recommended to use a dedicated database with Keycloak.
+
+For more examples see the [examples](./examples) folder.
+
+## Introduction
+
+This chart bootstraps a [Keycloak](http://www.keycloak.org/) StatefulSet on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
+It provisions a fully featured Keycloak installation.
+For more information on Keycloak and its capabilities, see its [documentation](http://www.keycloak.org/documentation.html).
+
+## Installing the Chart
+
+To install the chart with the release name `keycloakx`:
+
+```console
+$ helm install keycloak codecentric/keycloakx
+```
+
+## Uninstalling the Chart
+
+To uninstall the `keycloakx` deployment:
+
+```console
+$ helm uninstall keycloakx
+```
+
+## Configuration
+
+The following table lists the configurable parameters of the Keycloak-X chart and their default values.
+
+| Parameter                                    | Description                                                                                                                                                                                                                                                                       | Default                                                                                                                               |
+|----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
+| `fullnameOverride`                           | Optionally override the fully qualified name                                                                                                                                                                                                                                      | `""`                                                                                                                                  |
+| `nameOverride`                               | Optionally override the name                                                                                                                                                                                                                                                      | `""`                                                                                                                                  |
+| `replicas`                                   | The number of replicas to create                                                                                                                                                                                                                                                  | `1`                                                                                                                                   |
+| `image.repository`                           | The Keycloak image repository                                                                                                                                                                                                                                                     | `quay.io/keycloak/keycloak`                                                                                                           |
+| `image.tag`                                  | Overrides the Keycloak image tag whose default is the chart version                                                                                                                                                                                                               | `""`                                                                                                                                  |
+| `image.pullPolicy`                           | The Keycloak image pull policy                                                                                                                                                                                                                                                    | `IfNotPresent`                                                                                                                        |
+| `imagePullSecrets`                           | Image pull secrets for the Pod                                                                                                                                                                                                                                                    | `[]`                                                                                                                                  |
+| `hostAliases`                                | Mapping between IPs and hostnames that will be injected as entries in the Pod's hosts files                                                                                                                                                                                       | `[]`                                                                                                                                  |
+| `enableServiceLinks`                         | Indicates whether information about services should be injected into Pod's environment variables, matching the syntax of Docker links                                                                                                                                             | `true`                                                                                                                                |
+| `podManagementPolicy`                        | Pod management policy. One of `Parallel` or `OrderedReady`                                                                                                                                                                                                                        | `Parallel`                                                                                                                            |
+| `restartPolicy`                              | Pod restart policy. One of `Always`, `OnFailure`, or `Never`                                                                                                                                                                                                                      | `Always`                                                                                                                              |
+| `serviceAccount.create`                      | Specifies whether a ServiceAccount should be created                                                                                                                                                                                                                              | `true`                                                                                                                                |
+| `serviceAccount.allowReadPods`               | Specifies whether the ServiceAccount can get or list pods                                                                                                                                                                                                                         | `false`                                                                                                                               |
+| `serviceAccount.name`                        | The name of the service account to use. If not set and create is true, a name is generated using the fullname template                                                                                                                                                            | `""`                                                                                                                                  |
+| `serviceAccount.annotations`                 | Additional annotations for the ServiceAccount                                                                                                                                                                                                                                     | `{}`                                                                                                                                  |
+| `serviceAccount.labels`                      | Additional labels for the ServiceAccount                                                                                                                                                                                                                                          | `{}`                                                                                                                                  |
+| `serviceAccount.imagePullSecrets`            | Image pull secrets that are attached to the ServiceAccount                                                                                                                                                                                                                        | `[]`                                                                                                                                  |
+| `serviceAccount.automountServiceAccountToken`            | Automount API credentials for the Service Account                                                                                                                                                                                                                        | `true`                                                                                                                                  |
+| `rbac.create`                                | Specifies whether RBAC resources are to be created                                                                                                                                                                                                                                | `false`
+| `rbac.rules`                                 | Custom RBAC rules, e. g. for KUBE_PING                                                                                                                                                                                                                                            | `[]`
+| `podSecurityContext`                         | SecurityContext for the entire Pod. Every container running in the Pod will inherit this SecurityContext. This might be relevant when other components of the environment inject additional containers into running Pods (service meshes are the most prominent example for this) | `{"fsGroup":1000}`                                                                                                                    |
+| `securityContext`                            | SecurityContext for the Keycloak container                                                                                                                                                                                                                                        | `{"runAsNonRoot":true,"runAsUser":1000}`                                                                                              |
+| `extraInitContainers`                        | Additional init containers, e. g. for providing custom themes                                                                                                                                                                                                                     | `[]`                                                                                                                                  |
+| `skipInitContainers`                         | Skip all init containers (to avoid issues with service meshes which require sidecar proxies for connectivity)                                                                                                                                                                     | `false`
+| `extraContainers`                            | Additional sidecar containers, e. g. for a database proxy, such as Google's cloudsql-proxy                                                                                                                                                                                        | `[]`                                                                                                                                  |
+| `lifecycleHooks`                             | Lifecycle hooks for the Keycloak container                                                                                                                                                                                                                                        | `{}`                                                                                                                                  |
+| `terminationGracePeriodSeconds`              | Termination grace period in seconds for Keycloak shutdown. Clusters with a large cache might need to extend this to give Infinispan more time to rebalance                                                                                                                        | `60`                                                                                                                                  |
+| `clusterDomain`                              | The internal Kubernetes cluster domain                                                                                                                                                                                                                                            | `cluster.local`                                                                                                                       |
+| `command`                                    | Overrides the default entrypoint of the Keycloak container                                                                                                                                                                                                                        | `[]`                                                                                                                                  |
+| `args`                                       | Overrides the default args for the Keycloak container                                                                                                                                                                                                                             | `[]`                                                                                                                                  |
+| `extraEnv`                                   | Additional environment variables for Keycloak                                                                                                                                                                                                                                     | `""`                                                                                                                                  |
+| `extraEnvFrom`                               | Additional environment variables for Keycloak mapped from a Secret or ConfigMap                                                                                                                                                                                                   | `""`                                                                                                                                  |
+| `priorityClassName`                          | Pod priority class name                                                                                                                                                                                                                                                           | `""`                                                                                                                                  |
+| `affinity`                                   | Pod affinity                                                                                                                                                                                                                                                                      | Hard node and soft zone anti-affinity                                                                                                 |
+| `topologySpreadConstraints`                  | Topology spread constraints                                                                                                                                                                                                                                                       | Constraints used to spread pods                                                                                                       |
+| `nodeSelector`                               | Node labels for Pod assignment                                                                                                                                                                                                                                                    | `{}`                                                                                                                                  |
+| `tolerations`                                | Node taints to tolerate                                                                                                                                                                                                                                                           | `[]`                                                                                                                                  |
+| `podLabels`                                  | Additional Pod labels                                                                                                                                                                                                                                                             | `{}`                                                                                                                                  |
+| `podAnnotations`                             | Additional Pod annotations                                                                                                                                                                                                                                                        | `{}`                                                                                                                                  |
+| `livenessProbe`                              | Liveness probe configuration                                                                                                                                                                                                                                                      | `{"httpGet":{"path":"{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/","port":"http"},"initialDelaySeconds":0,"timeoutSeconds":5}`                                              |
+| `readinessProbe`                             | Readiness probe configuration                                                                                                                                                                                                                                                     | `{"httpGet":{"path":"{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/realms/master","port":"http"},"initialDelaySeconds":30,"timeoutSeconds":1}`                                |
+| `startupProbe`                               | Startup probe configuration                                                                                                                                                                                                                                                       | `{"httpGet":{"path":"{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/","port":"http"},"initialDelaySeconds":30,"timeoutSeconds":5, "failureThreshold": 60, "periodSeconds": 5}` |
+| `resources`                                  | Pod resource requests and limits                                                                                                                                                                                                                                                  | `{}`                                                                                                                                  |
+| `extraVolumes`                               | Add additional volumes, e. g. for custom themes                                                                                                                                                                                                                                   | `""`                                                                                                                                  |
+| `extraVolumeMounts`                          | Add additional volumes mounts, e. g. for custom themes                                                                                                                                                                                                                            | `""`                                                                                                                                  |
+| `extraPorts`                                 | Add additional ports, e. g. for admin console or exposing JGroups ports                                                                                                                                                                                                           | `[]`                                                                                                                                  |
+| `podDisruptionBudget`                        | Pod disruption budget                                                                                                                                                                                                                                                             | `{}`                                                                                                                                  |
+| `statefulsetAnnotations`                     | Annotations for the StatefulSet                                                                                                                                                                                                                                                   | `{}`                                                                                                                                  |
+| `statefulsetLabels`                          | Additional labels for the StatefulSet                                                                                                                                                                                                                                             | `{}`                                                                                                                                  |
+| `secrets`                                    | Configuration for secrets that should be created                                                                                                                                                                                                                                  | `{}`                                                                                                                                  |
+| `service.annotations`                        | Annotations for headless and HTTP Services                                                                                                                                                                                                                                        | `{}`                                                                                                                                  |
+| `service.labels`                             | Additional labels for headless and HTTP Services                                                                                                                                                                                                                                  | `{}`                                                                                                                                  |
+| `service.type`                               | The Service type                                                                                                                                                                                                                                                                  | `ClusterIP`                                                                                                                           |
+| `service.loadBalancerIP`                     | Optional IP for the load balancer. Used for services of type LoadBalancer only                                                                                                                                                                                                    | `""`                                                                                                                                  |
+| `loadBalancerSourceRanges`                   | Optional List of allowed source ranges (CIDRs). Used for service of type LoadBalancer only                                                                                                                                                                                        | `[]`                                                                                                                                  |
+| `service.externalTrafficPolicy`              | Optional external traffic policy. Used for services of type LoadBalancer only                                                                                                                                                                                                     | `"Cluster"`                                                                                                                           |
+| `service.httpPort`                           | The http Service port                                                                                                                                                                                                                                                             | `80`                                                                                                                                  |
+| `service.httpNodePort`                       | The HTTP Service node port if type is NodePort                                                                                                                                                                                                                                    | `""`                                                                                                                                  |
+| `service.httpsPort`                          | The HTTPS Service port                                                                                                                                                                                                                                                            | `8443`                                                                                                                                |
+| `service.httpsNodePort`                      | The HTTPS Service node port if type is NodePort                                                                                                                                                                                                                                   | `""`                                                                                                                                  |
+| `service.extraPorts`                         | Additional Service ports, e. g. for custom admin console                                                                                                                                                                                                                          | `[]`                                                                                                                                  |
+| `service.sessionAffinity`                    | sessionAffinity for Service, e. g. "ClientIP"                                                                                                                                                                                                                                     | `""`                                                                                                                                  |
+| `service.sessionAffinityConfig`              | sessionAffinityConfig for Service                                                                                                                                                                                                                                                 | `{}`                                                                                                                                  |
+| `ingress.enabled`                            | If `true`, an Ingress is created                                                                                                                                                                                                                                                  | `false`                                                                                                                               |
+| `ingress.rules`                              | List of Ingress Ingress rule                                                                                                                                                                                                                                                      | see below                                                                                                                             |
+| `ingress.rules[0].host`                      | Host for the Ingress rule                                                                                                                                                                                                                                                         | `{{ .Release.Name }}.keycloak.example.com`                                                                                            |
+| `ingress.rules[0].paths`                     | Paths for the Ingress rule                                                                                                                                                                                                                                                        | see below                                                                                                                             |
+| `ingress.rules[0].paths[0].path`             | Path for the Ingress rule                                                                                                                                                                                                                                                         | `/`                                                                                                                                   |
+| `ingress.rules[0].paths[0].pathType`         | Path Type for the Ingress rule                                                                                                                                                                                                                                                    | `Prefix`                                                                                                                              |
+| `ingress.servicePort`                        | The Service port targeted by the Ingress                                                                                                                                                                                                                                          | `http`                                                                                                                                |
+| `ingress.annotations`                        | Ingress annotations                                                                                                                                                                                                                                                               | `{}`                                                                                                                                  |
+| `ingress.ingressClassName`                   | The name of the Ingress Class associated with the ingress                                                                                                                                                                                                                         | `""`                                                                                                                                  |
+| `ingress.labels`                             | Additional Ingress labels                                                                                                                                                                                                                                                         | `{}`                                                                                                                                  |
+| `ingress.tls`                                | TLS configuration                                                                                                                                                                                                                                                                 | see below                                                                                                                             |
+| `ingress.tls[0].hosts`                       | List of TLS hosts                                                                                                                                                                                                                                                                 | `[keycloak.example.com]`                                                                                                              |
+| `ingress.tls[0].secretName`                  | Name of the TLS secret                                                                                                                                                                                                                                                            | `""`                                                                                                                                  |
+| `ingress.console.enabled`                    | If `true`, an Ingress for the console is created                                                                                                                                                                                                                                  | `false`                                                                                                                               |
+| `ingress.console.rules`                      | List of Ingress Ingress rule for the console                                                                                                                                                                                                                                      | see below                                                                                                                             |
+| `ingress.console.rules[0].host`              | Host for the Ingress rule for the console                                                                                                                                                                                                                                         | `{{ .Release.Name }}.keycloak.example.com`                                                                                            |
+| `ingress.console.rules[0].paths`             | Paths for the Ingress rule for the console                                                                                                                                                                                                                                        | see below                                                                                                                             |
+| `ingress.console.rules[0].paths[0].path`     | Path for the Ingress rule for the console                                                                                                                                                                                                                                         | `[{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/admin]`                                                                                                                       |
+| `ingress.console.rules[0].paths[0].pathType` | Path Type for the Ingress rule for the console                                                                                                                                                                                                                                    | `Prefix`                                                                                                                              |
+| `ingress.console.annotations`                | Ingress annotations for the console                                                                                                                                                                                                                                               | `{}`                                                                                                                                  |
+| `ingress.console.ingressClassName`           | The name of the Ingress Class associated with the console ingress                                                                                                                                                                                                                 | `""`                                                                                                                                  |
+| `ingress.console.tls` | TLS configuration                                                                                                                                                                                                                                                                 | see below                                                                                                                             |
+| `ingress.console.tls[0].hosts` | List of TLS hosts                                                                                                                                                                                                                                                                 | `[keycloak.example.com]`                                                                                                              |
+| `ingress.console.tls[0].secretName` | Name of the TLS secret                                                                                                                                                                                                                                                            | `""`                                                                                                                                  |
+| `networkPolicy.enabled`                      | If true, the ingress network policy is deployed                                                                                                                                                                                                                                   | `false`
+| `networkPolicy.extraFrom`                    | Allows to define allowed external traffic (see Kubernetes doc for network policy `from` format)                                                                                                                                                                                   | `[]`
+| `route.enabled`                              | If `true`, an OpenShift Route is created                                                                                                                                                                                                                                          | `false`                                                                                                                               |
+| `route.path`                                 | Path for the Route                                                                                                                                                                                                                                                                | `/`                                                                                                                                   |
+| `route.annotations`                          | Route annotations                                                                                                                                                                                                                                                                 | `{}`                                                                                                                                  |
+| `route.labels`                               | Additional Route labels                                                                                                                                                                                                                                                           | `{}`                                                                                                                                  |
+| `route.host`                                 | Host name for the Route                                                                                                                                                                                                                                                           | `""`                                                                                                                                  |
+| `route.tls.enabled`                          | If `true`, TLS is enabled for the Route                                                                                                                                                                                                                                           | `true`                                                                                                                                |
+| `route.tls.insecureEdgeTerminationPolicy`    | Insecure edge termination policy of the Route. Can be `None`, `Redirect`, or `Allow`                                                                                                                                                                                              | `Redirect`                                                                                                                            |
+| `route.tls.termination`                      | TLS termination of the route. Can be `edge`, `passthrough`, or `reencrypt`                                                                                                                                                                                                        | `edge`                                                                                                                                |
+| `dbchecker.image.repository`                 | Docker image used to check database readiness at startup                                                                                                                                                                                                                          | `docker.io/busybox`                                                                                                                   |
+| `dbchecker.image.tag`                        | Image tag for the dbchecker image                                                                                                                                                                                                                                                 | `1.32`                                                                                                                                |
+| `dbchecker.image.pullPolicy`                 | Image pull policy for the dbchecker image                                                                                                                                                                                                                                         | `IfNotPresent`                                                                                                                        |
+| `dbchecker.securityContext`                  | SecurityContext for the dbchecker container                                                                                                                                                                                                                                       | `{"allowPrivilegeEscalation":false,"runAsGroup":1000,"runAsNonRoot":true,"runAsUser":1000}`                                           |
+| `dbchecker.resources`                        | Resource requests and limits for the dbchecker container                                                                                                                                                                                                                          | `{"limits":{"cpu":"10m","memory":"16Mi"},"requests":{"cpu":"10m","memory":"16Mi"}}`                                                   |
+| `database.hostname`                          | Database Hostname                                                                                                                                                                                                                                                                 | unset                                                                                                                                 |
+| `database.port`                              | Database Port                                                                                                                                                                                                                                                                     | unset                                                                                                                                 |
+| `database.username`                          | Database User                                                                                                                                                                                                                                                                     | unset                                                                                                                                 |
+| `database.password`                          | Database Password                                                                                                                                                                                                                                                                 | unset                                                                                                                                 |
+| `database.existingSecret`                    | Existing Secret containing database password (expects key `password`) | unset                                                                                                                                 |
+| `database.database`                          | Database                                                                                                                                                                                                                                                                          | unset                                                                                                                                 |
+| `cache.stack`                                | Cache / Cluster Discovery, use `custom` to disable automatic configruation.                                                                                                                                                                                                       | `default`                                                                                                                             |
+| `proxy.enabled`                              | If `true`, the `KC_PROXY` env variable will be set to the configured mode                                                                                                                                                                                                         | `true`                                                                                                                                |
+| `proxy.mode`                                 | The configured proxy mode                                                                                                                                                                                                                                                         | `edge`                                                                                                                                |
+| `http.relativePath`                          | The relative http path (context-path)                                                                                                                                                                                                                                             | `/auth`                                                                                                                               |
+| `metrics.enabled`                            | If `true` then the metrics endpoint is exposed                                                                                                                                                                                                                                    | `true`                                                                                                                                |
+| `health.enabled`                            | If `true` then the health endpoint is exposed                                                                                                                                                                                                                                    | `true`                                                                                                                                |
+| `serviceMonitor.enabled`                     | If `true`, a ServiceMonitor resource for the prometheus-operator is created                                                                                                                                                                                                       | `false`                                                                                                                               |
+| `serviceMonitor.namespace`                   | Optionally sets a target namespace in which to deploy the ServiceMonitor resource                                                                                                                                                                                                 | `""`                                                                                                                                  |
+| `serviceMonitor.namespaceSelector`           | Optionally sets a namespace selector for the ServiceMonitor                                                                                                                                                                                                                       | `{}`                                                                                                                                  |
+| `serviceMonitor.annotations`                 | Annotations for the ServiceMonitor                                                                                                                                                                                                                                                | `{}`                                                                                                                                  |
+| `serviceMonitor.labels`                      | Additional labels for the ServiceMonitor                                                                                                                                                                                                                                          | `{}`                                                                                                                                  |
+| `serviceMonitor.interval`                    | Interval at which Prometheus scrapes metrics                                                                                                                                                                                                                                      | `10s`                                                                                                                                 |
+| `serviceMonitor.scrapeTimeout`               | Timeout for scraping                                                                                                                                                                                                                                                              | `10s`                                                                                                                                 |
+| `serviceMonitor.path`                        | The path at which metrics are served                                                                                                                                                                                                                                              | `{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/metrics`                                                                                                                       |
+| `serviceMonitor.port`                        | The Service port at which metrics are served                                                                                                                                                                                                                                      | `http`                                                                                                                                |
+| `extraServiceMonitor.enabled`                | If `true`, an additional ServiceMonitor resource for the prometheus-operator is created. Could be used for additional metrics via [Keycloak Metrics SPI](https://github.com/aerogear/keycloak-metrics-spi)                                                                        | `false`                                                                                                                               |
+| `extraServiceMonitor.namespace`              | Optionally sets a target namespace in which to deploy the additional ServiceMonitor resource                                                                                                                                                                                      | `""`                                                                                                                                  |
+| `extraServiceMonitor.namespaceSelector`      | Optionally sets a namespace selector for the additional ServiceMonitor                                                                                                                                                                                                            | `{}`                                                                                                                                  |
+| `extraServiceMonitor.annotations`            | Annotations for the additional ServiceMonitor                                                                                                                                                                                                                                     | `{}`                                                                                                                                  |
+| `extraServiceMonitor.labels`                 | Additional labels for the additional ServiceMonitor                                                                                                                                                                                                                               | `{}`                                                                                                                                  |
+| `extraServiceMonitor.interval`               | Interval at which Prometheus scrapes metrics                                                                                                                                                                                                                                      | `10s`                                                                                                                                 |
+| `extraServiceMonitor.scrapeTimeout`          | Timeout for scraping                                                                                                                                                                                                                                                              | `10s`                                                                                                                                 |
+| `extraServiceMonitor.path`                   | The path at which metrics are served                                                                                                                                                                                                                                              | `{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/metrics`                                                                                                                       |
+| `extraServiceMonitor.port`                   | The Service port at which metrics are served                                                                                                                                                                                                                                      | `http`                                                                                                                                |
+| `prometheusRule.enabled`                     | If `true`, a PrometheusRule resource for the prometheus-operator is created                                                                                                                                                                                                       | `false`                                                                                                                               |
+| `prometheusRule.namespace`                   | Optionally sets a target namespace in which to deploy the PrometheusRule resource                                                                                                                                                                                                 | `""`                                                                                                                               |
+| `prometheusRule.annotations`                 | Annotations for the PrometheusRule                                                                                                                                                                                                                                                | `{}`                                                                                                                                  |
+| `prometheusRule.labels`                      | Additional labels for the PrometheusRule                                                                                                                                                                                                                                          | `{}`                                                                                                                                  |
+| `prometheusRule.rules`                       | List of rules for Prometheus                                                                                                                                                                                                                                                      | `[]`                                                                                                                                  |
+| `autoscaling.enabled`                        | Enable creation of a HorizontalPodAutoscaler resource                                                                                                                                                                                                                             | `false`                                                                                                                               |
+| `autoscaling.labels`                         | Additional labels for the HorizontalPodAutoscaler resource                                                                                                                                                                                                                        | `{}`                                                                                                                                  |
+| `autoscaling.minReplicas`                    | The minimum number of Pods when autoscaling is enabled                                                                                                                                                                                                                            | `3`                                                                                                                                   |
+| `autoscaling.maxReplicas`                    | The maximum number of Pods when autoscaling is enabled                                                                                                                                                                                                                            | `10`                                                                                                                                  |
+| `autoscaling.metrics`                        | The metrics configuration for the HorizontalPodAutoscaler                                                                                                                                                                                                                         | `[{"resource":{"name":"cpu","target":{"averageUtilization":80,"type":"Utilization"}},"type":"Resource"}]`                             |
+| `autoscaling.behavior`                       | The scaling policy configuration for the HorizontalPodAutoscaler                                                                                                                                                                                                                  | `{"scaleDown":{"policies":[{"periodSeconds":300,"type":"Pods","value":1}],"stabilizationWindowSeconds":300}`                          |
+| `test.enabled`                               | If `true`, test resources are created                                                                                                                                                                                                                                             | `false`                                                                                                                               |
+| `test.image.repository`                      | The image for the test Pod                                                                                                                                                                                                                                                        | `docker.io/unguiculus/docker-python3-phantomjs-selenium`                                                                              |
+| `test.image.tag`                             | The tag for the test Pod image                                                                                                                                                                                                                                                    | `v1`                                                                                                                                  |
+| `test.image.pullPolicy`                      | The image pull policy for the test Pod image                                                                                                                                                                                                                                      | `IfNotPresent`                                                                                                                        |
+| `test.podSecurityContext`                    | SecurityContext for the entire test Pod                                                                                                                                                                                                                                           | `{"fsGroup":1000}`                                                                                                                    |
+| `test.securityContext`                       | SecurityContext for the test container                                                                                                                                                                                                                                            | `{"runAsNonRoot":true,"runAsUser":1000}`                                                                                              |
+| `test.deletionPolicy` | `helm.sh/hook-delete-policy` for the test Pod | `before-hook-creation` |
+
+Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example:
+
+```console
+$ helm install keycloak codecentric/keycloakx -n keycloak --set replicas=1
+```
+
+Alternatively, a YAML file that specifies the values for the parameters can be provided while
+installing the chart. For example:
+
+```console
+$ helm install keycloak codecentric/keycloakx -n keycloak --values values.yaml
+```
+
+The chart offers great flexibility.
+It can be configured to work with the official Keycloak-X Docker image but any custom image can be used as well.
+
+For the official Docker image, please check it's configuration at https://github.com/keycloak/keycloak/tree/main/quarkus/container.
+
+### Usage of the `tpl` Function
+
+The `tpl` function allows us to pass string values from `values.yaml` through the templating engine.
+It is used for the following values:
+
+* `extraInitContainers`
+* `extraContainers`
+* `extraEnv`
+* `extraEnvFrom`
+* `affinity`
+* `extraVolumeMounts`
+* `extraVolumes`
+* `livenessProbe`
+* `readinessProbe`
+* `startupProbe`
+* `topologySpreadConstraints`
+
+Additionally, custom labels and annotations can be set on various resources the values of which being passed through `tpl` as well.
+
+It is important that these values be configured as strings.
+Otherwise, installation will fail.
+See example for Google Cloud Proxy or default affinity configuration in `values.yaml`.
+
+### JVM Settings
+
+Keycloak sets the following system properties by default:
+`-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true`
+
+You can override these by setting the `JAVA_OPTS` environment variable.
+Make sure you configure container support.
+This allows you to only configure memory using Kubernetes resources and the JVM will automatically adapt.
+
+```yaml
+extraEnv: |
+  - name: JAVA_OPTS
+    value: >-
+      -XX:+UseContainerSupport
+      -XX:MaxRAMPercentage=50.0
+      -Djava.net.preferIPv4Stack=true
+      -Djava.awt.headless=true
+```
+
+Alternatively one can append custom JVM options by setting the `JAVA_OPTS_APPEND` environment variable.
+
+#### Using an External Database
+
+The Keycloak Docker image supports various database types.
+Configuration happens in a generic manner.
+
+##### Using a Secret Managed by the Chart
+
+The following examples uses a PostgreSQL database with a secret that is managed by the Helm chart.
+
+```yaml
+dbchecker:
+  enabled: true
+
+database:
+  vendor: postgres
+  hostname: mypostgres
+  port: 5432
+  username: '{{ .Values.dbUser }}'
+  password: '{{ .Values.dbPassword }}'
+  database: mydb
+```
+
+`dbUser` and `dbPassword` are custom values you'd then specify on the commandline using `--set-string`.
+
+##### Using an Existing Secret
+
+The following examples uses a PostgreSQL database with an existing secret.
+
+```yaml
+dbchecker:
+  enabled: true
+
+database:
+  vendor: postgres
+  hostname: mypostgres
+  port: 5432
+  database: mydb
+  username: db-user
+  existingSecret: byo-db-creds # Password is retrieved via .password
+```
+
+### Creating a Keycloak Admin User
+
+The Keycloak-X Docker image supports creating an initial admin user.
+It must be configured via environment variables:
+
+* `KC_DB_USERNAME` or `KC_DB_USERNAME_FILE`
+* `KC_DB_PASSWORD` or `KC_DB_PASSWORD_FILE`
+
+Please refer to the section on database configuration for how to configure a secret for this.
+
+### High Availability and Clustering
+
+For high availability, Keycloak must be run with multiple replicas (`replicas > 1`).
+The chart has a helper template (`keycloak.serviceDnsName`) that creates the DNS name based on the headless service.
+
+#### DNS_PING Service Discovery
+
+JGroups discovery via DNS_PING is enabled by default but needs an additional JVM setting, which can be configured as follows:
+
+```yaml
+extraEnv: |
+  - name: JAVA_OPTS_APPEND
+    value: >-
+      -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless
+```
+
+#### Custom Service Discovery
+
+If a custom JGroups discovery is needed, then you can configure:
+
+```yaml
+cache:
+  stack: custom
+```
+
+You can then reference your custom infinispan configuration file, e.g. `cache-custom.xml` via the `KC_CACHE_CONFIG_FILE` environment variable.
+Note that the `cache-custom.xml` must be available via `/opt/keycloak/conf/cache-custom.xml`.
+
+```yaml
+extraEnv: |
+  - name: KC_CACHE
+    value: "ispn"
+  - name: KC_CACHE_CONFIG_FILE
+    value: cache-custom.xml
+```
+
+#### Autoscaling
+
+Due to the caches in Keycloak only replicating to a few nodes (two in the example configuration above) and the limited controls around autoscaling built into Kubernetes, it has historically been problematic to autoscale Keycloak.
+However, in Kubernetes 1.18 [additional controls were introduced](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-configurable-scaling-behavior) which make it possible to scale down in a more controlled manner.
+
+The example autoscaling configuration in the values file scales from three up to a maximum of ten Pods using CPU utilization as the metric. Scaling up is done as quickly as required but scaling down is done at a maximum rate of one Pod per five minutes.
+
+Autoscaling can be enabled as follows:
+
+```yaml
+autoscaling:
+  enabled: true
+```
+
+KUBE_PING service discovery seems to be the most reliable mechanism to use when enabling autoscaling, due to being faster than DNS_PING at detecting changes in the cluster.
+
+### Running Keycloak Behind a Reverse Proxy
+
+When running Keycloak behind a reverse proxy, which is the case when using an ingress controller,
+proxy address forwarding must be enabled as follows:
+
+```yaml
+extraEnv: |
+  - name: KC_PROXY
+    value: "passthrough"
+```
+
+### Providing a Custom Theme
+
+One option is certainly to provide a custom Keycloak-X image that includes the theme.
+However, if you prefer to stick with the official Keycloak-X image, you can use an init container as theme provider.
+
+Create your own theme and package it up into a Docker image.
+
+```docker
+FROM busybox
+COPY mytheme /mytheme
+```
+
+In combination with an `emptyDir` that is shared with the Keycloak container, configure an init container that runs your theme image and copies the theme over to the right place where Keycloak will pick it up automatically.
+
+```yaml
+extraInitContainers: |
+  - name: theme-provider
+    image: myuser/mytheme:1
+    imagePullPolicy: IfNotPresent
+    command:
+      - sh
+    args:
+      - -c
+      - |
+        echo "Copying theme..."
+        cp -R /mytheme/* /theme
+    volumeMounts:
+      - name: theme
+        mountPath: /theme
+
+extraVolumeMounts: |
+  - name: theme
+    mountPath: /opt/keycloak/themes/mytheme
+
+extraVolumes: |
+  - name: theme
+    emptyDir: {}
+```
+
+### Using Google Cloud SQL Proxy
+
+Depending on your environment you may need a local proxy to connect to the database.
+This is, e. g., the case for Google Kubernetes Engine when using Google Cloud SQL.
+Create the secret for the credentials as documented [here](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) and configure the proxy as a sidecar.
+
+Because `extraContainers` is a string that is passed through the `tpl` function, it is possible to create custom values and use them in the string.
+
+```yaml
+database:
+  vendor: postgres
+  hostname: '127.0.0.1'
+  port: 5432
+  database: postgres
+  username: myuser
+  password: mypassword
+
+# Custom values for Google Cloud SQL
+cloudsql:
+  project: my-project
+  region: europe-west1
+  instance: my-instance
+
+extraContainers: |
+  - name: cloudsql-proxy
+    image: gcr.io/cloudsql-docker/gce-proxy:1.17
+    command:
+      - /cloud_sql_proxy
+    args:
+      - -instances={{ .Values.cloudsql.project }}:{{ .Values.cloudsql.region }}:{{ .Values.cloudsql.instance }}=tcp:5432
+      - -credential_file=/secrets/cloudsql/credentials.json
+    volumeMounts:
+      - name: cloudsql-creds
+        mountPath: /secrets/cloudsql
+        readOnly: true
+
+extraVolumes: |
+  - name: cloudsql-creds
+    secret:
+      secretName: cloudsql-instance-credentials
+```
+
+### Changing the Context Path
+
+By default, Keycloak-X is served under context `/auth`.
+Trailing slash is removed from path. This can be changed to another context path like `/` as follows:
+
+```yaml
+http:
+  relativePath: '/'
+```
+
+Alternatively, you may supply it via CLI flag:
+
+```console
+--set-string http.relativePath=/
+```
+
+### Prometheus Metrics Support
+
+#### Keycloak Metrics
+
+Keycloak-X can expose metrics via `/auth/metrics`.
+
+Metrics are enabled by default via:
+```yaml
+metrics:
+  enabled: true
+```
+
+Add a ServiceMonitor if using prometheus-operator:
+
+```yaml
+serviceMonitor:
+  # If `true`, a ServiceMonitor resource for the prometheus-operator is created
+  enabled: true
+```
+
+Checkout `values.yaml` for customizing the ServiceMonitor and for adding custom Prometheus rules.
+
+Add annotations if you don't use prometheus-operator:
+
+```yaml
+service:
+  annotations:
+    prometheus.io/scrape: "true"
+    prometheus.io/port: "8080"
+```
+
+#### Keycloak Metrics SPI
+
+Optionally, it is possible to add [Keycloak Metrics SPI](https://github.com/aerogear/keycloak-metrics-spi) via init container.
+Note that the `keycloak-metrics-spi.jar` needs to be added to the `/opt/keycloak/providers` directory.
+
+A separate `ServiceMonitor` can be enabled to scrape metrics from the SPI:
+
+```yaml
+extraServiceMonitor:
+  # If `true`, an additional ServiceMonitor resource for the prometheus-operator is created
+  enabled: true
+```
+
+Checkout `values.yaml` for customizing this ServiceMonitor.
+
+Note that the metrics endpoint is exposed on the HTTP port.
+You may want to restrict access to it in your ingress controller configuration.
+For ingress-nginx, this could be done as follows:
+
+```yaml
+annotations:
+  nginx.ingress.kubernetes.io/server-snippet: |
+    location ~* /auth/realms/[^/]+/metrics {
+        return 403;
+    }
+```
+
+## Why StatefulSet?
+
+The headless service that governs the StatefulSet is used for DNS discovery via DNS_PING.
+
+## Bad Gateway and Proxy Buffer Size in Nginx
+
+A common issue with Keycloak and nginx is that the proxy buffer may be too small for what Keycloak is trying to send. This will result in a Bad Gateway (502) error. There are [many](https://github.com/kubernetes/ingress-nginx/issues/4637) [issues](https://stackoverflow.com/questions/56126864/why-do-i-get-502-when-trying-to-authenticate) around the internet about this. The solution is to increase the buffer size of nginx. This can be done by creating an annotation in the ingress specification:
+
+```yaml
+ingress:
+  annotations:
+    nginx.ingress.kubernetes.io/proxy-buffer-size: "128k"
+```
+
+## Upgrading
+
+Notes for upgrading from previous Keycloak chart versions.
+
+### From chart < 18.0.0
+
+* Keycloak is updated to 18.0.0
+* Added new `health.enabled` option.
+
+Keycloak 18.0.0 allows to enable the health endpoint independently of the metrics endpoint via the `health-enabled` setting.
+We reflect that via the new config option `health.enabled`.
+
+Please read the additional notes about [Migrating to 18.0.0](https://www.keycloak.org/docs/latest/upgrading/index.html#migrating-to-18-0-0) in the Keycloak documentation.
diff --git a/kubernetes/platform/components/keycloak/templates/NOTES.txt b/kubernetes/platform/components/keycloak/templates/NOTES.txt
new file mode 100644 (file)
index 0000000..a6b49cf
--- /dev/null
@@ -0,0 +1,65 @@
+***********************************************************************
+*                                                                     *
+*                Keycloak Helm Chart by codecentric AG                *
+*                                                                     *
+***********************************************************************
+
+{{- if .Values.ingress.enabled }}
+
+Keycloak was installed with an Ingress and can be reached at the following URL(s):
+{{ range $unused, $rule := .Values.ingress.rules }}
+  {{- range $rule.paths }}
+  {{- if $rule.host }}
+  - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ tpl $rule.host $ }}{{ .path }}
+  {{- else }}
+  - http{{ if $.Values.ingress.tls }}s{{ end }}://<INGRESS_ADDRESS>{{ .path }}
+  {{-  end }}
+  {{-  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 {{ .Release.Namespace }} service {{ include "keycloak.fullname" . }}-http --template='{{"{{ range .spec.ports }}{{ if eq .name \"http\" }}{{ .nodePort }}{{ end }}{{ end }}"}}')
+export NODE_IP=$(kubectl get nodes --namespace {{ .Release.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 {{ .Release.Namespace }} service {{ include "keycloak.fullname" . }}-http --template='{{"{{ range .spec.ports }}{{ if eq .name \"https\" }}{{ .nodePort }}{{ end }}{{ end }}"}}')
+export NODE_IP=$(kubectl get nodes --namespace {{ .Release.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 {{ .Release.Namespace }} service -w {{ include "keycloak.fullname" . }}'
+
+Get its HTTP URL with the following commands:
+
+export SERVICE_IP=$(kubectl get service --namespace {{ .Release.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 {{ .Release.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 {{ .Release.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 {{ .Release.Namespace }} port-forward "$POD_NAME" 8080
+
+{{- end }}
diff --git a/kubernetes/platform/components/keycloak/templates/_helpers.tpl b/kubernetes/platform/components/keycloak/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..b06758a
--- /dev/null
@@ -0,0 +1,90 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "keycloak.name" -}}
+{{ include "common.name" . }}
+{{/* - default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" */}}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+*/}}
+{{- define "keycloak.fullname" -}}
+{{ include "common.fullname" . }}
+{{- 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 | 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.{{ .Release.Namespace }}.svc.{{ .Values.clusterDomain }}
+{{- 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: password
+  {{- end }}
+{{- end -}}
\ No newline at end of file
diff --git a/kubernetes/platform/components/keycloak/templates/configmap-startup.yaml b/kubernetes/platform/components/keycloak/templates/configmap-startup.yaml
new file mode 100644 (file)
index 0000000..6fdeec3
--- /dev/null
@@ -0,0 +1,35 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.startupScripts }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "keycloak.fullname" . }}-startup
+  namespace: {{ .Release.Namespace }}
+  labels:
+    {{- include "keycloak.labels" . | nindent 4 }}
+data:
+  {{- range $key, $value := .Values.startupScripts }}
+  {{ $key }}: |
+    {{- tpl $value $ | nindent 4 }}
+  {{- end }}
+{{- end -}}
diff --git a/kubernetes/platform/components/keycloak/templates/hpa.yaml b/kubernetes/platform/components/keycloak/templates/hpa.yaml
new file mode 100644 (file)
index 0000000..def92b9
--- /dev/null
@@ -0,0 +1,44 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta2
+kind: HorizontalPodAutoscaler
+metadata:
+  name: {{ include "keycloak.fullname" . }}
+  namespace: {{ .Release.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 }}
diff --git a/kubernetes/platform/components/keycloak/templates/ingress.yaml b/kubernetes/platform/components/keycloak/templates/ingress.yaml
new file mode 100644 (file)
index 0000000..6ca7cec
--- /dev/null
@@ -0,0 +1,21 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+
+{{ include "common.ingress" . }}
\ No newline at end of file
diff --git a/kubernetes/platform/components/keycloak/templates/networkpolicy.yaml b/kubernetes/platform/components/keycloak/templates/networkpolicy.yaml
new file mode 100644 (file)
index 0000000..00be51f
--- /dev/null
@@ -0,0 +1,66 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.networkPolicy.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ include "keycloak.fullname" . | quote }}
+  namespace: {{ .Release.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
+  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 }}
+{{- end }}
diff --git a/kubernetes/platform/components/keycloak/templates/poddisruptionbudget.yaml b/kubernetes/platform/components/keycloak/templates/poddisruptionbudget.yaml
new file mode 100644 (file)
index 0000000..5a62eb6
--- /dev/null
@@ -0,0 +1,35 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.podDisruptionBudget -}}
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: {{ include "keycloak.fullname" . }}
+  namespace: {{ .Release.Namespace }}
+  labels:
+    {{- include "keycloak.labels" . | nindent 4 }}
+spec:
+  selector:
+    matchLabels:
+      {{- include "keycloak.selectorLabels" . | nindent 6 }}
+  {{- toYaml .Values.podDisruptionBudget | nindent 2 }}
+{{- end -}}
diff --git a/kubernetes/platform/components/keycloak/templates/prometheusrule.yaml b/kubernetes/platform/components/keycloak/templates/prometheusrule.yaml
new file mode 100644 (file)
index 0000000..7392c60
--- /dev/null
@@ -0,0 +1,50 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- with .Values.prometheusRule -}}
+{{- if .enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: PrometheusRule
+metadata:
+  name: {{ include "keycloak.fullname" $ }}
+  {{- with .namespace }}
+  namespace: {{ . }}
+  {{- else }}
+  namespace: {{ $.Release.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 -}}
diff --git a/kubernetes/platform/components/keycloak/templates/rbac.yaml b/kubernetes/platform/components/keycloak/templates/rbac.yaml
new file mode 100644 (file)
index 0000000..fbcf201
--- /dev/null
@@ -0,0 +1,48 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if and .Values.rbac.create .Values.rbac.rules }}
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ include "keycloak.fullname" . }}
+  namespace: {{ .Release.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: {{ .Release.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: {{ .Release.Namespace | quote }}
+{{- end }}
diff --git a/kubernetes/platform/components/keycloak/templates/route.yaml b/kubernetes/platform/components/keycloak/templates/route.yaml
new file mode 100644 (file)
index 0000000..055df8e
--- /dev/null
@@ -0,0 +1,60 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- $route := .Values.route -}}
+{{- if $route.enabled -}}
+apiVersion: route.openshift.io/v1
+kind: Route
+metadata:
+  name: {{ include "keycloak.fullname" . }}
+  namespace: {{ .Release.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 -}}
diff --git a/kubernetes/platform/components/keycloak/templates/secrets.yaml b/kubernetes/platform/components/keycloak/templates/secrets.yaml
new file mode 100644 (file)
index 0000000..1bc7611
--- /dev/null
@@ -0,0 +1,52 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{ include "common.secretFast" . }}
+{{- range $nameSuffix, $values := .Values.secrets }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ include "keycloak.fullname" $ }}-{{ $nameSuffix }}
+  namespace: {{ $.Release.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 -}}
diff --git a/kubernetes/platform/components/keycloak/templates/service-headless.yaml b/kubernetes/platform/components/keycloak/templates/service-headless.yaml
new file mode 100644 (file)
index 0000000..6556ef2
--- /dev/null
@@ -0,0 +1,39 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "keycloak.fullname" . }}-headless
+  namespace: {{ .Release.Namespace }}
+  labels:
+    {{- include "keycloak.labels" . | nindent 4 }}
+    app.kubernetes.io/component: headless
+spec:
+  type: ClusterIP
+  clusterIP: None
+  ports:
+    - name: http
+      port: {{ .Values.service.httpPort }}
+      targetPort: http
+      protocol: TCP
+  selector:
+    {{- include "keycloak.selectorLabels" . | nindent 4 }}
diff --git a/kubernetes/platform/components/keycloak/templates/service-http.yaml b/kubernetes/platform/components/keycloak/templates/service-http.yaml
new file mode 100644 (file)
index 0000000..2aca87c
--- /dev/null
@@ -0,0 +1,77 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "keycloak.fullname" . }}-http
+  namespace: {{ .Release.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 eq "LoadBalancer" .Values.service.type }}
+  externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
+  {{- end }}
+  {{- if .Values.service.sessionAffinity }}
+  sessionAffinity: {{ .Values.service.sessionAffinity }}
+    {{- with .Values.service.sessionAffinityConfig }}
+  sessionAffinityConfig:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+  {{- end }}
+  ports:
+    - 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
+    - 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
+    {{- with .Values.service.extraPorts }}
+    {{- toYaml . | nindent 4 }}
+    {{- end }}
+  selector:
+    {{- include "keycloak.selectorLabels" . | nindent 4 }}
diff --git a/kubernetes/platform/components/keycloak/templates/serviceaccount.yaml b/kubernetes/platform/components/keycloak/templates/serviceaccount.yaml
new file mode 100644 (file)
index 0000000..c199067
--- /dev/null
@@ -0,0 +1,68 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ include "keycloak.serviceAccountName" . }}
+  namespace: {{ .Release.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 }}
+imagePullSecrets:
+  {{- toYaml .Values.serviceAccount.imagePullSecrets | nindent 4 }}
+automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
+
+---
+
+  {{- if .Values.serviceAccount.allowReadPods -}}
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: jgroups-kubeping-pod-reader-{{ .Release.Namespace }}
+rules:
+  - apiGroups: [""]
+    resources: ["pods"]
+    verbs: ["get", "list"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: jgroups-kubeping-api-access-{{ .Release.Namespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: jgroups-kubeping-pod-reader-{{ .Release.Namespace }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ include "keycloak.serviceAccountName" . }}
+    namespace: {{ .Release.Namespace }}
+  {{- end }}
+{{- end }}
diff --git a/kubernetes/platform/components/keycloak/templates/servicemonitor.yaml b/kubernetes/platform/components/keycloak/templates/servicemonitor.yaml
new file mode 100644 (file)
index 0000000..213a94f
--- /dev/null
@@ -0,0 +1,62 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- 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: {{ $.Release.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: {{ .port }}
+      path: {{ tpl .path $ | quote }}
+      interval: {{ .interval }}
+      scrapeTimeout: {{ .scrapeTimeout }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/kubernetes/platform/components/keycloak/templates/statefulset.yaml b/kubernetes/platform/components/keycloak/templates/statefulset.yaml
new file mode 100644 (file)
index 0000000..9305681
--- /dev/null
@@ -0,0 +1,231 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "keycloak.fullname" . }}
+  namespace: {{ .Release.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: RollingUpdate
+  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 .Values.dbchecker.enabled }}
+        {{ include "common.readinessCheck.waitFor" . | nindent 6 }}
+        {{- end }}
+        {{- with .Values.extraInitContainers }}
+        {{- tpl . $ | nindent 8 }}
+        {{- end }}
+      {{- end }}
+    {{- end }}
+      containers:
+        - name: keycloak
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ include "repositoryGenerator.quayRepository" . }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          #image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          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: "kubernetes"
+            {{- end }}
+            {{- if .Values.proxy.enabled }}
+            - name: KC_PROXY
+              value: {{ .Values.proxy.mode }}
+            {{- end }}
+            {{- if .Values.database.vendor }}
+            - name: KC_DB
+              value: {{ .Values.database.vendor }}
+            {{- end }}
+            {{- if .Values.database.hostname }}
+            - name: KC_DB_URL_HOST
+              value: {{ .Values.postgres.service.name2 }}
+            {{- 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
+              {{- include "common.secret.envFromSecretFast" (dict "global" . "uid" "pg-user-creds" "key" "login") | indent 14 }}
+            {{- end }}
+            {{/*- if or .Values.database.password .Values.database.existingSecret -*/}}
+            - name: KC_DB_PASSWORD
+              {{- include "common.secret.envFromSecretFast" (dict "global" . "uid" "pg-user-creds" "key" "password") | indent 14 }}
+            {{/*- 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: https
+              containerPort: 8443
+              protocol: TCP
+            {{- with .Values.extraPorts }}
+            {{- toYaml . | nindent 12 }}
+            {{- end }}
+          {{- if .Values.health.enabled }}
+          {{- with .Values.livenessProbe }}
+          livenessProbe:
+            {{- tpl . $ | nindent 12 }}
+          {{- end }}
+          {{- with .Values.readinessProbe }}
+          readinessProbe:
+            {{- tpl . $ | nindent 12 }}
+          {{- 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 }}
diff --git a/kubernetes/platform/components/keycloak/templates/test/configmap-test.yaml b/kubernetes/platform/components/keycloak/templates/test/configmap-test.yaml
new file mode 100644 (file)
index 0000000..a346cde
--- /dev/null
@@ -0,0 +1,72 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.test.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "keycloak.fullname" . }}-test
+  namespace: {{ .Release.Namespace }}
+  labels:
+    {{- include "keycloak.labels" . | nindent 4 }}
+  annotations:
+    helm.sh/hook: test
+    helm.sh/hook-delete-policy: hook-succeeded
+data:
+  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.support import expected_conditions
+    from urllib.parse import urlparse
+
+    print('Creating PhantomJS driver...')
+    driver = webdriver.PhantomJS(service_log_path='/tmp/ghostdriver.log')
+
+    base_url = 'http://{{ include "keycloak.fullname" . }}-http{{ if ne 80 (int .Values.service.httpPort) }}:{{ .Values.service.httpPort }}{{ end }}'
+
+    print('Opening Keycloak...')
+    driver.get('{0}/auth/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: '/auth/admin/master/console/' in driver.current_url)
+
+    print('Admin console visible. Login successful.')
+
+    driver.quit()
+
+  {{- end }}
diff --git a/kubernetes/platform/components/keycloak/templates/test/pod-test.yaml b/kubernetes/platform/components/keycloak/templates/test/pod-test.yaml
new file mode 100644 (file)
index 0000000..43a0bca
--- /dev/null
@@ -0,0 +1,66 @@
+{{/*
+#  ============LICENSE_START=======================================================
+#   Copyright (C) 2022 Codecentric
+#   Modifications (C) 2022 Deutsche Telekom
+#  ================================================================================
+#  Original licence (https://github.com/codecentric/helm-charts/blob/master/LICENSE)
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#  SPDX-License-Identifier: Apache-2.0
+#  ============LICENSE_END=========================================================
+*/}}
+{{- if .Values.test.enabled }}
+apiVersion: v1
+kind: Pod
+metadata:
+  name: {{ include "keycloak.fullname" . }}-test
+  namespace: {{ .Release.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 }}:{{ .Values.test.image.tag }}"
+      imagePullPolicy: {{ .Values.test.image.pullPolicy }}
+      securityContext:
+        {{- toYaml .Values.test.securityContext | nindent 8 }}
+      command:
+        - python3
+      args:
+        - /tests/test.py
+      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 }}
diff --git a/kubernetes/platform/components/keycloak/values.schema.json b/kubernetes/platform/components/keycloak/values.schema.json
new file mode 100644 (file)
index 0000000..331de51
--- /dev/null
@@ -0,0 +1,496 @@
+{
+  "$schema": "http://json-schema.org/schema#",
+  "type": "object",
+  "required": [
+    "image"
+  ],
+  "definitions": {
+    "image": {
+      "type": "object",
+      "required": [
+        "repository",
+        "tag"
+      ],
+      "properties": {
+        "pullPolicy": {
+          "type": "string",
+          "pattern": "^(Always|Never|IfNotPresent)$"
+        },
+        "repository": {
+          "type": "string"
+        },
+        "tag": {
+          "type": ["string", "integer"]
+        }
+      }
+    },
+    "imagePullSecrets": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "name": {
+            "type": "string"
+          }
+        }
+      }
+    }
+  },
+  "properties": {
+    "affinity": {
+      "type": "string"
+    },
+    "args": {
+      "type": "array"
+    },
+    "clusterDomain": {
+      "type": "string"
+    },
+    "command": {
+      "type": "array"
+    },
+    "enableServiceLinks": {
+      "type": "boolean"
+    },
+    "extraContainers": {
+      "type": "string"
+    },
+    "extraEnv": {
+      "type": "string"
+    },
+    "extraEnvFrom": {
+      "type": "string"
+    },
+    "extraInitContainers": {
+      "type": "string"
+    },
+    "extraPorts": {
+      "type": "array"
+    },
+    "extraVolumeMounts": {
+      "type": "string"
+    },
+    "extraVolumes": {
+      "type": "string"
+    },
+    "fullnameOverride": {
+      "type": "string"
+    },
+    "hostAliases": {
+      "type": "array"
+    },
+    "http": {
+      "relativePath": "string"
+    },
+    "image": {
+      "$ref": "#/definitions/image"
+    },
+    "imagePullSecrets": {
+      "$ref": "#/definitions/imagePullSecrets"
+    },
+    "ingress": {
+      "type": "object",
+      "properties": {
+        "annotations": {
+          "type": "object"
+        },
+        "enabled": {
+          "type": "boolean"
+        },
+        "labels": {
+          "type": "object"
+        },
+        "rules": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "properties": {
+              "host": {
+                "type": "string"
+              },
+              "paths": {
+                "type": "array",
+                "items": {
+                  "type": "object",
+                  "properties": {
+                    "path": {
+                      "type": "string"
+                    },
+                    "pathType": {
+                      "type": "string"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        },
+        "servicePort": {
+          "anyOf": [
+            {
+              "type": "integer"
+            },
+            {
+              "type": "string"
+            }
+          ]
+        },
+        "tls": {
+          "type": "array",
+          "items": {
+            "type": "object",
+            "properties": {
+              "hosts": {
+                "type": "array",
+                "items": {
+                  "items": {
+                    "type": "string"
+                  }
+                },
+                "secretName": {
+                  "type": "string"
+                }
+              }
+            }
+          }
+        }
+      },
+      "lifecycleHooks": {
+        "type": "string"
+      },
+      "livenessProbe": {
+        "type": "string"
+      },
+      "nameOverride": {
+        "type": "string"
+      },
+      "nodeSelector": {
+        "type": "object"
+      },
+      "dbchecker": {
+        "type": "object",
+        "properties": {
+          "enabled": {
+            "type": "boolean"
+          },
+          "image": {
+            "$ref": "#/definitions/image"
+          },
+          "resources": {
+            "type": "object",
+            "properties": {
+              "limits": {
+                "type": "object",
+                "properties": {
+                  "cpu": {
+                    "type": "string"
+                  },
+                  "memory": {
+                    "type": "string"
+                  }
+                }
+              },
+              "requests": {
+                "type": "object",
+                "properties": {
+                  "cpu": {
+                    "type": "string"
+                  },
+                  "memory": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          },
+          "securityContext": {
+            "type": "object"
+          }
+        }
+      },
+      "podAnnotations": {
+        "type": "object"
+      },
+      "podDisruptionBudget": {
+        "type": "object"
+      },
+      "podLabels": {
+        "type": "object"
+      },
+      "podManagementPolicy": {
+        "type": "string"
+      },
+      "podSecurityContext": {
+        "type": "object"
+      },
+      "cache": {
+        "type": "object",
+        "properties": {
+          "stack": {
+            "type": "string"
+          }
+        }
+      },
+      "proxy": {
+        "type": "object",
+        "properties": {
+          "enabled": {
+            "type": "boolean"
+          },
+          "mode": {
+            "type": "string"
+          }
+        }
+      },
+      "metrics": {
+        "type": "object",
+        "properties": {
+          "enabled": {
+            "type": "boolean"
+          }
+        }
+      },
+      "health": {
+        "type": "object",
+        "properties": {
+          "enabled": {
+            "type": "boolean"
+          }
+        }
+      },
+      "database": {
+        "type": "object",
+        "properties": {
+          "vendor": {
+            "type": "string"
+          },
+          "hostname": {
+            "type": "string"
+          },
+          "port": {
+            "type": "integer"
+          },
+          "username": {
+            "type": "string"
+          },
+          "password": {
+            "type": "string"
+          },
+          "database": {
+            "type": "string"
+          },
+          "existingSecret": {
+            "type": "string"
+          }
+        }
+      },
+      "priorityClassName": {
+        "type": "string"
+      },
+      "prometheusRule": {
+        "type": "object"
+      },
+      "serviceMonitor": {
+        "type": "object"
+      },
+      "extraServiceMonitor": {
+        "type": "object"
+      },
+      "readinessProbe": {
+        "type": "string"
+      },
+      "replicas": {
+        "type": "integer"
+      },
+      "resources": {
+        "type": "object"
+      },
+      "restartPolicy": {
+        "type": "string"
+      },
+      "route": {
+        "type": "object",
+        "properties": {
+          "annotations": {
+            "type": "object"
+          },
+          "enabled": {
+            "type": "boolean"
+          },
+          "host": {
+            "type": "string"
+          },
+          "labels": {
+            "type": "object"
+          },
+          "path": {
+            "type": "string"
+          },
+          "tls": {
+            "type": "object"
+          }
+        }
+      },
+      "secrets": {
+        "type": "object"
+      },
+      "securityContext": {
+        "type": "object"
+      },
+      "service": {
+        "type": "object",
+        "properties": {
+          "annotations": {
+            "type": "object"
+          },
+          "extraPorts": {
+            "type": "array"
+          },
+          "loadBalancerSourceRanges": {
+            "type": "array"
+          },
+          "httpNodePort": {
+            "anyOf": [
+              {
+                "type": "integer"
+              },
+              {
+                "type": "null"
+              }
+            ]
+          },
+          "httpPort": {
+            "type": "integer"
+          },
+          "httpsNodePort": {
+            "anyOf": [
+              {
+                "type": "integer"
+              },
+              {
+                "type": "null"
+              }
+            ]
+          },
+          "httpsPort": {
+            "type": "integer"
+          },
+          "labels": {
+            "type": "object"
+          },
+          "nodePort": {
+            "anyOf": [
+              {
+                "type": "integer"
+              },
+              {
+                "type": "null"
+              }
+            ]
+          },
+          "type": {
+            "type": "string"
+          },
+          "loadBalancerIP": {
+            "type": "string"
+          },
+          "sessionAffinity": {
+            "type": "string"
+          },
+          "sessionAffinityConfig": {
+            "type": "object"
+          }
+        }
+      },
+      "serviceAccount": {
+        "type": "object",
+        "properties": {
+          "annotations": {
+            "type": "object"
+          },
+          "create": {
+            "type": "boolean"
+          },
+          "allowReadPods": {
+            "type": "boolean"
+          },
+          "imagePullSecrets": {
+            "$ref": "#/definitions/imagePullSecrets"
+          },
+          "labels": {
+            "type": "object"
+          },
+          "name": {
+            "type": "string"
+          },
+          "automountServiceAccountToken": {
+            "type": "boolean"
+          }
+        }
+      },
+      "rbac": {
+        "type": "object",
+        "properties": {
+          "create": {
+            "type": "boolean"
+          },
+          "rules": {
+            "type": "array"
+          }
+        }
+      },
+      "statefulsetAnnotations": {
+        "type": "object"
+      },
+      "statefulsetLabels": {
+        "type": "object"
+      },
+      "terminationGracePeriodSeconds": {
+        "type": "integer"
+      },
+      "autoscaling": {
+        "type": "object",
+        "properties": {
+          "enabled": {
+            "type": "boolean"
+          },
+          "labels": {
+            "type": "object"
+          },
+          "minReplicas": {
+            "type": "integer"
+          },
+          "maxReplicas": {
+            "type": "integer"
+          },
+          "metrics": {
+            "type": "array"
+          },
+          "behavior": {
+            "type": "object"
+          }
+        }
+      },
+      "test": {
+        "type": "object",
+        "properties": {
+          "enabled": {
+            "type": "boolean"
+          },
+          "image": {
+            "$ref": "#/definitions/image"
+          },
+          "podSecurityContext": {
+            "type": "object"
+          },
+          "securityContext": {
+            "type": "object"
+          }
+        }
+      },
+      "tolerations": {
+        "type": "array"
+      }
+    }
+  }
+}
diff --git a/kubernetes/platform/components/keycloak/values.yaml b/kubernetes/platform/components/keycloak/values.yaml
new file mode 100644 (file)
index 0000000..7674a4c
--- /dev/null
@@ -0,0 +1,649 @@
+# Copyright © 2020-2022, Codecentrics
+# Modifications Copyright  © 2022, Deutsche Telekom
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Global (ONAP)
+global:
+  quayRepository: "quay.io"
+  busyboxRepository: docker.io
+  busyboxImage: busybox:1.34.1
+  #Service Names of the postgres db to connect to.
+  #Override it to cps-postgres if localCluster is enabled.
+  postgres:
+    localCluster: true
+    service:
+      name: keycloak-postgres
+      externalPort: 5432
+      name2: keycloak-pg-primary
+      externalPort2: 5432
+      name3: keycloak-pg-replica
+      externalPort3: 5432
+    container:
+      name: keycloak-postgres
+
+# Optionally override the fully qualified name
+fullnameOverride: ""
+
+# Optionally override the name
+nameOverride: ""
+
+# The number of replicas to create (has no effect if autoscaling enabled)
+replicas: 1
+
+image:
+  # The Keycloak image repository
+  #repository: quay.io/keycloak/keycloak
+  repository: keycloak/keycloak
+  # Overrides the Keycloak image tag whose default is the chart appVersion
+  tag: ""
+  # The Keycloak image pull policy
+  pullPolicy: IfNotPresent
+
+# Image pull secrets for the Pod
+imagePullSecrets: []
+# - name: myRegistrKeySecretName
+
+# Mapping between IPs and hostnames that will be injected as entries in the Pod's hosts files
+hostAliases: []
+# - ip: "1.2.3.4"
+#   hostnames:
+#     - "my.host.com"
+
+# Indicates whether information about services should be injected into Pod's environment variables, matching the syntax of Docker links
+enableServiceLinks: true
+
+# Pod management policy. One of `Parallel` or `OrderedReady`
+podManagementPolicy: OrderedReady
+
+# Pod restart policy. One of `Always`, `OnFailure`, or `Never`
+restartPolicy: Always
+
+serviceAccount:
+  nameOverride: keycloak
+  roles:
+    - read
+#  # Specifies whether a ServiceAccount should be created
+#  create: true
+#  # The name of the service account to use.
+#  # If not set and create is true, a name is generated using the fullname template
+#  name: ""
+#  # Additional annotations for the ServiceAccount
+#  annotations: {}
+#  # Additional labels for the ServiceAccount
+#  labels: {}
+#  # Image pull secrets that are attached to the ServiceAccount
+#  imagePullSecrets: []
+
+rbac:
+  create: false
+  rules: []
+  # RBAC rules for KUBE_PING
+  #  - apiGroups:
+  #      - ""
+  #    resources:
+  #      - pods
+  #    verbs:
+  #      - get
+  #      - list
+
+# SecurityContext for the entire Pod. Every container running in the Pod will inherit this SecurityContext. This might be relevant when other components of the environment inject additional containers into running Pods (service meshes are the most prominent example for this)
+podSecurityContext:
+  fsGroup: 1000
+
+# SecurityContext for the Keycloak container
+securityContext:
+  runAsUser: 1000
+  runAsNonRoot: true
+
+# Additional init containers, e. g. for providing custom themes
+extraInitContainers: ""
+
+# When using service meshes which rely on a sidecar, it may be necessary to skip init containers altogether,
+# since the sidecar doesn't start until the init containers are done, and the sidecar may be required
+# for network access.
+# For example, Istio in strict mTLS mode prevents the dbchecker init container from ever completing
+skipInitContainers: false
+
+# Additional sidecar containers, e. g. for a database proxy, such as Google's cloudsql-proxy
+extraContainers: ""
+
+# Lifecycle hooks for the Keycloak container
+lifecycleHooks: |
+#  postStart:
+#    exec:
+#      command:
+#        - /bin/sh
+#        - -c
+#        - ls
+
+# Termination grace period in seconds for Keycloak shutdown. Clusters with a large cache might need to extend this to give Infinispan more time to rebalance
+terminationGracePeriodSeconds: 60
+
+# The internal Kubernetes cluster domain
+clusterDomain: cluster.local
+
+## Overrides the default entrypoint of the Keycloak container
+command:
+  - "/opt/keycloak/bin/kc.sh"
+  - "--verbose"
+  - "start"
+  - "--auto-build"
+  - "--http-enabled=true"
+  - "--http-port=8080"
+  - "--hostname-strict=false"
+  - "--hostname-strict-https=false"
+  - "--spi-events-listener-jboss-logging-success-level=info"
+  - "--spi-events-listener-jboss-logging-error-level=warn"
+
+## Overrides the default args for the Keycloak container
+args: []
+
+# Additional environment variables for Keycloak
+extraEnv: |
+  - name: KEYCLOAK_ADMIN
+    valueFrom:
+      secretKeyRef:
+        name: {{ include "keycloak.fullname" . }}-admin-creds
+        key: login
+  - name: KEYCLOAK_ADMIN_PASSWORD
+    valueFrom:
+      secretKeyRef:
+        name: {{ include "keycloak.fullname" . }}-admin-creds
+        key: password
+  - name: JAVA_OPTS_APPEND
+    value: >-
+      -XX:+UseContainerSupport
+      -XX:MaxRAMPercentage=50.0
+      -Djava.awt.headless=true
+      -Djgroups.dns.query={{ include "keycloak.fullname" . }}-headless
+
+# Additional environment variables for Keycloak mapped from Secret or ConfigMap
+extraEnvFrom: ""
+
+#  Pod priority class name
+priorityClassName: ""
+
+# Pod affinity
+affinity: |
+  podAntiAffinity:
+    requiredDuringSchedulingIgnoredDuringExecution:
+      - labelSelector:
+          matchLabels:
+            {{- include "keycloak.selectorLabels" . | nindent 10 }}
+          matchExpressions:
+            - key: app.kubernetes.io/component
+              operator: NotIn
+              values:
+                - test
+        topologyKey: kubernetes.io/hostname
+    preferredDuringSchedulingIgnoredDuringExecution:
+      - weight: 100
+        podAffinityTerm:
+          labelSelector:
+            matchLabels:
+              {{- include "keycloak.selectorLabels" . | nindent 12 }}
+            matchExpressions:
+              - key: app.kubernetes.io/component
+                operator: NotIn
+                values:
+                  - test
+          topologyKey: failure-domain.beta.kubernetes.io/zone
+
+# Topology spread constraints template
+topologySpreadConstraints:
+
+# Node labels for Pod assignment
+nodeSelector: {}
+
+# Node taints to tolerate
+tolerations: []
+
+# Additional Pod labels
+podLabels: {}
+
+# Additional Pod annotations
+podAnnotations: {}
+
+# Liveness probe configuration
+livenessProbe: |
+  httpGet:
+    path: '{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/'
+    port: http
+  initialDelaySeconds: 0
+  timeoutSeconds: 5
+
+# Readiness probe configuration
+readinessProbe: |
+  httpGet:
+    path: '{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/realms/master'
+    port: http
+  initialDelaySeconds: 10
+  timeoutSeconds: 1
+
+# Startup probe configuration
+startupProbe: |
+  httpGet:
+    path: '{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/'
+    port: http
+  initialDelaySeconds: 15
+  timeoutSeconds: 1
+  failureThreshold: 60
+  periodSeconds: 5
+
+# Pod resource requests and limits
+resources: {}
+  # requests:
+  #   cpu: "500m"
+  #   memory: "1024Mi"
+  # limits:
+  #   cpu: "500m"
+  #   memory: "1024Mi"
+
+# Add additional volumes, e. g. for custom themes
+extraVolumes: ""
+
+# Add additional volumes mounts, e. g. for custom themes
+extraVolumeMounts: ""
+
+# Add additional ports, e. g. for admin console or exposing JGroups ports
+extraPorts: []
+
+# Pod disruption budget
+podDisruptionBudget: {}
+#  maxUnavailable: 1
+#  minAvailable: 1
+
+# Annotations for the StatefulSet
+statefulsetAnnotations: {}
+
+# Additional labels for the StatefulSet
+statefulsetLabels: {}
+
+# Configuration for secrets that should be created
+secrets:
+  - uid: pg-root-pass
+    name: &pgRootPassSecretName '{{ include "common.release" . }}-keycloak-pg-root-pass'
+    type: password
+    externalSecret: '{{ ternary "" (tpl (default "" .Values.postgres.config.pgRootPasswordExternalSecret) .) (hasSuffix "keycloak-pg-root-pass" .Values.postgres.config.pgRootPasswordExternalSecret) }}'
+    password: '{{ .Values.postgres.config.pgRootpassword }}'
+    policy: generate
+  - uid: pg-user-creds
+    name: &pgUserCredsSecretName '{{ include "common.release" . }}-keycloak-pg-user-creds'
+    type: basicAuth
+    externalSecret: '{{ ternary "" (tpl (default "" .Values.postgres.config.pgUserExternalSecret) .) (hasSuffix "keycloak-pg-user-creds" .Values.postgres.config.pgUserExternalSecret) }}'
+    login: '{{ .Values.postgres.config.pgUserName }}'
+    password: '{{ .Values.postgres.config.pgUserPassword }}'
+    passwordPolicy: generate
+  - uid: kc-admin-creds
+    name: &kcAdminCredsSecretName '{{ include "common.release" . }}-keycloak-admin-creds'
+    type: basicAuth
+    externalSecret: '{{ ternary "" (tpl (default "" .Values.keycloak.config.kcAdminExternalSecret) .) (hasSuffix "keycloak-admin-creds" .Values.keycloak.config.kcAdminExternalSecret) }}'
+    login: '{{ .Values.keycloak.config.kcAdminUser }}'
+    password: '{{ .Values.keycloak.config.kcAdminPassword }}'
+    passwordPolicy: generate
+  # mysecret:
+  #   type: {}
+  #   annotations: {}
+  #   labels: {}
+  #   stringData: {}
+  #   data: {}
+
+keycloak:
+  config:
+    kcAdminUser: "admin"
+    kcAdminPassword: "secret"
+    kcAdminExternalSecret: *kcAdminCredsSecretName
+
+service:
+  # Annotations for headless and HTTP Services
+  annotations: {}
+  # Additional labels for headless and HTTP Services
+  labels: {}
+  # key: value
+  # The Service type
+  type: ClusterIP
+  # Optional IP for the load balancer. Used for services of type LoadBalancer only
+  loadBalancerIP: ""
+  # The http Service port
+  httpPort: 80
+  # The HTTP Service node port if type is NodePort
+  httpNodePort: null
+  # The HTTPS Service port
+  httpsPort: 8443
+  # The HTTPS Service node port if type is NodePort
+  httpsNodePort: null
+  # Additional Service ports, e. g. for custom admin console
+  extraPorts: []
+  # When using Service type LoadBalancer, you can restrict source ranges allowed
+  # to connect to the LoadBalancer, e. g. will result in Security Groups
+  # (or equivalent) with inbound source ranges allowed to connect
+  loadBalancerSourceRanges: []
+  # When using Service type LoadBalancer, you can preserve the source IP seen in the container
+  # by changing the default (Cluster) to be Local.
+  # See https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
+  externalTrafficPolicy: "Cluster"
+  # Session affinity
+  # See https://kubernetes.io/docs/concepts/services-networking/service/#proxy-mode-userspace
+  sessionAffinity: ""
+  # Session affinity config
+  sessionAffinityConfig: {}
+
+ingress:
+  service:
+    - baseaddr: "keycloak-ui"
+      name: "onap-keycloak-http"
+      path: "/auth"
+      port: 80
+  # If `true`, an Ingress is created
+  enabled: false
+  # The name of the Ingress Class associated with this ingress
+  ingressClassName: ""
+  # The Service port targeted by the Ingress
+  servicePort: http
+  # Ingress annotations
+  annotations: {}
+    ## Resolve HTTP 502 error using ingress-nginx:
+    ## See https://www.ibm.com/support/pages/502-error-ingress-keycloak-response
+    # nginx.ingress.kubernetes.io/proxy-buffer-size: 128k
+
+  # Additional Ingress labels
+  labels: {}
+   # List of rules for the Ingress
+  rules:
+    -
+      # Ingress host
+      host: '{{ .Release.Name }}.keycloak.example.com'
+      # Paths for the host
+      paths:
+        - path: /
+          pathType: Prefix
+  # TLS configuration
+  tls:
+    - hosts:
+        - keycloak.example.com
+      secretName: ""
+
+  # ingress for console only (/auth/admin)
+  console:
+    # If `true`, an Ingress is created for console path only
+    enabled: false
+    # The name of Ingress Class associated with the console ingress only
+    ingressClassName: ""
+    # Ingress annotations for console ingress only
+    # Useful to set nginx.ingress.kubernetes.io/whitelist-source-range particularly
+    annotations: {}
+    rules:
+      -
+        # Ingress host
+        host: '{{ .Release.Name }}.keycloak.example.com'
+        # Paths for the host
+        paths:
+          - path: '{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/admin'
+            pathType: Prefix
+    # Console TLS configuration
+    tls: []
+#      - hosts:
+#          - console.keycloak.example.com
+#        secretName: ""
+
+## Network policy configuration
+networkPolicy:
+  # If true, the Network policies are deployed
+  enabled: false
+
+  # Additional Network policy labels
+  labels: {}
+
+  # Define all other external allowed source
+  # See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#networkpolicypeer-v1-networking-k8s-io
+  extraFrom: []
+
+route:
+  # If `true`, an OpenShift Route is created
+  enabled: false
+  # Path for the Route
+  path: /
+  # Route annotations
+  annotations: {}
+  # Additional Route labels
+  labels: {}
+  # Host name for the Route
+  host: ""
+  # TLS configuration
+  tls:
+    # If `true`, TLS is enabled for the Route
+    enabled: true
+    # Insecure edge termination policy of the Route. Can be `None`, `Redirect`, or `Allow`
+    insecureEdgeTerminationPolicy: Redirect
+    # TLS termination of the route. Can be `edge`, `passthrough`, or `reencrypt`
+    termination: edge
+
+dbchecker:
+  enabled: true
+  image:
+    # Docker image used to check Database readiness at startup
+    repository: docker.io/busybox
+    # Image tag for the dbchecker image
+    tag: 1.32
+    # Image pull policy for the dbchecker image
+    pullPolicy: IfNotPresent
+  # SecurityContext for the dbchecker container
+  securityContext:
+    allowPrivilegeEscalation: false
+    runAsUser: 1000
+    runAsGroup: 1000
+    runAsNonRoot: true
+  # Resource requests and limits for the dbchecker container
+  resources:
+    requests:
+      cpu: "20m"
+      memory: "32Mi"
+    limits:
+      cpu: "20m"
+      memory: "32Mi"
+
+database:
+  # don't create secret for db password. Instead use existing k8s secret
+  # existingSecret: "my-existent-dbpass-secret"
+  existingSecret: *pgUserCredsSecretName
+  # E.g. dev-file, dev-mem, mariadb, mssql, mysql, oracle or postgres
+  vendor: postgres
+  hostname: &postgresName keycloak-postgres
+  port: &postgresPort 5432
+  database: &dbName keycloak
+  username: &dbUser keycloak
+  password:
+
+  # PostgreSQL User to create
+  # postgresqlUsername: keycloak
+  # PostgreSQL Password for the new user
+  # postgresqlPassword: keycloak
+  # PostgreSQL Database to create
+  # postgresqlDatabase: keycloak
+  # PostgreSQL network policy configuration
+  # networkPolicy:
+  #   enabled: false
+  # service:
+  #  port: 5432
+
+#################################################################
+# Postgres overriding defaults in the postgres
+#################################################################
+postgres:
+  postgresInit: false
+  nameOverride: *postgresName
+  service:
+    name: *postgresName
+    externalPort: *postgresPort
+    name2: keycloak-pg-primary
+    externalPort2: *postgresPort
+    name3: keycloak-pg-replica
+    externalPort3: *postgresPort
+  container:
+    name:
+      primary: keycloak-pg-primary
+      replica: keycloak-pg-replica
+  persistence:
+    mountSubPath: keycloak/data
+    mountInitPath: keycloak
+  config:
+    pgUserName: *dbUser
+    pgDatabase: *dbName
+    pgUserExternalSecret: *pgUserCredsSecretName
+    pgRootPasswordExternalSecret: *pgRootPassSecretName
+    #pgPrimaryPassword: keycloak
+    #pgUserPassword: keycloak
+    #pgRootPassword: keycloak
+
+cache:
+  # Use "custom" to disable automatic cache configuration
+  stack: default
+
+proxy:
+  enabled: true
+  mode: edge
+
+metrics:
+  enabled: true
+
+health:
+  enabled: true
+
+http:
+  # For backwards compatibility reasons we set this to the value used by previous Keycloak versions.
+  relativePath: "/auth"
+
+serviceMonitor:
+  # If `true`, a ServiceMonitor resource for the prometheus-operator is created
+  enabled: false
+  # Optionally sets a target namespace in which to deploy the ServiceMonitor resource
+  namespace: ""
+  # Optionally sets a namespace for the ServiceMonitor
+  namespaceSelector: {}
+  # Annotations for the ServiceMonitor
+  annotations: {}
+  # Additional labels for the ServiceMonitor
+  labels: {}
+  # Interval at which Prometheus scrapes metrics
+  interval: 10s
+  # Timeout for scraping
+  scrapeTimeout: 10s
+  # The path at which metrics are served
+  path: '{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/metrics'
+  # The Service port at which metrics are served
+  port: http
+
+extraServiceMonitor:
+  # If `true`, a ServiceMonitor resource for the prometheus-operator is created
+  enabled: false
+  # Optionally sets a target namespace in which to deploy the ServiceMonitor resource
+  namespace: ""
+  # Optionally sets a namespace for the ServiceMonitor
+  namespaceSelector: {}
+  # Annotations for the ServiceMonitor
+  annotations: {}
+  # Additional labels for the ServiceMonitor
+  labels: {}
+  # Interval at which Prometheus scrapes metrics
+  interval: 10s
+  # Timeout for scraping
+  scrapeTimeout: 10s
+  # The path at which metrics are served
+  path: '{{ tpl .Values.http.relativePath $ | trimSuffix "/" }}/realms/master/metrics'
+  # The Service port at which metrics are served
+  port: http
+
+prometheusRule:
+  # If `true`, a PrometheusRule resource for the prometheus-operator is created
+  enabled: false
+  # Optionally sets a target namespace in which to deploy the ServiceMonitor resource
+  namespace: ""
+  # Annotations for the PrometheusRule
+  annotations: {}
+  # Additional labels for the PrometheusRule
+  labels: {}
+  # List of rules for Prometheus
+  rules: []
+  # - alert: keycloak-IngressHigh5xxRate
+  #   annotations:
+  #     message: The percentage of 5xx errors for keycloak over the last 5 minutes is over 1%.
+  #   expr: |
+  #     (
+  #       sum(
+  #         rate(
+  #           nginx_ingress_controller_response_duration_seconds_count{exported_namespace="mynamespace",ingress="mynamespace-keycloak",status=~"5[0-9]{2}"}[1m]
+  #         )
+  #       )
+  #       /
+  #       sum(
+  #         rate(
+  #           nginx_ingress_controller_response_duration_seconds_count{exported_namespace="mynamespace",ingress="mynamespace-keycloak"}[1m]
+  #         )
+  #       )
+  #     ) * 100 > 1
+  #   for: 5m
+  #   labels:
+  #     severity: warning
+
+autoscaling:
+  # If `true`, a autoscaling/v2beta2 HorizontalPodAutoscaler resource is created (requires Kubernetes 1.18 or above)
+  # Autoscaling seems to be most reliable when using KUBE_PING service discovery (see README for details)
+  # This disables the `replicas` field in the StatefulSet
+  enabled: false
+  # Additional HorizontalPodAutoscaler labels
+  labels: {}
+  # The minimum and maximum number of replicas for the Keycloak StatefulSet
+  minReplicas: 3
+  maxReplicas: 10
+  # The metrics to use for scaling
+  metrics:
+    - type: Resource
+      resource:
+        name: cpu
+        target:
+          type: Utilization
+          averageUtilization: 80
+  # The scaling policy to use. This will scale up quickly but only scale down a single Pod per 5 minutes.
+  # This is important because caches are usually only replicated to 2 Pods and if one of those Pods is terminated this will give the cluster time to recover.
+  behavior:
+    scaleDown:
+      stabilizationWindowSeconds: 300
+      policies:
+        - type: Pods
+          value: 1
+          periodSeconds: 300
+
+test:
+  # If `true`, test resources are created
+  enabled: false
+  image:
+    # The image for the test Pod
+    repository: docker.io/unguiculus/docker-python3-phantomjs-selenium
+    # The tag for the test Pod image
+    tag: v1
+    # The image pull policy for the test Pod image
+    pullPolicy: IfNotPresent
+  # SecurityContext for the entire test Pod
+  podSecurityContext:
+    fsGroup: 1000
+  # SecurityContext for the test container
+  securityContext:
+    runAsUser: 1000
+    runAsNonRoot: true
+  # See https://helm.sh/docs/topics/charts_hooks/#hook-deletion-policies
+  deletionPolicy: before-hook-creation
+
+readinessCheck:
+  wait_for:
+    - '{{ .Values.postgres.service.name }}'