From 9f180cc0e979dcc8abe0f71db73667acb15ca8e0 Mon Sep 17 00:00:00 2001 From: Tomaz <1279460+tomazb@users.noreply.github.com> Date: Tue, 9 Jun 2026 17:15:30 +0200 Subject: [PATCH 1/2] fix: harden security-sensitive deployment paths --- Dockerfile.helm-runner | 17 ++ deploy/deploy.sh | 50 ++++- .../openshiftpulse/templates/deployment.yaml | 5 +- .../templates/nginx-config.yaml | 28 +-- deploy/helm/openshiftpulse/values.yaml | 6 + deploy/helm/pulse/Chart.lock | 6 +- deploy/helm/pulse/Chart.yaml | 2 +- .../charts/openshift-sre-agent-1.13.0.tgz | Bin 0 -> 6172 bytes .../charts/openshift-sre-agent-2.6.0.tgz | Bin 7120 -> 0 bytes .../pulse/charts/openshiftpulse-4.7.0.tgz | Bin 7020 -> 7057 bytes deploy/helm/pulse/values.yaml | 14 ++ deploy/test-helm.sh | 42 ++++- public/config.js | 1 + public/index.html | 7 +- rspack.config.ts | 27 +-- src/dev/__tests__/helmRepoProxy.test.ts | 31 ++++ src/dev/helmRepoProxy.ts | 171 ++++++++++++++++++ src/kubeview/config/runtime.ts | 21 +++ src/kubeview/views/create/HelmTab.tsx | 57 +++--- .../create/__tests__/helmInstall.test.ts | 42 +++++ src/kubeview/views/create/helmInstall.ts | 135 ++++++++++++++ 21 files changed, 581 insertions(+), 81 deletions(-) create mode 100644 Dockerfile.helm-runner create mode 100644 deploy/helm/pulse/charts/openshift-sre-agent-1.13.0.tgz delete mode 100644 deploy/helm/pulse/charts/openshift-sre-agent-2.6.0.tgz create mode 100644 public/config.js create mode 100644 src/dev/__tests__/helmRepoProxy.test.ts create mode 100644 src/dev/helmRepoProxy.ts create mode 100644 src/kubeview/config/runtime.ts create mode 100644 src/kubeview/views/create/__tests__/helmInstall.test.ts create mode 100644 src/kubeview/views/create/helmInstall.ts diff --git a/Dockerfile.helm-runner b/Dockerfile.helm-runner new file mode 100644 index 00000000..f10fdd45 --- /dev/null +++ b/Dockerfile.helm-runner @@ -0,0 +1,17 @@ +FROM registry.access.redhat.com/ubi9/ubi-minimal:latest + +ARG HELM_VERSION=3.15.4 +ARG TARGETARCH=amd64 + +RUN microdnf install -y ca-certificates curl gzip tar && microdnf clean all +RUN curl -fsSLo /tmp/helm.tar.gz "https://get.helm.sh/helm-v${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" \ + && curl -fsSLo /tmp/helm.tar.gz.sha256sum "https://get.helm.sh/helm-v${HELM_VERSION}-linux-${TARGETARCH}.tar.gz.sha256sum" \ + && cd /tmp \ + && sha256sum -c helm.tar.gz.sha256sum \ + && tar -xzf helm.tar.gz \ + && install -m 0755 "linux-${TARGETARCH}/helm" /usr/local/bin/helm \ + && rm -rf /tmp/helm.tar.gz /tmp/helm.tar.gz.sha256sum "/tmp/linux-${TARGETARCH}" + +USER 1001 +WORKDIR /tmp/work +ENTRYPOINT ["/usr/local/bin/helm"] diff --git a/deploy/deploy.sh b/deploy/deploy.sh index aaf40380..e285d4e4 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -16,7 +16,7 @@ set -euo pipefail DEPLOY_START=$(date +%s) VALUES_FILE="/tmp/pulse-deploy-values-$$.yaml" -trap 'rm -f /tmp/pulse-ui-build.log /tmp/pulse-ui-push.log "$VALUES_FILE"' EXIT +trap 'rm -f /tmp/pulse-ui-build.log /tmp/pulse-ui-push.log /tmp/pulse-helm-runner.digest "$VALUES_FILE"' EXIT # ─── Configuration ─────────────────────────────────────────────────────────── @@ -26,6 +26,8 @@ NAMESPACE="openshiftpulse" RELEASE="pulse" UI_IMAGE="${PULSE_UI_IMAGE:-quay.io/amobrem/openshiftpulse}" AGENT_IMAGE="${PULSE_AGENT_IMAGE:-quay.io/amobrem/pulse-agent}" +HELM_RUNNER_IMAGE="${PULSE_HELM_RUNNER_IMAGE:-quay.io/amobrem/pulse-helm-runner}" +HELM_RUNNER_IMAGE_REF="${PULSE_HELM_RUNNER_IMAGE_REF:-}" UI_TAG="" AGENT_TAG="" _WS_TOKEN_OVERRIDE="${PULSE_AGENT_WS_TOKEN:-}" @@ -252,6 +254,10 @@ fi if [[ -z "$AGENT_TAG" ]]; then AGENT_TAG=$(git_tag "$AGENT_REPO") fi +if [[ -n "$HELM_RUNNER_IMAGE_REF" && "$HELM_RUNNER_IMAGE_REF" != *@sha256:* ]]; then + error "PULSE_HELM_RUNNER_IMAGE_REF must be an immutable digest reference (repo@sha256:...)" + exit 1 +fi info "UI tag: $UI_TAG" info "Agent tag: $AGENT_TAG" @@ -305,6 +311,7 @@ if [[ "$DRY_RUN" == "true" ]]; then echo " Namespace: $NAMESPACE" echo " UI image: ${UI_IMAGE}:${UI_TAG}" echo " Agent image: ${AGENT_IMAGE}:${AGENT_TAG}" + echo " Helm runner: ${HELM_RUNNER_IMAGE_REF:-${HELM_RUNNER_IMAGE}:${UI_TAG} (digest resolved after push)}" if [[ -n "${ANTHROPIC_VERTEX_PROJECT_ID:-}" ]]; then echo " AI backend: Vertex AI (${ANTHROPIC_VERTEX_PROJECT_ID} / ${CLOUD_ML_REGION:-us-east5})" elif [[ -n "${ANTHROPIC_API_KEY:-}" ]]; then @@ -333,10 +340,15 @@ fi pnpm run build info "UI built (dist/)" - info "Building UI and Agent images in parallel..." + info "Building UI, Agent, and Helm runner images..." podman build --platform linux/amd64 -t "${UI_IMAGE}:${UI_TAG}" "$PROJECT_DIR" &>/tmp/pulse-ui-build.log & UI_BUILD_PID=$! + if [[ -z "$HELM_RUNNER_IMAGE_REF" ]]; then + podman build --platform linux/amd64 -t "${HELM_RUNNER_IMAGE}:${UI_TAG}" -f "$PROJECT_DIR/Dockerfile.helm-runner" "$PROJECT_DIR" + info "Helm runner image built" + fi + cd "$AGENT_REPO" # Default Dockerfile is the full single-stage build. # Use Dockerfile.fast only when the pre-built deps image is available in-cluster. @@ -355,6 +367,7 @@ fi info "Pushing images..." podman tag "${UI_IMAGE}:${UI_TAG}" "${UI_IMAGE}:latest" podman tag "${AGENT_IMAGE}:${AGENT_TAG}" "${AGENT_IMAGE}:latest" + [[ -z "$HELM_RUNNER_IMAGE_REF" ]] && podman tag "${HELM_RUNNER_IMAGE}:${UI_TAG}" "${HELM_RUNNER_IMAGE}:latest" podman push "${UI_IMAGE}:${UI_TAG}" &>/tmp/pulse-ui-push.log & UI_PUSH_PID=$! @@ -363,6 +376,14 @@ fi podman push "${AGENT_IMAGE}:latest" info "Pushed ${AGENT_IMAGE}:${AGENT_TAG} + latest" + if [[ -z "$HELM_RUNNER_IMAGE_REF" ]]; then + podman push --digestfile /tmp/pulse-helm-runner.digest "${HELM_RUNNER_IMAGE}:${UI_TAG}" + podman push "${HELM_RUNNER_IMAGE}:latest" + HELM_RUNNER_DIGEST=$(cat /tmp/pulse-helm-runner.digest) + HELM_RUNNER_IMAGE_REF="${HELM_RUNNER_IMAGE}@${HELM_RUNNER_DIGEST}" + info "Pushed Helm runner ${HELM_RUNNER_IMAGE_REF}" + fi + if wait $UI_PUSH_PID; then podman push "${UI_IMAGE}:latest" info "Pushed ${UI_IMAGE}:${UI_TAG} + latest" @@ -433,15 +454,22 @@ fi # Generate values file (keeps secrets out of process listings) AI_BACKEND="none" AI_VALUES="" +AI_VALUES_COMPAT="" if [[ -n "${ANTHROPIC_VERTEX_PROJECT_ID:-}" ]]; then AI_VALUES=" vertexAI: projectId: ${ANTHROPIC_VERTEX_PROJECT_ID} region: ${CLOUD_ML_REGION:-us-east5} existingSecret: gcp-sa-key" + AI_VALUES_COMPAT=" vertexAI: + projectId: ${ANTHROPIC_VERTEX_PROJECT_ID} + region: ${CLOUD_ML_REGION:-us-east5} + existingSecret: gcp-sa-key" AI_BACKEND="vertex" elif [[ -n "${ANTHROPIC_API_KEY:-}" ]]; then AI_VALUES=" anthropicApiKey: existingSecret: anthropic-api-key" + AI_VALUES_COMPAT=" anthropicApiKey: + existingSecret: anthropic-api-key" AI_BACKEND="anthropic" fi @@ -474,6 +502,9 @@ openshiftpulse: enabled: $MONITORING_ENABLED alertmanager: enabled: $MONITORING_ENABLED + helmInstall: + runnerImage: "$HELM_RUNNER_IMAGE_REF" + serviceAccountName: openshiftpulse-helm-installer agent: enabled: true serviceName: $AGENT_DEPLOY @@ -487,9 +518,24 @@ agent: rbac: allowWriteOperations: ${AGENT_ALLOW_WRITES:-false} allowSecretAccess: ${AGENT_ALLOW_SECRETS:-false} + mcp: + enabled: false wsAuth: existingSecret: $WS_SECRET $AI_VALUES +openshift-sre-agent: + enabled: true + image: + repository: $AGENT_IMAGE + tag: "$AGENT_TAG" + rbac: + allowWriteOperations: ${AGENT_ALLOW_WRITES:-false} + allowSecretAccess: ${AGENT_ALLOW_SECRETS:-false} + mcp: + enabled: false + wsAuth: + existingSecret: $WS_SECRET +$AI_VALUES_COMPAT YAML chmod 600 "$VALUES_FILE" diff --git a/deploy/helm/openshiftpulse/templates/deployment.yaml b/deploy/helm/openshiftpulse/templates/deployment.yaml index 5b78be1a..950eec4b 100644 --- a/deploy/helm/openshiftpulse/templates/deployment.yaml +++ b/deploy/helm/openshiftpulse/templates/deployment.yaml @@ -114,8 +114,6 @@ spec: echo "Agent WS token: injected at template time" fi {{- end }} - SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token 2>/dev/null || echo "") - sed -i "s|__SA_TOKEN__|${SA_TOKEN}|g" /tmp/nginx.conf exec nginx -c /tmp/nginx.conf -g 'daemon off;' ports: - containerPort: 8080 @@ -123,6 +121,9 @@ spec: - name: nginx-config mountPath: /etc/nginx/nginx.conf subPath: nginx.conf + - name: nginx-config + mountPath: /opt/app-root/src/config.js + subPath: config.js {{- if .Values.agent.enabled }} - name: agent-token mountPath: /etc/nginx/agent-token diff --git a/deploy/helm/openshiftpulse/templates/nginx-config.yaml b/deploy/helm/openshiftpulse/templates/nginx-config.yaml index 8a0f0b4c..15c65bb7 100644 --- a/deploy/helm/openshiftpulse/templates/nginx-config.yaml +++ b/deploy/helm/openshiftpulse/templates/nginx-config.yaml @@ -6,6 +6,13 @@ metadata: labels: {{- include "openshiftpulse.labels" . | nindent 4 }} data: + config.js: | + window.__OPENSHIFTPULSE_CONFIG__ = { + helmInstall: { + runnerImage: {{ .Values.helmInstall.runnerImage | quote }}, + serviceAccountName: {{ .Values.helmInstall.serviceAccountName | quote }} + } + }; nginx.conf: | worker_processes auto; error_log /dev/stderr warn; @@ -44,11 +51,10 @@ data: proxy_pass https://kubernetes.default.svc/; proxy_ssl_verify on; proxy_ssl_trusted_certificate /var/run/secrets/kubernetes.io/serviceaccount/ca.crt; - set $k8s_token $http_x_forwarded_access_token; - if ($k8s_token = '') { - set $k8s_token '__SA_TOKEN__'; + if ($http_x_forwarded_access_token = '') { + return 401 '{"error":"X-Forwarded-Access-Token header is required"}'; } - proxy_set_header Authorization "Bearer $k8s_token"; + proxy_set_header Authorization "Bearer $http_x_forwarded_access_token"; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_http_version 1.1; @@ -60,11 +66,10 @@ data: proxy_pass https://{{ .Values.monitoring.prometheus.host }}/; proxy_ssl_verify on; proxy_ssl_trusted_certificate /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt; - set $prom_token $http_x_forwarded_access_token; - if ($prom_token = '') { - set $prom_token '__SA_TOKEN__'; + if ($http_x_forwarded_access_token = '') { + return 401 '{"error":"X-Forwarded-Access-Token header is required"}'; } - proxy_set_header Authorization "Bearer $prom_token"; + proxy_set_header Authorization "Bearer $http_x_forwarded_access_token"; proxy_read_timeout 60s; } {{- else }} @@ -84,11 +89,10 @@ data: proxy_pass https://{{ .Values.monitoring.alertmanager.host }}/; proxy_ssl_verify on; proxy_ssl_trusted_certificate /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt; - set $am_token $http_x_forwarded_access_token; - if ($am_token = '') { - set $am_token '__SA_TOKEN__'; + if ($http_x_forwarded_access_token = '') { + return 401 '{"error":"X-Forwarded-Access-Token header is required"}'; } - proxy_set_header Authorization "Bearer $am_token"; + proxy_set_header Authorization "Bearer $http_x_forwarded_access_token"; proxy_read_timeout 60s; } {{- else }} diff --git a/deploy/helm/openshiftpulse/values.yaml b/deploy/helm/openshiftpulse/values.yaml index 3a277fc4..e69b4e2f 100644 --- a/deploy/helm/openshiftpulse/values.yaml +++ b/deploy/helm/openshiftpulse/values.yaml @@ -36,6 +36,12 @@ monitoring: selfMonitor: enabled: true +# In-cluster Helm installs use a project-owned runner image. Leave empty to +# fail closed rather than execute a mutable third-party image. +helmInstall: + runnerImage: "" + serviceAccountName: openshiftpulse-helm-installer + # Resource limits resources: app: diff --git a/deploy/helm/pulse/Chart.lock b/deploy/helm/pulse/Chart.lock index d155a254..14535a86 100644 --- a/deploy/helm/pulse/Chart.lock +++ b/deploy/helm/pulse/Chart.lock @@ -4,6 +4,6 @@ dependencies: version: 4.7.0 - name: openshift-sre-agent repository: file://../../../../pulse-agent/chart - version: 2.6.0 -digest: sha256:a9ce7715a3e0c6ae6513674f5de98df4be4d79627d42a96091fe7d620fa69d17 -generated: "2026-04-28T18:09:47.246482-07:00" + version: 1.13.0 +digest: sha256:0408c4a4e57404efbda9a53cf921bb4cde8634b182e14bdb7c87cdc8d760aca5 +generated: "2026-06-09T16:58:30.041978735+02:00" diff --git a/deploy/helm/pulse/Chart.yaml b/deploy/helm/pulse/Chart.yaml index da880374..bead4301 100644 --- a/deploy/helm/pulse/Chart.yaml +++ b/deploy/helm/pulse/Chart.yaml @@ -16,7 +16,7 @@ dependencies: repository: "file://../openshiftpulse" - name: openshift-sre-agent - version: "2.7.1" + version: "1.13.0" repository: "file://../../../../pulse-agent/chart" alias: agent condition: agent.enabled diff --git a/deploy/helm/pulse/charts/openshift-sre-agent-1.13.0.tgz b/deploy/helm/pulse/charts/openshift-sre-agent-1.13.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..22272bb459841a80b99d5ee62db65762d9142fe2 GIT binary patch literal 6172 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 KCfI2JoB#lMR?QXw diff --git a/deploy/helm/pulse/values.yaml b/deploy/helm/pulse/values.yaml index be679669..27631caf 100644 --- a/deploy/helm/pulse/values.yaml +++ b/deploy/helm/pulse/values.yaml @@ -24,6 +24,10 @@ openshiftpulse: enabled: true host: alertmanager-main.openshift-monitoring.svc:9094 + helmInstall: + runnerImage: "" + serviceAccountName: openshiftpulse-helm-installer + agent: enabled: true # Auto-derived from release name if empty: -openshift-sre-agent @@ -65,6 +69,9 @@ agent: allowWriteOperations: false allowSecretAccess: false + mcp: + enabled: false + database: type: postgresql postgresql: @@ -79,3 +86,10 @@ agent: wsAuth: existingSecret: "pulse-ws-token" secretKey: "token" + +# Compatibility for stale packaged dependencies that were not aliased as +# `agent`. Keep this until the archived dependency is refreshed everywhere. +openshift-sre-agent: + enabled: true + mcp: + enabled: false diff --git a/deploy/test-helm.sh b/deploy/test-helm.sh index 51cdd1ad..8cee36cc 100755 --- a/deploy/test-helm.sh +++ b/deploy/test-helm.sh @@ -40,7 +40,14 @@ AGENT_VALUES=( --set agent.enabled=true --set agent.image.repository=quay.io/test/agent --set agent.image.tag=test + --set agent.wsAuth.existingSecret=pulse-ws-token --set agent.anthropicApiKey.existingSecret=test-secret + # Compatibility for stale packaged dependencies before helm dependency update. + --set openshift-sre-agent.enabled=true + --set openshift-sre-agent.image.repository=quay.io/test/agent + --set openshift-sre-agent.image.tag=test + --set openshift-sre-agent.wsAuth.existingSecret=pulse-ws-token + --set openshift-sre-agent.anthropicApiKey.existingSecret=test-secret ) # 1. Helm lint @@ -53,8 +60,7 @@ fi # 2. Template renders without errors echo "--- Template rendering ---" -RENDERED=$(helm template pulse "$CHART_DIR" "${COMMON[@]}" "${AGENT_VALUES[@]}" 2>&1) -if [[ $? -eq 0 ]]; then +if RENDERED=$(helm template pulse "$CHART_DIR" "${COMMON[@]}" "${AGENT_VALUES[@]}" 2>&1); then pass "Template renders (agent enabled)" else fail "Template renders (agent enabled)" @@ -118,10 +124,10 @@ else fi # 10. Agent disabled renders without errors -RENDERED_NO_AGENT=$(helm template pulse "$CHART_DIR" "${COMMON[@]}" \ +if RENDERED_NO_AGENT=$(helm template pulse "$CHART_DIR" "${COMMON[@]}" \ --set openshiftpulse.agent.enabled=false \ - --set agent.enabled=false 2>&1) -if [[ $? -eq 0 ]]; then + --set agent.enabled=false \ + --set openshift-sre-agent.enabled=false 2>&1); then pass "Template renders (agent disabled)" else fail "Template renders (agent disabled)" @@ -149,6 +155,32 @@ else fail "RollingUpdate strategy missing" fi +# 14. User token proxy must fail closed instead of falling back to service-account token +if has "$RENDERED" "__SA_TOKEN__"; then + fail "nginx config still contains service-account token fallback" +else + pass "nginx config has no service-account token fallback" +fi + +if has "$RENDERED" "X-Forwarded-Access-Token header is required"; then + pass "nginx returns 401 when forwarded access token is missing" +else + fail "nginx missing-token 401 guard not rendered" +fi + +if has "$RENDERED" "sed -i \"s|__SA_TOKEN__"; then + fail "deployment still injects service-account token into nginx" +else + pass "deployment does not inject service-account token into nginx" +fi + +# 15. MCP server must not render by default +if has "$RENDERED" "app.kubernetes.io/component: mcp-server"; then + fail "MCP server renders by default" +else + pass "MCP server disabled by default" +fi + # Summary echo "" echo "===========================" diff --git a/public/config.js b/public/config.js new file mode 100644 index 00000000..a3a8511b --- /dev/null +++ b/public/config.js @@ -0,0 +1 @@ +window.__OPENSHIFTPULSE_CONFIG__ = window.__OPENSHIFTPULSE_CONFIG__ || {}; diff --git a/public/index.html b/public/index.html index 9b7d1a9c..d7c35261 100644 --- a/public/index.html +++ b/public/index.html @@ -3,9 +3,10 @@ - - OpenShift Pulse - + + OpenShift Pulse + +