From 3b574bedcd6e4f4bb31c21b72249bfff81f670f9 Mon Sep 17 00:00:00 2001 From: Tomasz Baran <110602076+tomasz-baran@users.noreply.github.com> Date: Mon, 10 Oct 2022 11:15:52 +0200 Subject: [PATCH] Keycloak v19 updates (#3281) * Update tests * Fix for custom value of http.relativePath * Set Keycloak to be disabled by default * Change proxy mode * Idempotent autogenerated certs * Idempotent autogenerated certs - another approach * Add atomic option * Add loop label * Mount CA cert * Fix for restarting PG apps * Gather facts for postgresql * Better when condition * Set database.hostname to pgbouncer when enabled * Update alternative names of tls.crt * Add doc * Enable metrics by default for readinessProbe * Add podAntiAffinity to be just preferred * Add busybox image for dbchecker option * Use local repo also for dbchecker image * Update chart version to bump its appVersion --- ansible/playbooks/keycloak.yml | 4 + .../roles/keycloak/defaults/main.yml | 2 +- .../roles/keycloak/tasks/create-database.yml | 25 ++-- .../playbooks/roles/keycloak/tasks/main.yml | 3 +- .../templates/dynamic-chart-values.yml.j2 | 21 +-- .../requirements/aarch64/files.yml | 4 +- .../requirements/aarch64/images.yml | 4 + .../requirements/x86_64/files.yml | 4 +- .../requirements/x86_64/images.yml | 4 + cli/src/commands/Test.py | 2 +- docs/home/HOWTO.md | 3 + docs/home/howto/KEYCLOAK.md | 131 ++++++++++++++++++ .../defaults/configuration/features.yml | 2 +- .../defaults/configuration/image-registry.yml | 4 + .../defaults/configuration/keycloak.yml | 92 +++++++----- .../validation/configuration/keycloak.yml | 11 ++ .../spec/applications/applications_spec.rb | 12 -- .../applications/auth-service/auth-service.rb | 58 -------- tests/spec/spec/keycloak/keycloak_spec.rb | 42 ++++++ 19 files changed, 299 insertions(+), 129 deletions(-) create mode 100644 docs/home/howto/KEYCLOAK.md delete mode 100644 tests/spec/spec/applications/auth-service/auth-service.rb create mode 100644 tests/spec/spec/keycloak/keycloak_spec.rb diff --git a/ansible/playbooks/keycloak.yml b/ansible/playbooks/keycloak.yml index 06a5166698..f673a1015d 100644 --- a/ansible/playbooks/keycloak.yml +++ b/ansible/playbooks/keycloak.yml @@ -1,6 +1,10 @@ --- # Ansible playbook that deploys Keycloak on Kubernetes +- hosts: postgresql + gather_facts: true + tasks: [] + - hosts: 127.0.0.1 gather_facts: false become: false diff --git a/ansible/playbooks/roles/keycloak/defaults/main.yml b/ansible/playbooks/roles/keycloak/defaults/main.yml index f772e2e35b..403d1eb88d 100644 --- a/ansible/playbooks/roles/keycloak/defaults/main.yml +++ b/ansible/playbooks/roles/keycloak/defaults/main.yml @@ -1 +1 @@ -keycloak_helm_chart_file_name: keycloakx-1.6.0.tgz +keycloak_helm_chart_file_name: keycloakx-1.6.1.tgz diff --git a/ansible/playbooks/roles/keycloak/tasks/create-database.yml b/ansible/playbooks/roles/keycloak/tasks/create-database.yml index 6bc311d799..7f33850714 100644 --- a/ansible/playbooks/roles/keycloak/tasks/create-database.yml +++ b/ansible/playbooks/roles/keycloak/tasks/create-database.yml @@ -14,6 +14,8 @@ set_fact: postgres_primary: "{{ item.item }}" loop: "{{ in_recovery_state.results }}" + loop_control: + label: {in_recovery: "{{ item.in_recovery }}"} when: not item.in_recovery - name: Create DB objects @@ -42,18 +44,23 @@ - name: Refresh password file in PgPool and users list in PgBouncer when: - create_keycloak_user.changed - - groups.postgresql | count > 1 or "'pgbouncer' in _chart_values.database.hostname" + - applications_vars.specification.applications is defined + vars: + _pgbouncer_spec: >- + {{ applications_vars.specification.applications | selectattr('name', '==', 'pgbouncer') }} + _pgpool_spec: >- + {{ applications_vars.specification.applications | selectattr('name', '==', 'pgpool') }} block: - name: Restart PgPool deployment to update pool_passwd file + when: + - _pgpool_spec | count > 0 + - (_pgpool_spec | first).enabled command: | - kubectl rollout restart deployment/pgpool -n {{ _namespace }} - vars: - _namespace: >- - {{ (applications_vars.specification.applications | selectattr('name', '==', 'pgpool') | first).namespace }} + kubectl rollout restart deployment/pgpool -n {{ (_pgpool_spec | first).namespace }} - name: Restart PgBouncer deployment to update users list + when: + - _pgbouncer_spec | count > 0 + - (_pgbouncer_spec | first).enabled command: | - kubectl rollout restart deployment/pgbouncer -n {{ _namespace }} - vars: - _namespace: >- - {{ (applications_vars.specification.applications | selectattr('name', '==', 'pgbouncer') | first).namespace }} + kubectl rollout restart deployment/pgbouncer -n {{ (_pgbouncer_spec | first).namespace }} diff --git a/ansible/playbooks/roles/keycloak/tasks/main.yml b/ansible/playbooks/roles/keycloak/tasks/main.yml index 122e97e17b..e7b0af85b8 100644 --- a/ansible/playbooks/roles/keycloak/tasks/main.yml +++ b/ansible/playbooks/roles/keycloak/tasks/main.yml @@ -8,7 +8,7 @@ include_vars: file: roles/applications/vars/main.yml name: applications_vars - when: groups.postgresql | count > 1 or "'pgbouncer' in _chart_values.database.hostname" + when: groups.applications is defined - name: Include database configuration when Epiphany storage is used include_tasks: create-database.yml @@ -40,6 +40,7 @@ helm upgrade keycloak {{ download_directory }}/{{ keycloak_helm_chart_file_name }} \ -f {{ vault_location }}/keycloak-chart-values.yml \ -n {{ specification.namespace }} \ + --atomic \ --create-namespace \ --install diff --git a/ansible/playbooks/roles/keycloak/templates/dynamic-chart-values.yml.j2 b/ansible/playbooks/roles/keycloak/templates/dynamic-chart-values.yml.j2 index bac4e88b3d..affd81810c 100644 --- a/ansible/playbooks/roles/keycloak/templates/dynamic-chart-values.yml.j2 +++ b/ansible/playbooks/roles/keycloak/templates/dynamic-chart-values.yml.j2 @@ -1,21 +1,26 @@ #jinja2: lstrip_blocks: True -# Keep data structure in sync with Helm chart's values. -# ref: https://raw.githubusercontent.com/codecentric/helm-charts/keycloakx-1.6.0/charts/keycloakx/values.yaml +{#- +This file is used only locally to override chart's values defined in `configuration/keycloak` doc. + +Keep data structure in sync with Helm chart's values. +ref: https://github.com/codecentric/helm-charts/blob/keycloakx-1.6.1/charts/keycloakx/values.yaml +-#} {% if specification.image_registry.use_local %} image: repository: {{ image_registry_address }}/{{ _chart_values.image.repository }} -{% else %} -image: - repository: {{ _chart_values.image.repository }} +dbchecker: + image: + repository: {{ image_registry_address }}/{{ _chart_values.dbchecker.image.repository }} {% endif %} {% if specification.database.epiphany_managed and _chart_values.database.hostname | lower == 'autoconfigured' %} database: - {% if groups.postgresql | count == 1 %} - hostname: {{ hostvars[groups.postgresql[0]].ansible_default_ipv4.address }} + {% set pgbouncer_items = applications_vars.specification.applications | default([]) | selectattr('name', '==', 'pgbouncer') %} + {% if pgbouncer_items | count > 0 and pgbouncer_items[0].enabled is defined and pgbouncer_items[0].enabled %} + hostname: {{ pgbouncer_items[0].pgbouncer.env.DB_HOST }} {% else %} - hostname: {{ (applications_vars.specification.applications | selectattr('name', '==', 'pgbouncer') | first).pgbouncer.env.DB_HOST }} + hostname: {{ hostvars[groups.postgresql[0]].ansible_default_ipv4.address }} {% endif %} {% endif %} diff --git a/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/files.yml b/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/files.yml index ed4784cc9c..af8e21bfcd 100644 --- a/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/files.yml +++ b/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/files.yml @@ -71,8 +71,8 @@ files: keycloak: options: - - url: 'https://github.com/codecentric/helm-charts/releases/download/keycloakx-1.6.0/keycloakx-1.6.0.tgz' - sha256: 11c5536008f47257ea6255d6129948df1178c7d009519b6a460a35995e74356a + - url: 'https://github.com/codecentric/helm-charts/releases/download/keycloakx-1.6.1/keycloakx-1.6.1.tgz' + sha256: 9a29ccf04343b2b1b8a877e9259aa07332606945017d8c17d85702506aac38f3 deps: [keycloak] # --- OpenSearch Bundle --- diff --git a/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/images.yml b/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/images.yml index b9e5807001..53fd35e3a8 100644 --- a/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/images.yml +++ b/ansible/playbooks/roles/repository/files/download-requirements/requirements/aarch64/images.yml @@ -14,6 +14,10 @@ images: sha1: 003cefb9c3309c55fa67f68067db9355750513d6 keycloak: + # optional - can be used by Helm chart to check database readiness at startup + 'docker.io/busybox:1.32': + sha1: 90402d70a03ed8248ec353ec8158da8cc3e8066a + 'quay.io/keycloak/keycloak:19.0.2': sha1: 484d69fc4690b4816ec4c1ad66ad2352017aa19c diff --git a/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/files.yml b/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/files.yml index ed2b7157fb..0249778ccf 100644 --- a/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/files.yml +++ b/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/files.yml @@ -83,8 +83,8 @@ files: keycloak: options: - - url: 'https://github.com/codecentric/helm-charts/releases/download/keycloakx-1.6.0/keycloakx-1.6.0.tgz' - sha256: 11c5536008f47257ea6255d6129948df1178c7d009519b6a460a35995e74356a + - url: 'https://github.com/codecentric/helm-charts/releases/download/keycloakx-1.6.1/keycloakx-1.6.1.tgz' + sha256: 9a29ccf04343b2b1b8a877e9259aa07332606945017d8c17d85702506aac38f3 deps: [keycloak] # --- OpenSearch Bundle --- diff --git a/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/images.yml b/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/images.yml index 02f0ce6b25..2b69625ee5 100644 --- a/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/images.yml +++ b/ansible/playbooks/roles/repository/files/download-requirements/requirements/x86_64/images.yml @@ -20,6 +20,10 @@ images: sha1: 2705b05f9ac0bda6a4136fc8d66dc99295daa95d keycloak: + # optional - can be used by Helm chart to check database readiness at startup + 'docker.io/busybox:1.32': + sha1: 0355284f96b69167cc50641845691ef737724414 + 'quay.io/keycloak/keycloak:19.0.2': sha1: ffbe5f8fff32eaa1f14043c5aa5f558a4ba17b52 diff --git a/cli/src/commands/Test.py b/cli/src/commands/Test.py index a785e624a1..d476b99438 100644 --- a/cli/src/commands/Test.py +++ b/cli/src/commands/Test.py @@ -56,7 +56,7 @@ def __is_env_preparation_needed(self) -> bool: Check whether additional actions are needed in order to run selected test groups """ if self.kubeconfig_remote_path: - kubectl_groups = ['applications', 'kubernetes_master'] + kubectl_groups = ('applications', 'keycloak', 'kubernetes_master') if any(group in kubectl_groups for group in self.selected_groups): return True if 'all' in self.selected_groups and any(group in kubectl_groups for group in self.available_groups): diff --git a/docs/home/HOWTO.md b/docs/home/HOWTO.md index ed218e5f19..a5314e806b 100644 --- a/docs/home/HOWTO.md +++ b/docs/home/HOWTO.md @@ -48,6 +48,9 @@ - [Persistent storage](./howto/kubernetes/PERSISTENT_STORAGE.md) - [Certificate management](./howto/kubernetes/CERTIFICATES.md) +- [Keycloak](./howto/KEYCLOAK.md) + - [How to run Keycloak](./howto/KEYCLOAK.md#how-to-run-keycloak) + - [Helm](./howto/HELM.md) - [Helm "system" chart repository](./howto/HELM.md#helm-system-chart-repository) - [Installing Helm charts from the "system" repository](./howto/HELM.md#installing-helm-charts-from-the-system-repository) diff --git a/docs/home/howto/KEYCLOAK.md b/docs/home/howto/KEYCLOAK.md new file mode 100644 index 0000000000..b19741277a --- /dev/null +++ b/docs/home/howto/KEYCLOAK.md @@ -0,0 +1,131 @@ +# Keycloak + +## How to run Keycloak + +1. Enable `kubernetes_master`, `kubernetes_node`, `repository` and `postgresql` components in the input manifest (yaml) + by increasing `count` value. Enable `load_balancer` if needed. + + ```yaml + kind: epiphany-cluster + title: Epiphany cluster Config + provider: azure + name: default + specification: + components: + repository: + count: 1 + kubernetes_master: + count: 1 + kubernetes_node: + count: 2 + postgresql: + count: 2 + load_balancer: + count: 1 + ``` + +2. Enable `keycloak` in `configuration/features` doc: + + ```yaml + kind: configuration/features + title: Features to be enabled/disabled + name: default + specification: + features: + ... + - name: keycloak + enabled: true + ``` + +3. Enable PostgreSQL related applications by setting `enabled: true` and adjust other parameters in `configuration/applications` + doc. + + The default applications configuration is + available [here](https://github.com/epiphany-platform/epiphany/blob/develop/schema/common/defaults/configuration/applications.yml) + + Note: To get working with Pgbouncer, Keycloak requires Pgbouncer configuration parameter `POOL_MODE` set to `session`, + see [Installing Pgbouncer and Pgpool](DATABASES.md#installing-pgbouncer-and-pgpool) section. The reason is that Keycloak + uses SET SQL statements. For details, see [SQL feature map for pooling modes](https://www.pgbouncer.org/features.html). + +4. Adjust default Keycloak settings to your needs by editing `configuration/keycloak` doc. + + By default, only HTTPS protocol is enabled and auto-generated TLS certificate is used. + + You can provide your own certificate: + + ```yaml + kind: configuration/keycloak + title: Keycloak Config + name: default + specification: + ... + chart_values: + secrets: + ... + tls-certs: + type: kubernetes.io/tls + data: + # the data is abbreviated in this example + # `ca.crt` is optional (not used by Keycloak) + ca.crt: | + LS0tLS1CRUdJTiBDRVJUSUZJQ0FUR... + # a server certificate or certificate chain in PEM format + tls.crt: | + MIIC2DCCAcCgAwIBAgIBATANBgkqh... + tls.key: | + MIIEpgIBAAKCAQEA7yn3bRHQ5FHMQ... + ``` + + All default passwords should be changed. You may need to adjust `specification.chart_values.resources`. + + By default, Epiphany managed PostgreSQL cluster is used for Keycloak database + and `specification.chart_values.database.hostname` is set to `AUTOCONFIGURED` + which means: `pgbouncer` `ClusterIP` service is used if enabled, otherwise the first host of `postgresql` group. + +5. Run `epicli apply` on your input manifest. + +6. Reconfigure HA proxy (if needed). + + By default, Keycloak listens only for HTTPS traffic on port which is exposed via `NodePort` service. + + Some Keycloak features rely on the assumption that the remote address of the HTTP request connecting to Keycloak + is the real IP address of the client machine. + + When you have HAProxy in front of Keycloak, this might not be the case, so we need to ensure that the X-Forwarded-For + header is set by HAProxy. In order to achive this the content has to be modified by HAProxy. For that reason, + TLS is terminated by HAProxy and the modified content is re-encrypted. Different keys and certificates are used on HAProxy + as well as on Keycloak. + + Example of backend configuration: + + ```text + backend keycloak + balance roundrobin + option forwardfor + server kubernetes-node-vm-0 10.1.1.151:30104 check ssl verify required ca-file /etc/ssl/haproxy/epiphany-keycloak-ca.crt + server kubernetes-node-vm-1 10.1.1.235:30104 check ssl verify required ca-file /etc/ssl/haproxy/epiphany-keycloak-ca.crt + ``` + + It's recommended to not expose some endpoints, see https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations. + + Example of frontend configuration: + + ```text + frontend https_fe + bind *:443 ssl crt /etc/ssl/haproxy/cert.crt + # Do not expose health checks & metrics, see https://www.keycloak.org/server/reverseproxy#_exposed_path_recommendations + http-request deny if { path_beg /auth/health/ } || { path /auth/health } || { path_beg /auth/metrics/ } || { path /auth/metrics } + use_backend keycloak if { path -m beg /auth/ } || { path /auth } + ``` + +7. Log into GUI + + Note: Accessing the Keycloak GUI depends on your configuration. + + One method for reaching GUI is to use SSH tunnel with forwarding `NodePort`: + + ```bash + ssh -L 30104:localhost:30104 @ -i + ``` + + GUI should be reachable at: https://localhost:30104/auth diff --git a/schema/common/defaults/configuration/features.yml b/schema/common/defaults/configuration/features.yml index 204f3ae403..418b01b7ae 100644 --- a/schema/common/defaults/configuration/features.yml +++ b/schema/common/defaults/configuration/features.yml @@ -51,6 +51,6 @@ specification: - name: applications enabled: true - name: keycloak - enabled: true + enabled: false - name: rook enabled: false diff --git a/schema/common/defaults/configuration/image-registry.yml b/schema/common/defaults/configuration/image-registry.yml index 2d8c2e7da8..4c7ab66bf6 100644 --- a/schema/common/defaults/configuration/image-registry.yml +++ b/schema/common/defaults/configuration/image-registry.yml @@ -18,6 +18,8 @@ specification: - name: "bitnami/pgbouncer:1.16.0" file_name: pgbouncer-1.16.0.tar keycloak: + - name: "docker.io/busybox:1.32" + file_name: busybox-1.32.tar - name: "quay.io/keycloak/keycloak:19.0.2" file_name: keycloak-19.0.2.tar kubernetes-master: @@ -163,6 +165,8 @@ specification: - name: "rabbitmq:3.8.9" file_name: rabbitmq-3.8.9.tar keycloak: + - name: "docker.io/busybox:1.32" + file_name: busybox-1.32.tar - name: "quay.io/keycloak/keycloak:19.0.2" file_name: keycloak-19.0.2.tar kubernetes-master: diff --git a/schema/common/defaults/configuration/keycloak.yml b/schema/common/defaults/configuration/keycloak.yml index fa94ca9ca2..ef07688eb0 100644 --- a/schema/common/defaults/configuration/keycloak.yml +++ b/schema/common/defaults/configuration/keycloak.yml @@ -6,14 +6,14 @@ specification: namespace: keycloak database: - epiphany_managed: true + epiphany_managed: true # if true, Keycloak database and user are created by Epiphany in `postgresql` component image_registry: use_local: true chart_values: # Refs: - # - https://github.com/codecentric/helm-charts/tree/keycloakx-1.6.0/charts/keycloakx + # - https://github.com/codecentric/helm-charts/tree/keycloakx-1.6.1/charts/keycloakx # - https://github.com/epam/edp-install/blob/d01c15ea20906cd336c781ae29c4adaeab06df48/helmfiles/releases/keycloak.yaml # - https://github.com/bitnami/charts/tree/2a326f1a1ea5abbe4e8486666ba4f813264c98cf/bitnami/keycloak # - https://www.keycloak.org/server/all-config @@ -61,6 +61,24 @@ specification: value: /mnt/certificates/tls.key {%- endraw %} + # Pod affinity + affinity: |- + {%- raw -%} + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchLabels: + {{- include "keycloak.selectorLabels" . | nindent 10 }} + topologyKey: kubernetes.io/hostname + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + {{- include "keycloak.selectorLabels" . | nindent 12 }} + topologyKey: topology.kubernetes.io/zone + {%- endraw %} + # Probes configuration based on https://github.com/keycloak/keycloak/blob/19.0/operator/src/main/java/org/keycloak/operator/controllers/KeycloakDeployment.java livenessProbe: |- @@ -72,11 +90,7 @@ specification: - --fail - --silent - --insecure - {{ if and (.Values.http.relativePath) (ne .Values.http.relativePath "/") }} - - https://127.0.0.1:8443/{{ .Values.http.relativePath | trimSuffix "/" }}/health/live - {{ else }} - - https://127.0.0.1:8443/health/live - {{ end }} + - https://127.0.0.1:8443{{ .Values.http.relativePath | trimSuffix "/" }}/health/live {% endraw %} initialDelaySeconds: 0 periodSeconds: 2 @@ -91,11 +105,7 @@ specification: - --fail - --silent - --insecure - {{ if and (.Values.http.relativePath) (ne .Values.http.relativePath "/") }} - - https://127.0.0.1:8443/{{ .Values.http.relativePath | trimSuffix "/" }}/health/ready - {{ else }} - - https://127.0.0.1:8443/health/ready - {{ end }} + - https://127.0.0.1:8443{{ .Values.http.relativePath | trimSuffix "/" }}/health/ready {% endraw %} initialDelaySeconds: 10 periodSeconds: 2 @@ -110,11 +120,7 @@ specification: - --fail - --silent - --insecure - {{ if and (.Values.http.relativePath) (ne .Values.http.relativePath "/") }} - - https://127.0.0.1:8443/{{ .Values.http.relativePath | trimSuffix "/" }}/health - {{ else }} - - https://127.0.0.1:8443/health - {{ end }} + - https://127.0.0.1:8443{{ .Values.http.relativePath | trimSuffix "/" }}/health {% endraw %} initialDelaySeconds: 15 periodSeconds: 1 @@ -125,19 +131,19 @@ specification: # cpu: 1000m memory: 512Mi requests: - cpu: 50m + cpu: 50m # minimal usage (when idle): ~ 38m memory: 512Mi extraVolumes: |- - - name: keycloak-tls-certificates + - name: keycloak-tls-certs secret: defaultMode: 420 optional: false - secretName: {% raw %}{{ include "keycloak.fullname" . }}{% endraw %}-tls-certificates + secretName: {% raw %}{{ include "keycloak.fullname" . }}{% endraw %}-tls-certs extraVolumeMounts: |- - mountPath: /mnt/certificates - name: keycloak-tls-certificates + name: keycloak-tls-certs # Configuration for secrets that should be created secrets: @@ -146,27 +152,42 @@ specification: stringData: username: keycloak-admin password: PASSWORD_TO_CHANGE - ca: + tls-certs: + type: kubernetes.io/tls stringData: ca.crt: |- {%- raw -%} {{- $ca := genCA "epiphany-keycloak-ca" 3650 }} {{- $_ := set $.Values "_shared" dict }} {{- $_ := set $.Values._shared "ca" $ca }} - {{- $ca.Cert -}} + {{- $caCert := $ca.Cert }} + {{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-%s" (include "keycloak.fullname" .) "tls-certs")) }} + {{- if $secret }} + {{- $caCert = index $secret.data "ca.crt" | b64dec }} + {{- end }} + {{- $caCert -}} {%- endraw %} - tls-certificates: - type: kubernetes.io/tls - stringData: tls.crt: |- {%- raw -%} - {{- $altNames := list "keycloak.keycloak.svc.cluster.local" "keycloak" }} - {{- $crt := genSignedCert "keycloak.keycloak.svc.cluster.local" nil $altNames 3650 $.Values._shared.ca }} + {{- $altNames := list "keycloak-0.keycloak-headless.keycloak.svc.cluster.local" "keycloak-0.keycloak-headless.keycloak" "keycloak-0.keycloak-headless" "keycloak-0" "keycloak-1.keycloak-headless.keycloak.svc.cluster.local" "keycloak-1.keycloak-headless.keycloak" "keycloak-1.keycloak-headless" "keycloak-1" "keycloak-headless.keycloak.svc.cluster.local" "keycloak-headless.keycloak" "keycloak-headless" "keycloak-http.keycloak.svc.cluster.local" "keycloak-http.keycloak" "keycloak-http" }} + {{- $crt := genSignedCert "keycloak-http.keycloak.svc.cluster.local" nil $altNames 3650 $.Values._shared.ca }} {{- $_ := set $.Values._shared "crt" $crt }} - {{- $crt.Cert -}} + {{- $tlsCert := $crt.Cert }} + {{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-%s" (include "keycloak.fullname" .) "tls-certs")) }} + {{- if $secret }} + {{- $tlsCert = index $secret.data "tls.crt" | b64dec }} + {{- end }} + {{- $tlsCert -}} {%- endraw %} tls.key: |- - {% raw %}{{ $.Values._shared.crt.Key }}{% endraw %} + {%- raw -%} + {{- $tlsKey := $.Values._shared.crt.Key }} + {{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-%s" (include "keycloak.fullname" .) "tls-certs")) }} + {{- if $secret }} + {{- $tlsKey = index $secret.data "tls.key" | b64dec }} + {{- end }} + {{- $tlsKey -}} + {%- endraw %} service: type: NodePort httpNodePort: 30103 @@ -174,7 +195,10 @@ specification: # Check database readiness at startup dbchecker: - enabled: false # requires additional image + enabled: false + image: + repository: docker.io/busybox + tag: '1.32' database: vendor: postgres @@ -187,10 +211,10 @@ specification: # ref: https://www.keycloak.org/server/reverseproxy proxy: enabled: true - mode: passthrough + mode: reencrypt metrics: - enabled: false + enabled: true # used by readinessProbe http: - relativePath: / # /auth before Quarkus + relativePath: /auth # for backward compatibility and HAProxy diff --git a/schema/common/validation/configuration/keycloak.yml b/schema/common/validation/configuration/keycloak.yml index 1bf10666c9..71a2463bc5 100644 --- a/schema/common/validation/configuration/keycloak.yml +++ b/schema/common/validation/configuration/keycloak.yml @@ -132,8 +132,19 @@ properties: properties: enabled: type: boolean + image: + type: object + properties: + repository: + type: string + tag: + type: string + required: + - repository + - tag required: - enabled + - image database: type: object properties: diff --git a/tests/spec/spec/applications/applications_spec.rb b/tests/spec/spec/applications/applications_spec.rb index c4a5331def..ef33fa9dcb 100644 --- a/tests/spec/spec/applications/applications_spec.rb +++ b/tests/spec/spec/applications/applications_spec.rb @@ -1,7 +1,6 @@ require 'spec_helper' require 'securerandom' require 'applications/rabbitmq/rabbitmq' -require 'applications/auth-service/auth-service' require 'applications/pgpool/pgpool' if !readDataYaml('configuration/applications')['specification']['applications'].select do |i| @@ -15,17 +14,6 @@ end -if !readDataYaml('configuration/applications')['specification']['applications'].select do |i| - i['name'] == 'auth-service' -end.empty? && - readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['enabled'] - - callAuthServiceDeploymentTests - -end - if !readDataYaml('configuration/applications')['specification']['applications'].select do |i| i['name'] == 'pgpool' end.empty? && diff --git a/tests/spec/spec/applications/auth-service/auth-service.rb b/tests/spec/spec/applications/auth-service/auth-service.rb deleted file mode 100644 index 70ec8adf20..0000000000 --- a/tests/spec/spec/applications/auth-service/auth-service.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'spec_helper' -require 'securerandom' - -def callAuthServiceDeploymentTests - service_port = readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['service']['port'] - service_replicas = readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['service']['replicas'] - service_namespace = readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['service']['namespace'] - service_name = readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['service']['name'] - service_admin_user = readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['service']['admin_user'] - service_admin_password = readDataYaml('configuration/applications')['specification']['applications'].detect do |i| - i['name'] == 'auth-service' - end ['service']['admin_password'] - - describe 'Checking if auth-service is running' do - describe command("kubectl get services --namespace=#{service_namespace}") do - its(:stdout) { should match(/#{service_name}/) } - end - end - - describe 'Checking if the ports are open' do - describe port(service_port) do - let(:disable_sudo) { false } - it { should be_listening } - end - end - - describe 'Checking the status of auth-service pods - all pods should be running' do - describe command("kubectl get pods --namespace=#{service_namespace} --field-selector=status.phase=Running | grep #{service_name} | wc -l") do - it 'is expected to be equal' do - expect(subject.stdout.to_i).to eq service_replicas - end - its(:exit_status) { should eq 0 } - end - end - - describe 'Checking the auth-service API connection' do - describe command("curl -o /dev/null -s -w '%{http_code}' -k https://#{host_inventory['hostname']}:#{service_port}/auth/") do - it 'is expected to be equal' do - expect(subject.stdout.to_i).to eq 200 - end - end - describe command("curl -k -d \"client_id=admin-cli\" -d \"username=#{service_admin_user}\" -d \"password=#{service_admin_password}\" \ - -d \"grant_type=password\" https://#{host_inventory['hostname']}:#{service_port}/auth/realms/master/protocol/openid-connect/token") do - its(:stdout) { should match(/access_token/) } - its(:exit_status) { should eq 0 } - end - end -end diff --git a/tests/spec/spec/keycloak/keycloak_spec.rb b/tests/spec/spec/keycloak/keycloak_spec.rb new file mode 100644 index 0000000000..0a06308234 --- /dev/null +++ b/tests/spec/spec/keycloak/keycloak_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' +require 'securerandom' + +config_spec = readDataYaml('configuration/keycloak')['specification'] +chart_values = config_spec['chart_values'] +service_port = chart_values['service']['httpsNodePort'] +service_replicas = chart_values['replicas'] +service_namespace = config_spec['namespace'] +chart_fullname = chart_values['fullnameOverride'] +service_name = "#{chart_fullname}-http" +http_settings = chart_values.fetch('http', {}) # optional setting +url_relative_path = http_settings.fetch('relativePath', '/auth').chomp('/') + +describe 'Check if service is present' do + describe command("kubectl get services --namespace=#{service_namespace}") do + its(:stdout) { should match(/#{service_name}/) } + end +end + +describe 'Check if port is open' do + describe port(service_port) do + let(:disable_sudo) { false } + it { should be_listening } + end +end + +describe 'Check status - all pods should be running' do + describe command("kubectl get pods --namespace=#{service_namespace} --field-selector=status.phase=Running | grep #{chart_fullname} | wc -l") do + it 'is expected to be equal' do + expect(subject.stdout.to_i).to eq service_replicas + end + its(:exit_status) { should eq 0 } + end +end + +describe 'Check service URL' do + describe command("curl -o /dev/null -s -w '%{http_code}' -k https://#{host_inventory['hostname']}:#{service_port}#{url_relative_path}/") do + it 'is expected to be equal' do + expect(subject.stdout.to_i).to eq 200 + end + end +end