From 8705700c3aee4d6f61b296f0a93affe98716ba59 Mon Sep 17 00:00:00 2001 From: Viet Nguyen Duc Date: Thu, 19 Sep 2024 22:20:43 +0000 Subject: [PATCH] chart(add): Grid scaler use trigger auth to secure GraphQL endpoint Signed-off-by: Viet Nguyen Duc --- Video/video_graphQLQuery.sh | 6 ++ Video/video_gridUrl.sh | 7 +-- charts/selenium-grid/CONFIGURATION.md | 6 +- charts/selenium-grid/README.md | 5 +- charts/selenium-grid/templates/_helpers.tpl | 14 ++++- .../selenium-grid/templates/_nameHelpers.tpl | 14 +++++ .../templates/basic-auth-secret.yaml | 21 +++++++ .../templates/distributor-deployment.yaml | 4 +- .../templates/event-bus-deployment.yaml | 8 ++- .../templates/hub-deployment.yaml | 12 ++-- .../templates/node-configmap.yaml | 2 - .../templates/router-deployment.yaml | 8 ++- charts/selenium-grid/templates/secrets.yaml | 6 +- .../templates/session-map-deployment.yaml | 10 ++-- .../templates/session-queue-deployment.yaml | 8 ++- .../selenium-grid/templates/trigger-auth.yaml | 25 ++++++++ charts/selenium-grid/values.yaml | 13 +++-- tests/charts/templates/render/dummy.yaml | 1 + .../templates/render/dummy_solution.yaml | 1 + tests/charts/templates/test.py | 58 ++++++++++++++----- 20 files changed, 172 insertions(+), 57 deletions(-) create mode 100644 charts/selenium-grid/templates/basic-auth-secret.yaml create mode 100644 charts/selenium-grid/templates/trigger-auth.yaml diff --git a/Video/video_graphQLQuery.sh b/Video/video_graphQLQuery.sh index 0c08f516ea..3382773dfe 100755 --- a/Video/video_graphQLQuery.sh +++ b/Video/video_graphQLQuery.sh @@ -14,6 +14,8 @@ if [[ -n ${GRAPHQL_ENDPOINT} ]] && [[ ! ${GRAPHQL_ENDPOINT} == */graphql ]]; the GRAPHQL_ENDPOINT="${GRAPHQL_ENDPOINT}/graphql" fi +BASIC_AUTH="$(echo -n "${SE_ROUTER_USERNAME}:${SE_ROUTER_USERNAME}" | base64)" + VIDEO_CAP_NAME=${VIDEO_CAP_NAME:-"se:recordVideo"} TEST_NAME_CAP=${TEST_NAME_CAP:-"se:name"} VIDEO_NAME_CAP=${VIDEO_NAME_CAP:-"se:videoName"} @@ -27,12 +29,16 @@ if [ -n "${GRAPHQL_ENDPOINT}" ]; then # Send GraphQL query endpoint_checks=$(curl --noproxy "*" -m ${max_time} -k -X POST \ -H "Content-Type: application/json" \ + -H "Authorization: Basic ${BASIC_AUTH}" \ --data '{"query":"{ session (id: \"'${SESSION_ID}'\") { id, capabilities, startTime, uri, nodeId, nodeUri, sessionDurationMillis, slot { id, stereotype, lastStarted } } } "}' \ -s "${GRAPHQL_ENDPOINT}" -o "/tmp/graphQL_${SESSION_ID}.json" -w "%{http_code}") current_check=$((current_check + 1)) # Check if the response contains "capabilities" if [[ "$endpoint_checks" = "404" ]] || [[ $current_check -eq $retry_time ]]; then break + else if [[ "$endpoint_checks" = "401" ]] || [[ $current_check -eq $retry_time ]]; then + echo "GraphQL endpoint requires authentication. Please provide the correct credentials to ENV variables SE_ROUTER_USERNAME and SE_ROUTER_PASSWORD" + break elif [[ "$endpoint_checks" = "200" ]] && [[ $(jq -e '.data.session.capabilities | fromjson | ."'se:vncEnabled'"' /tmp/graphQL_${SESSION_ID}.json >/dev/null) -eq 0 ]]; then break fi diff --git a/Video/video_gridUrl.sh b/Video/video_gridUrl.sh index f9cbd00286..537248c496 100755 --- a/Video/video_gridUrl.sh +++ b/Video/video_gridUrl.sh @@ -2,18 +2,15 @@ max_time=3 -if [ -n "${SE_ROUTER_USERNAME}" ] && [ -n "${SE_ROUTER_PASSWORD}" ]; then - BASIC_AUTH="${SE_ROUTER_USERNAME}:${SE_ROUTER_PASSWORD}@" -fi if [ "${SE_SUB_PATH}" = "/" ]; then SE_SUB_PATH="" fi grid_url="${SE_NODE_GRID_URL}" if [ -n "${SE_HUB_HOST:-$SE_ROUTER_HOST}" ] && [ -n "${SE_HUB_PORT:-$SE_ROUTER_PORT}" ]; then - grid_url=${SE_SERVER_PROTOCOL}://${BASIC_AUTH}${SE_HUB_HOST:-$SE_ROUTER_HOST}:${SE_HUB_PORT:-$SE_ROUTER_PORT}${SE_SUB_PATH} + grid_url=${SE_SERVER_PROTOCOL}://${SE_HUB_HOST:-$SE_ROUTER_HOST}:${SE_HUB_PORT:-$SE_ROUTER_PORT}${SE_SUB_PATH} elif [ -n "${DISPLAY_CONTAINER_NAME}" ] && [ "${SE_VIDEO_RECORD_STANDALONE}" = "true" ]; then - grid_url="${SE_SERVER_PROTOCOL}://${BASIC_AUTH}${DISPLAY_CONTAINER_NAME}:${SE_NODE_PORT:-4444}${SE_SUB_PATH}" # For standalone mode + grid_url="${SE_SERVER_PROTOCOL}://${DISPLAY_CONTAINER_NAME}:${SE_NODE_PORT:-4444}${SE_SUB_PATH}" # For standalone mode fi if [[ ${grid_url} == */ ]]; then diff --git a/charts/selenium-grid/CONFIGURATION.md b/charts/selenium-grid/CONFIGURATION.md index d98a1902ee..5eecdf1fab 100644 --- a/charts/selenium-grid/CONFIGURATION.md +++ b/charts/selenium-grid/CONFIGURATION.md @@ -66,9 +66,11 @@ A Helm chart for creating a Selenium Grid Server in Kubernetes | tls.disableHostnameVerification | bool | `true` | Disable verification the hostname included in the server's TLS/SSL certificates matches the hostnames provided | | registrationSecret.enabled | bool | `false` | Enable feature node registration secret to make sure that the node is one you control and not a rouge node | | registrationSecret.value | string | `"HappyTesting"` | The secret value to be used for node registration | +| basicAuth.nameOverride | string | `""` | External secret containing the basic auth username and password for reference | | basicAuth.enabled | bool | `false` | Enable or disable basic auth for the Hub/Router | | basicAuth.username | string | `"admin"` | Username for basic auth | | basicAuth.password | string | `"admin"` | Password for basic auth | +| basicAuth.annotations | object | `{}` | Annotations for basic auth secret resource | | isolateComponents | bool | `false` | Deploy Router, Distributor, EventBus, SessionMap and Nodes separately | | serviceAccount.create | bool | `true` | Create a service account for all components | | serviceAccount.nameOverride | string | `nil` | Override to use an external service account | @@ -300,6 +302,7 @@ A Helm chart for creating a Selenium Grid Server in Kubernetes | autoscaling.enabled | bool | `false` | Enable autoscaling. Implies installing KEDA | | autoscaling.enableWithExistingKEDA | bool | `false` | Enable autoscaling without automatically installing KEDA | | autoscaling.scalingType | string | `"job"` | Which type of KEDA scaling to use: job or deployment | +| autoscaling.authenticationRef | object | `{"name":""}` | Specify an external KEDA TriggerAuthentication resource is used for scaler triggers config. Apply for all browser nodes | | autoscaling.annotations | object | `{"helm.sh/hook":"post-install,post-upgrade,post-rollback","helm.sh/hook-weight":"1"}` | Annotations for KEDA resources: ScaledObject and ScaledJob | | autoscaling.patchObjectFinalizers.nameOverride | string | `nil` | Override the name of the patch job | | autoscaling.patchObjectFinalizers.enabled | bool | `true` | Enable patching finalizers for KEDA scaled resources. Workaround for Hook post-upgrade selenium-grid/templates/x-node-hpa.yaml failed: object is being deleted: scaledobjects.keda.sh "x" already exists | @@ -361,7 +364,6 @@ A Helm chart for creating a Selenium Grid Server in Kubernetes | chromeNode.scaledOptions | string | `nil` | Override the scaled options for chrome nodes | | chromeNode.scaledJobOptions | string | `nil` | Override the scaledJobOptions for chrome nodes | | chromeNode.scaledObjectOptions | string | `nil` | Override the scaledObjectOptions for chrome nodes | -| chromeNode.hpa.url | string | `"{{ template \"seleniumGrid.graphqlURL\" . }}"` | Graphql endpoint for the HPA to fetch metrics | | chromeNode.hpa.browserName | string | `"chrome"` | browserName from the capability | | chromeNode.hpa.sessionBrowserName | string | `"chrome"` | sessionBrowserName if the browserName is different from the sessionBrowserName | | chromeNode.hpa.platformName | string | `"linux"` | platformName from the capability | @@ -411,7 +413,6 @@ A Helm chart for creating a Selenium Grid Server in Kubernetes | firefoxNode.scaledOptions | string | `nil` | Override the scaled options for firefox nodes | | firefoxNode.scaledJobOptions | string | `nil` | Override the scaledJobOptions for firefox nodes | | firefoxNode.scaledObjectOptions | string | `nil` | Override the scaledObjectOptions for firefox nodes | -| firefoxNode.hpa.url | string | `"{{ template \"seleniumGrid.graphqlURL\" . }}"` | Graphql endpoint for the HPA to fetch metrics | | firefoxNode.hpa.browserName | string | `"firefox"` | browserName from the capability | | firefoxNode.hpa.sessionBrowserName | string | `"firefox"` | sessionBrowserName if the browserName is different from the sessionBrowserName | | firefoxNode.hpa.platformName | string | `"linux"` | platformName from the capability | @@ -461,7 +462,6 @@ A Helm chart for creating a Selenium Grid Server in Kubernetes | edgeNode.scaledOptions | string | `nil` | Override the scaled options for edge nodes | | edgeNode.scaledJobOptions | string | `nil` | Override the scaledJobOptions for edge nodes | | edgeNode.scaledObjectOptions | string | `nil` | Override the scaledObjectOptions for edge nodes | -| edgeNode.hpa.url | string | `"{{ template \"seleniumGrid.graphqlURL\" . }}"` | Graphql endpoint for the HPA to fetch metrics | | edgeNode.hpa.browserName | string | `"MicrosoftEdge"` | browserName from the capability | | edgeNode.hpa.sessionBrowserName | string | `"msedge"` | sessionBrowserName if the browserName is different from the sessionBrowserName | | edgeNode.hpa.platformName | string | `"linux"` | platformName from the capability | diff --git a/charts/selenium-grid/README.md b/charts/selenium-grid/README.md index 70222a736b..71d6442705 100644 --- a/charts/selenium-grid/README.md +++ b/charts/selenium-grid/README.md @@ -11,6 +11,7 @@ This chart enables the creation of a Selenium Grid Server in Kubernetes. * [Installing the Nightly chart](#installing-the-nightly-chart) * [Chart Release Name convention](#chart-release-name-convention) * [Enable Selenium Grid Autoscaling](#enable-selenium-grid-autoscaling) + * [Preview new changes in Selenium Grid Scaler implementation](#preview-new-changes-in-selenium-grid-scaler-implementation) * [Settings common for both `job` and `deployment` scalingType](#settings-common-for-both-job-and-deployment-scalingtype) * [Settings when scalingType with `deployment`](#settings-when-scalingtype-with-deployment-) * [Settings when scalingType with `job`](#settings-when-scalingtype-with-job) @@ -127,7 +128,9 @@ or [jobs](https://keda.sh/docs/latest/concepts/scaling-jobs/) and the charts sup chart support both modes. It is controlled with `autoscaling.scalingType` that can be set to either job (default) or deployment. -Preview new changes in Selenium Grid scaler implementation. Refer to [README](../../.keda/README.md) +### Preview new changes in Selenium Grid Scaler implementation + +Refer to [README](../../.keda/README.md) ### Settings common for both `job` and `deployment` scalingType diff --git a/charts/selenium-grid/templates/_helpers.tpl b/charts/selenium-grid/templates/_helpers.tpl index e893bd23a8..cf2a5ca586 100644 --- a/charts/selenium-grid/templates/_helpers.tpl +++ b/charts/selenium-grid/templates/_helpers.tpl @@ -243,6 +243,10 @@ triggers: {{- with .node.hpa }} {{- tpl (toYaml .) $ | nindent 6 }} {{- end }} + {{- if not .node.hpa.authenticationRef }} + authenticationRef: + name: {{ template "seleniumGrid.autoscaling.authenticationRef.fullname" $ }} + {{- end }} {{- end }} {{- end -}} @@ -358,7 +362,9 @@ template: - configMapRef: name: {{ template "seleniumGrid.server.configmap.fullname" $ }} - secretRef: - name: {{ include "seleniumGrid.common.secrets.fullname" $ }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- with .node.extraEnvFrom }} {{- tpl (toYaml .) $ | nindent 10 }} {{- end }} @@ -481,6 +487,8 @@ template: name: {{ template "seleniumGrid.recorder.configmap.fullname" $ }} - configMapRef: name: {{ template "seleniumGrid.server.configmap.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- if and $.Values.videoRecorder.uploader.enabled (empty $.Values.videoRecorder.uploader.name) }} - secretRef: name: {{ tpl (default (include "seleniumGrid.common.secrets.fullname" $) $.Values.uploaderConfigMap.secretVolumeMountName) $ }} @@ -538,6 +546,8 @@ template: envFrom: - configMapRef: name: {{ template "seleniumGrid.uploader.configmap.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} - secretRef: name: {{ tpl (default (include "seleniumGrid.common.secrets.fullname" $) $.Values.uploaderConfigMap.secretVolumeMountName) $ }} {{- with .uploader.extraEnvFrom }} @@ -621,7 +631,7 @@ Get the url of the grid. If the external url can be figured out from the ingress Get the url of the grid server in the cluster */}} {{- define "seleniumGrid.server.url" -}} -{{- $url := printf "%s://%s%s%s%s" (include "seleniumGrid.server.url.schema" .) (include "seleniumGrid.url.basicAuth" .) (include "seleniumGrid.server.url.host" .) (include "seleniumGrid.server.url.port" .) (include "seleniumGrid.url.subPath" .) -}} +{{- $url := printf "%s://%s%s%s" (include "seleniumGrid.server.url.schema" .) (include "seleniumGrid.server.url.host" .) (include "seleniumGrid.server.url.port" .) (include "seleniumGrid.url.subPath" .) -}} {{- $url }} {{- end -}} diff --git a/charts/selenium-grid/templates/_nameHelpers.tpl b/charts/selenium-grid/templates/_nameHelpers.tpl index 6778381d19..67c020c402 100644 --- a/charts/selenium-grid/templates/_nameHelpers.tpl +++ b/charts/selenium-grid/templates/_nameHelpers.tpl @@ -140,6 +140,20 @@ Common secrets cross components {{- tpl (default (include "seleniumGrid.component.name" (list "selenium-secrets" $)) .Values.secrets.nameOverride) $ | trunc 63 | trimSuffix "-" -}} {{- end -}} +{{/* +Basic authentication secrets for components fullname +*/}} +{{- define "seleniumGrid.basicAuth.secrets.fullname" -}} +{{- tpl (default (include "seleniumGrid.component.name" (list "selenium-basic-auth-secrets" $)) .Values.basicAuth.nameOverride) $ | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +KEDA TriggerAuthentication resource fullname +*/}} +{{- define "seleniumGrid.autoscaling.authenticationRef.fullname" -}} +{{- tpl (default (include "seleniumGrid.component.name" (list "selenium-scaler-trigger-auth" $)) .Values.autoscaling.authenticationRef.name) $ | trunc 63 | trimSuffix "-" -}} +{{- end -}} + {{/* Secret TLS fullname */}} diff --git a/charts/selenium-grid/templates/basic-auth-secret.yaml b/charts/selenium-grid/templates/basic-auth-secret.yaml new file mode 100644 index 0000000000..70c9b19c06 --- /dev/null +++ b/charts/selenium-grid/templates/basic-auth-secret.yaml @@ -0,0 +1,21 @@ +{{- if (not $.Values.basicAuth.nameOverride) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} + namespace: {{ .Release.Namespace }} +{{- with .Values.basicAuth.annotations }} + annotations: {{- toYaml . | nindent 4 }} +{{- end }} + labels: + {{- include "seleniumGrid.commonLabels" $ | nindent 4 }} + {{- with .Values.customLabels }} + {{- toYaml . | nindent 4 }} + {{- end }} +type: Opaque +data: +{{- if eq .Values.basicAuth.enabled true }} + SE_ROUTER_USERNAME: {{ .Values.basicAuth.username | b64enc }} + SE_ROUTER_PASSWORD: {{ .Values.basicAuth.password | b64enc }} +{{- end }} +{{- end }} diff --git a/charts/selenium-grid/templates/distributor-deployment.yaml b/charts/selenium-grid/templates/distributor-deployment.yaml index b1d9f35d76..210f8ab194 100644 --- a/charts/selenium-grid/templates/distributor-deployment.yaml +++ b/charts/selenium-grid/templates/distributor-deployment.yaml @@ -83,7 +83,9 @@ spec: - configMapRef: name: {{ template "seleniumGrid.server.configmap.fullname" . }} - secretRef: - name: {{ include "seleniumGrid.common.secrets.fullname" $ | quote }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- with .Values.components.extraEnvFrom }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/selenium-grid/templates/event-bus-deployment.yaml b/charts/selenium-grid/templates/event-bus-deployment.yaml index c441a32fb8..6ae4a6fba9 100644 --- a/charts/selenium-grid/templates/event-bus-deployment.yaml +++ b/charts/selenium-grid/templates/event-bus-deployment.yaml @@ -58,11 +58,13 @@ spec: {{- end }} envFrom: - configMapRef: - name: {{ template "seleniumGrid.logging.configmap.fullname" . }} + name: {{ template "seleniumGrid.logging.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.server.configmap.fullname" . }} + name: {{ template "seleniumGrid.server.configmap.fullname" $ }} - secretRef: - name: {{ template "seleniumGrid.common.secrets.fullname" . }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- with .Values.components.extraEnvFrom }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/selenium-grid/templates/hub-deployment.yaml b/charts/selenium-grid/templates/hub-deployment.yaml index 4d1b137adb..5e5981a4c2 100644 --- a/charts/selenium-grid/templates/hub-deployment.yaml +++ b/charts/selenium-grid/templates/hub-deployment.yaml @@ -130,15 +130,17 @@ spec: {{- end }} envFrom: - configMapRef: - name: {{ template "seleniumGrid.distributor.configmap.fullname" . }} + name: {{ template "seleniumGrid.distributor.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.router.configmap.fullname" . }} + name: {{ template "seleniumGrid.router.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.logging.configmap.fullname" . }} + name: {{ template "seleniumGrid.logging.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.server.configmap.fullname" . }} + name: {{ template "seleniumGrid.server.configmap.fullname" $ }} - secretRef: - name: {{ template "seleniumGrid.common.secrets.fullname" . }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- with .Values.hub.extraEnvFrom }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/selenium-grid/templates/node-configmap.yaml b/charts/selenium-grid/templates/node-configmap.yaml index 2fb804c721..d5a1953548 100644 --- a/charts/selenium-grid/templates/node-configmap.yaml +++ b/charts/selenium-grid/templates/node-configmap.yaml @@ -24,8 +24,6 @@ data: NODE_CONFIG_DIRECTORY: '{{ $.Values.nodeConfigMap.extraScriptsDirectory }}' SE_SUB_PATH: '{{ template "seleniumGrid.url.subPath" $ }}' SE_DRAIN_AFTER_SESSION_COUNT: '{{- and (eq (include "seleniumGrid.useKEDA" .) "true") (eq .Values.autoscaling.scalingType "job") | ternary "1" "0" -}}' - SE_NODE_GRID_URL: '{{ include "seleniumGrid.url" $ }}' - SE_NODE_GRID_GRAPHQL_URL: '{{ include "seleniumGrid.graphqlURL" $ }}' {{- if $.Values.videoRecorder.enabled }} SE_VIDEO_CONTAINER_NAME: {{ $.Values.videoRecorder.name | quote }} {{- end }} diff --git a/charts/selenium-grid/templates/router-deployment.yaml b/charts/selenium-grid/templates/router-deployment.yaml index a7e30913ec..5f479d641e 100644 --- a/charts/selenium-grid/templates/router-deployment.yaml +++ b/charts/selenium-grid/templates/router-deployment.yaml @@ -72,11 +72,13 @@ spec: {{- end }} envFrom: - configMapRef: - name: {{ template "seleniumGrid.logging.configmap.fullname" . }} + name: {{ template "seleniumGrid.logging.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.server.configmap.fullname" . }} + name: {{ template "seleniumGrid.server.configmap.fullname" $ }} - secretRef: - name: {{ template "seleniumGrid.common.secrets.fullname" . }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- with .Values.components.extraEnvFrom }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/selenium-grid/templates/secrets.yaml b/charts/selenium-grid/templates/secrets.yaml index b848c237d3..2b5c4c0c36 100644 --- a/charts/selenium-grid/templates/secrets.yaml +++ b/charts/selenium-grid/templates/secrets.yaml @@ -21,10 +21,8 @@ data: {{ $name }}: {{ tpl ($value) $ | b64enc }} {{- end }} {{- end }} -{{- if eq .Values.basicAuth.enabled true }} - SE_ROUTER_USERNAME: {{ .Values.basicAuth.username | b64enc }} - SE_ROUTER_PASSWORD: {{ .Values.basicAuth.password | b64enc }} -{{- end }} + SE_NODE_GRID_URL: {{ include "seleniumGrid.url" $ | b64enc }} + SE_NODE_GRID_GRAPHQL_URL: {{ include "seleniumGrid.graphqlURL" $ | b64enc }} {{- with $.Values.tls.trustStorePassword }} SE_JAVA_SSL_TRUST_STORE_PASSWORD: {{ . | b64enc }} {{- end }} diff --git a/charts/selenium-grid/templates/session-map-deployment.yaml b/charts/selenium-grid/templates/session-map-deployment.yaml index 00e2b3f5dd..043637928a 100644 --- a/charts/selenium-grid/templates/session-map-deployment.yaml +++ b/charts/selenium-grid/templates/session-map-deployment.yaml @@ -52,13 +52,15 @@ spec: {{- end }} envFrom: - configMapRef: - name: {{ template "seleniumGrid.logging.configmap.fullname" . }} + name: {{ template "seleniumGrid.logging.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.server.configmap.fullname" . }} + name: {{ template "seleniumGrid.server.configmap.fullname" $ }} - secretRef: - name: {{ template "seleniumGrid.common.secrets.fullname" . }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.eventBus.configmap.fullname" . }} + name: {{ template "seleniumGrid.eventBus.configmap.fullname" $ }} {{- with .Values.components.extraEnvFrom }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/selenium-grid/templates/session-queue-deployment.yaml b/charts/selenium-grid/templates/session-queue-deployment.yaml index 10bd525a0a..2f454687fe 100644 --- a/charts/selenium-grid/templates/session-queue-deployment.yaml +++ b/charts/selenium-grid/templates/session-queue-deployment.yaml @@ -51,11 +51,13 @@ spec: {{- end }} envFrom: - configMapRef: - name: {{ template "seleniumGrid.logging.configmap.fullname" . }} + name: {{ template "seleniumGrid.logging.configmap.fullname" $ }} - configMapRef: - name: {{ template "seleniumGrid.server.configmap.fullname" . }} + name: {{ template "seleniumGrid.server.configmap.fullname" $ }} - secretRef: - name: {{ template "seleniumGrid.common.secrets.fullname" . }} + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + - secretRef: + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} {{- with .Values.components.extraEnvFrom }} {{- toYaml . | nindent 12 }} {{- end }} diff --git a/charts/selenium-grid/templates/trigger-auth.yaml b/charts/selenium-grid/templates/trigger-auth.yaml new file mode 100644 index 0000000000..7872ec02bf --- /dev/null +++ b/charts/selenium-grid/templates/trigger-auth.yaml @@ -0,0 +1,25 @@ +{{- if and (eq (include "seleniumGrid.useKEDA" $) "true") (not $.Values.autoscaling.authenticationRef.name) }} +apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{ template "seleniumGrid.autoscaling.authenticationRef.fullname" $ }} + namespace: {{ .Release.Namespace }} + annotations: + {{- with $.Values.autoscaling.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "seleniumGrid.commonLabels" $ | nindent 4 }} + {{- include "seleniumGrid.autoscalingLabels" $ | nindent 4 }} +spec: + secretTargetRef: + - parameter: url + name: {{ template "seleniumGrid.common.secrets.fullname" $ }} + key: SE_NODE_GRID_GRAPHQL_URL + - parameter: username + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} + key: SE_ROUTER_USERNAME + - parameter: password + name: {{ template "seleniumGrid.basicAuth.secrets.fullname" $ }} + key: SE_ROUTER_PASSWORD +{{- end }} diff --git a/charts/selenium-grid/values.yaml b/charts/selenium-grid/values.yaml index e0bc1dcdb4..f4de98a7ef 100644 --- a/charts/selenium-grid/values.yaml +++ b/charts/selenium-grid/values.yaml @@ -103,12 +103,16 @@ registrationSecret: # Basic auth settings for Selenium Grid basicAuth: + # -- External secret containing the basic auth username and password for reference + nameOverride: "" # -- Enable or disable basic auth for the Hub/Router enabled: false # -- Username for basic auth username: admin # -- Password for basic auth password: admin + # -- Annotations for basic auth secret resource + annotations: {} # -- Deploy Router, Distributor, EventBus, SessionMap and Nodes separately isolateComponents: false @@ -780,6 +784,9 @@ autoscaling: enableWithExistingKEDA: false # -- Which type of KEDA scaling to use: job or deployment scalingType: job + # -- Specify an external KEDA TriggerAuthentication resource is used for scaler triggers config. Apply for all browser nodes + authenticationRef: + name: "" # -- Annotations for KEDA resources: ScaledObject and ScaledJob annotations: "helm.sh/hook": post-install,post-upgrade,post-rollback @@ -1004,8 +1011,6 @@ chromeNode: # -- Override the scaledObjectOptions for chrome nodes scaledObjectOptions: hpa: - # -- Graphql endpoint for the HPA to fetch metrics - url: '{{ template "seleniumGrid.graphqlURL" . }}' # -- browserName from the capability browserName: "chrome" # -- sessionBrowserName if the browserName is different from the sessionBrowserName @@ -1185,8 +1190,6 @@ firefoxNode: # -- Override the scaledObjectOptions for firefox nodes scaledObjectOptions: hpa: - # -- Graphql endpoint for the HPA to fetch metrics - url: '{{ template "seleniumGrid.graphqlURL" . }}' # -- browserName from the capability browserName: "firefox" # -- sessionBrowserName if the browserName is different from the sessionBrowserName @@ -1365,8 +1368,6 @@ edgeNode: # -- Override the scaledObjectOptions for edge nodes scaledObjectOptions: hpa: - # -- Graphql endpoint for the HPA to fetch metrics - url: '{{ template "seleniumGrid.graphqlURL" . }}' # -- browserName from the capability browserName: "MicrosoftEdge" # -- sessionBrowserName if the browserName is different from the sessionBrowserName diff --git a/tests/charts/templates/render/dummy.yaml b/tests/charts/templates/render/dummy.yaml index b9aeeb8beb..8aa6a3ee19 100644 --- a/tests/charts/templates/render/dummy.yaml +++ b/tests/charts/templates/render/dummy.yaml @@ -23,6 +23,7 @@ autoscaling: scalingType: deployment basicAuth: + nameOverride: "my-external-basic-auth-secret" enabled: true username: sysadmin password: strongPassword diff --git a/tests/charts/templates/render/dummy_solution.yaml b/tests/charts/templates/render/dummy_solution.yaml index 68ab41d48d..44443f8e7c 100644 --- a/tests/charts/templates/render/dummy_solution.yaml +++ b/tests/charts/templates/render/dummy_solution.yaml @@ -24,6 +24,7 @@ selenium-grid: scalingType: deployment basicAuth: + nameOverride: "my-external-basic-auth-secret" enabled: true username: sysadmin password: strongPassword diff --git a/tests/charts/templates/test.py b/tests/charts/templates/test.py index 615a945730..684d8f239b 100644 --- a/tests/charts/templates/test.py +++ b/tests/charts/templates/test.py @@ -2,6 +2,7 @@ import unittest import sys import logging +import base64 logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) @@ -52,14 +53,13 @@ def test_ingress_nginx_annotations(self): self.assertEqual(count, len(resources_name), "No ingress resources found") def test_sub_path_append_to_node_grid_url(self): - resources_name = ['{0}selenium-node-config'.format(RELEASE_NAME)] - count = 0 + resources_name = ['{0}selenium-secrets'.format(RELEASE_NAME),] for doc in LIST_OF_DOCUMENTS: - if doc['metadata']['name'] in resources_name and doc['kind'] == 'ConfigMap': - logger.info(f"Assert subPath is appended to Node env SE_NODE_GRID_URL") - self.assertTrue(doc['data']['SE_NODE_GRID_URL'] == 'https://sysadmin:strongPassword@10.10.10.10:8443/selenium') - count += 1 - self.assertEqual(count, len(resources_name), "No node config resources found") + if doc['metadata']['name'] in resources_name and doc['kind'] == 'Secret': + logger.info(f"Assert graphql url is constructed without basic auth in url") + base64_url = doc['data']['SE_NODE_GRID_URL'] + decoded_url = base64.b64decode(base64_url).decode('utf-8') + self.assertTrue(decoded_url == 'https://sysadmin:strongPassword@10.10.10.10:8443/selenium', decoded_url) def test_sub_path_set_to_grid_env_var(self): resources_name = ['{0}selenium-router'.format(RELEASE_NAME)] @@ -73,15 +73,14 @@ def test_sub_path_set_to_grid_env_var(self): is_present = True self.assertTrue(is_present, "ENV variable SE_SUB_PATH is not populated") - def test_graphql_url_for_autoscaling_constructed_correctly(self): - resources_name = ['{0}selenium-chrome-node'.format(RELEASE_NAME),] - count = 0 + def test_graphql_url_for_autoscaling_constructed_without_basic_auth_in_url(self): + resources_name = ['{0}selenium-secrets'.format(RELEASE_NAME),] for doc in LIST_OF_DOCUMENTS: - if doc['metadata']['name'] in resources_name and doc['kind'] == 'ScaledObject': - logger.info(f"Assert trigger url is set GraphQL endpoint in resource {doc['metadata']['name']}") - self.assertTrue(doc['spec']['triggers'][0]['metadata']['url'] == 'https://sysadmin:strongPassword@{0}selenium-router.default:4444/selenium/graphql'.format(RELEASE_NAME)) - count += 1 - self.assertEqual(count, len(resources_name), "GraphQL endpoint is not set correctly") + if doc['metadata']['name'] in resources_name and doc['kind'] == 'Secret': + logger.info(f"Assert graphql url is constructed without basic auth in url") + base64_url = doc['data']['SE_NODE_GRID_GRAPHQL_URL'] + decoded_url = base64.b64decode(base64_url).decode('utf-8') + self.assertTrue(decoded_url == 'https://{0}selenium-router.default:4444/selenium/graphql'.format(RELEASE_NAME), decoded_url) def test_distributor_new_session_thread_pool_size(self): resources_name = ['{0}selenium-distributor'.format(RELEASE_NAME)] @@ -301,6 +300,35 @@ def test_topologySpreadConstraints_in_all_components(self): count += 1 self.assertEqual(count, len(resources_name), "No deployment resources found with topologySpreadConstraints") + def test_not_create_basic_auth_secret_when_nameOverride_is_set(self): + resources_name = ['{0}selenium-basic-auth-secrets'.format(RELEASE_NAME)] + count = 0 + logger.info(f"Assert basic auth secret is not created when nameOverride is set") + for doc in LIST_OF_DOCUMENTS: + if doc['metadata']['name'] in resources_name and doc['kind'] == 'Secret': + count += 1 + self.assertEqual(count, 0, "Basic auth secret resource is created when nameOverride is set") + + def test_router_envFrom_secretRef_name_use_external_secret_when_basicAuth_nameOverride_is_set(self): + resources_name = ['{0}selenium-chrome-node'.format(RELEASE_NAME), + '{0}selenium-edge-node'.format(RELEASE_NAME), + '{0}selenium-firefox-node'.format(RELEASE_NAME), + '{0}selenium-distributor'.format(RELEASE_NAME), + '{0}selenium-event-bus'.format(RELEASE_NAME), + '{0}selenium-router'.format(RELEASE_NAME), + '{0}selenium-session-map'.format(RELEASE_NAME), + '{0}selenium-session-queue'.format(RELEASE_NAME),] + is_present = False + for doc in LIST_OF_DOCUMENTS: + if doc['metadata']['name'] in resources_name and doc['kind'] == 'Deployment': + logger.info(f"Assert envFrom secretRef name is set to external secret when basicAuth nameOverride is set") + list_env_from = doc['spec']['template']['spec']['containers'][0]['envFrom'] + for env in list_env_from: + if env.get('secretRef') is not None: + if env['secretRef']['name'] == 'my-external-basic-auth-secret': + is_present = True + self.assertTrue(is_present, "ENV variable from secretRef name is not set to external secret") + if __name__ == '__main__': failed = False try: