From 7063dd8fe42e216f86477ea12bf4f0381ce50832 Mon Sep 17 00:00:00 2001 From: SarthakB11 Date: Sun, 5 Jul 2026 14:35:14 +0000 Subject: [PATCH 1/3] fix(helm): don't pin runAsUser/runAsGroup in grafana-mcp and querydoc chart defaults The grafana-mcp and querydoc subcharts hardcode securityContext.runAsUser (1000 and 14000) and runAsGroup (999 and 14000) in their default values.yaml. On OpenShift, each namespace is assigned a dynamic UID range and the restricted-v2 SCC rejects any pod whose runAsUser falls outside that range, so the chart is undeployable out of the box: the Deployments stay at 0/1 with a FailedCreate admission error until each component's UID is overridden by hand to an in-range value that is cluster- and namespace-specific. Remove the pinned UIDs from the defaults. Documented commented overrides remain for clusters that want to pin them. runAsNonRoot in podSecurityContext still enforces non-root, and the rest of the hardening (allowPrivilegeEscalation: false, capabilities.drop: [ALL], readOnlyRootFilesystem: true, seccompProfile: RuntimeDefault) is unchanged. Fixes #2079 Signed-off-by: SarthakB11 --- helm/tools/grafana-mcp/tests/deployment_test.yaml | 6 ++---- helm/tools/grafana-mcp/values.yaml | 10 ++++++++-- helm/tools/querydoc/tests/deployment_test.yaml | 6 ++---- helm/tools/querydoc/values.yaml | 10 ++++++++-- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/helm/tools/grafana-mcp/tests/deployment_test.yaml b/helm/tools/grafana-mcp/tests/deployment_test.yaml index d1ed1c4add..bcb4683132 100644 --- a/helm/tools/grafana-mcp/tests/deployment_test.yaml +++ b/helm/tools/grafana-mcp/tests/deployment_test.yaml @@ -64,12 +64,10 @@ tests: - equal: path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem value: true - - equal: + - isNull: path: spec.template.spec.containers[0].securityContext.runAsUser - value: 1000 - - equal: + - isNull: path: spec.template.spec.containers[0].securityContext.runAsGroup - value: 999 - isNull: path: spec.template.spec.containers[0].securityContext.seccompProfile diff --git a/helm/tools/grafana-mcp/values.yaml b/helm/tools/grafana-mcp/values.yaml index 01f0f1f50a..d73dfe1a7b 100644 --- a/helm/tools/grafana-mcp/values.yaml +++ b/helm/tools/grafana-mcp/values.yaml @@ -31,8 +31,14 @@ securityContext: drop: - ALL readOnlyRootFilesystem: true - runAsUser: 1000 - runAsGroup: 999 + # runAsUser / runAsGroup are left unset so the chart installs on OpenShift, + # where the restricted-v2 SCC assigns a per-namespace UID range and rejects a + # pinned UID outside it. runAsNonRoot (in podSecurityContext) enforces + # non-root: with runAsUser unset the container runs as the image's USER, so + # the mcp/grafana image must ship a non-root USER or the pod will fail to + # start. Set a fixed UID below on clusters that allow it: + # runAsUser: 1000 + # runAsGroup: 999 tolerations: [] diff --git a/helm/tools/querydoc/tests/deployment_test.yaml b/helm/tools/querydoc/tests/deployment_test.yaml index 2fb47c58a1..5f77fe64b6 100644 --- a/helm/tools/querydoc/tests/deployment_test.yaml +++ b/helm/tools/querydoc/tests/deployment_test.yaml @@ -112,12 +112,10 @@ tests: - equal: path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem value: true - - equal: + - isNull: path: spec.template.spec.containers[0].securityContext.runAsUser - value: 14000 - - equal: + - isNull: path: spec.template.spec.containers[0].securityContext.runAsGroup - value: 14000 - isNull: path: spec.template.spec.containers[0].securityContext.seccompProfile diff --git a/helm/tools/querydoc/values.yaml b/helm/tools/querydoc/values.yaml index 13185e9740..ca9a6e4e79 100644 --- a/helm/tools/querydoc/values.yaml +++ b/helm/tools/querydoc/values.yaml @@ -25,8 +25,14 @@ securityContext: drop: - ALL readOnlyRootFilesystem: true - runAsUser: 14000 - runAsGroup: 14000 + # runAsUser / runAsGroup are left unset so the chart installs on OpenShift, + # where the restricted-v2 SCC assigns a per-namespace UID range and rejects a + # pinned UID outside it. runAsNonRoot (in podSecurityContext) enforces + # non-root: with runAsUser unset the container runs as the image's USER, so + # the mcp/querydoc image must ship a non-root USER or the pod will fail to + # start. Set a fixed UID below on clusters that allow it: + # runAsUser: 14000 + # runAsGroup: 14000 tolerations: [] From 1518b3524a96b7cf23e60e14cd365569d7cf95d5 Mon Sep 17 00:00:00 2001 From: SarthakB11 Date: Sat, 11 Jul 2026 23:13:01 +0000 Subject: [PATCH 2/3] fix(helm): pin numeric non-root UID by default, document OpenShift override The grafana-mcp and querydoc charts enable podSecurityContext.runAsNonRoot. On vanilla Kubernetes the kubelet can only confirm a container is non-root from a numeric runAsUser or a numeric image USER, and neither image ships one (the mcp/grafana image's USER is the name "mcp-grafana" and the querydoc image runs as root). Leaving runAsUser unset therefore fails admission with CreateContainerConfigError and the pods never start. Keep a fixed non-root UID/GID as the default so the charts install on vanilla Kubernetes, and document the one-line override to null so OpenShift users let the restricted-v2 SCC assign an in-range UID. Fixes #2079 Signed-off-by: SarthakB11 --- .../grafana-mcp/tests/deployment_test.yaml | 6 ++++-- helm/tools/grafana-mcp/values.yaml | 17 +++++++++-------- helm/tools/querydoc/tests/deployment_test.yaml | 6 ++++-- helm/tools/querydoc/values.yaml | 17 +++++++++-------- 4 files changed, 26 insertions(+), 20 deletions(-) diff --git a/helm/tools/grafana-mcp/tests/deployment_test.yaml b/helm/tools/grafana-mcp/tests/deployment_test.yaml index bcb4683132..d1ed1c4add 100644 --- a/helm/tools/grafana-mcp/tests/deployment_test.yaml +++ b/helm/tools/grafana-mcp/tests/deployment_test.yaml @@ -64,10 +64,12 @@ tests: - equal: path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem value: true - - isNull: + - equal: path: spec.template.spec.containers[0].securityContext.runAsUser - - isNull: + value: 1000 + - equal: path: spec.template.spec.containers[0].securityContext.runAsGroup + value: 999 - isNull: path: spec.template.spec.containers[0].securityContext.seccompProfile diff --git a/helm/tools/grafana-mcp/values.yaml b/helm/tools/grafana-mcp/values.yaml index d73dfe1a7b..dc4478a442 100644 --- a/helm/tools/grafana-mcp/values.yaml +++ b/helm/tools/grafana-mcp/values.yaml @@ -31,14 +31,15 @@ securityContext: drop: - ALL readOnlyRootFilesystem: true - # runAsUser / runAsGroup are left unset so the chart installs on OpenShift, - # where the restricted-v2 SCC assigns a per-namespace UID range and rejects a - # pinned UID outside it. runAsNonRoot (in podSecurityContext) enforces - # non-root: with runAsUser unset the container runs as the image's USER, so - # the mcp/grafana image must ship a non-root USER or the pod will fail to - # start. Set a fixed UID below on clusters that allow it: - # runAsUser: 1000 - # runAsGroup: 999 + # A fixed non-root UID/GID is set so the chart installs on vanilla Kubernetes: + # runAsNonRoot (in podSecurityContext) needs a numeric non-root user and the + # mcp/grafana image does not ship one. On OpenShift, where the restricted-v2 + # SCC assigns a per-namespace UID range and rejects a pinned UID outside it, + # override these to null so the SCC injects an in-range UID: + # --set tools.grafana-mcp.securityContext.runAsUser=null + # --set tools.grafana-mcp.securityContext.runAsGroup=null + runAsUser: 1000 + runAsGroup: 999 tolerations: [] diff --git a/helm/tools/querydoc/tests/deployment_test.yaml b/helm/tools/querydoc/tests/deployment_test.yaml index 5f77fe64b6..2fb47c58a1 100644 --- a/helm/tools/querydoc/tests/deployment_test.yaml +++ b/helm/tools/querydoc/tests/deployment_test.yaml @@ -112,10 +112,12 @@ tests: - equal: path: spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem value: true - - isNull: + - equal: path: spec.template.spec.containers[0].securityContext.runAsUser - - isNull: + value: 14000 + - equal: path: spec.template.spec.containers[0].securityContext.runAsGroup + value: 14000 - isNull: path: spec.template.spec.containers[0].securityContext.seccompProfile diff --git a/helm/tools/querydoc/values.yaml b/helm/tools/querydoc/values.yaml index ca9a6e4e79..489a84d3f3 100644 --- a/helm/tools/querydoc/values.yaml +++ b/helm/tools/querydoc/values.yaml @@ -25,14 +25,15 @@ securityContext: drop: - ALL readOnlyRootFilesystem: true - # runAsUser / runAsGroup are left unset so the chart installs on OpenShift, - # where the restricted-v2 SCC assigns a per-namespace UID range and rejects a - # pinned UID outside it. runAsNonRoot (in podSecurityContext) enforces - # non-root: with runAsUser unset the container runs as the image's USER, so - # the mcp/querydoc image must ship a non-root USER or the pod will fail to - # start. Set a fixed UID below on clusters that allow it: - # runAsUser: 14000 - # runAsGroup: 14000 + # A fixed non-root UID/GID is set so the chart installs on vanilla Kubernetes: + # runAsNonRoot (in podSecurityContext) needs a numeric non-root user and the + # querydoc image does not ship one. On OpenShift, where the restricted-v2 SCC + # assigns a per-namespace UID range and rejects a pinned UID outside it, + # override these to null so the SCC injects an in-range UID: + # --set tools.querydoc.securityContext.runAsUser=null + # --set tools.querydoc.securityContext.runAsGroup=null + runAsUser: 14000 + runAsGroup: 14000 tolerations: [] From b8f728d3ad9c2223fa066764ec08895d21199602 Mon Sep 17 00:00:00 2001 From: SarthakB11 Date: Sat, 11 Jul 2026 23:52:50 +0000 Subject: [PATCH 3/3] docs(helm): note querydoc pin can drop once its image ships a numeric USER The querydoc image (doc2vec/mcp) does not currently run as a numeric non-root user, so the runAsUser/runAsGroup pin is required for the default install to pass runAsNonRoot on vanilla Kubernetes. Record that the pin can be removed once the image ships a numeric non-root USER, at which point kubelet reads the UID from the image directly. Fixes #2079 Signed-off-by: SarthakB11 --- helm/tools/querydoc/values.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/helm/tools/querydoc/values.yaml b/helm/tools/querydoc/values.yaml index 489a84d3f3..fbbdc2bca9 100644 --- a/helm/tools/querydoc/values.yaml +++ b/helm/tools/querydoc/values.yaml @@ -26,10 +26,12 @@ securityContext: - ALL readOnlyRootFilesystem: true # A fixed non-root UID/GID is set so the chart installs on vanilla Kubernetes: - # runAsNonRoot (in podSecurityContext) needs a numeric non-root user and the - # querydoc image does not ship one. On OpenShift, where the restricted-v2 SCC - # assigns a per-namespace UID range and rejects a pinned UID outside it, - # override these to null so the SCC injects an in-range UID: + # runAsNonRoot (in podSecurityContext) needs a numeric non-root user, and the + # querydoc image (doc2vec/mcp) does not currently run as one. Once that image + # ships a numeric non-root USER, this pin can be dropped and kubelet will read + # the UID from the image. On OpenShift, where the restricted-v2 SCC assigns a + # per-namespace UID range and rejects a pinned UID outside it, override these + # to null so the SCC injects an in-range UID: # --set tools.querydoc.securityContext.runAsUser=null # --set tools.querydoc.securityContext.runAsGroup=null runAsUser: 14000