Summary
Several bundled subcharts pin securityContext.runAsUser / runAsGroup (and one podSecurityContext) to fixed UIDs in their default values. On OpenShift this makes the chart undeployable out of the box: each namespace is assigned a dynamic UID range and the restricted-v2 SCC rejects any pod whose runAsUser falls outside that range. The affected Deployments stay at 0/1 with a FailedCreate event, and every component has to be overridden to an in-range UID by hand.
Relates to #459 ("[FEATURE] OpenShift support", closed as stale).
Affected defaults (chart 0.9.9)
| component |
file |
value |
grafana-mcp |
charts/grafana-mcp/values.yaml (securityContext) |
runAsUser: 1000, runAsGroup: 999 |
querydoc |
charts/querydoc/values.yaml (securityContext) |
runAsUser: 14000, runAsGroup: 14000 |
oauth2-proxy (vendored dependency) |
charts/oauth2-proxy/values.yaml (podSecurityContext) |
runAsUser: 2000, runAsGroup: 2000 |
| bundled demo PostgreSQL |
values.yaml (...postgresql.podSecurityContext) |
runAsUser: 999, runAsGroup: 999, fsGroup: 999 |
Impact / symptom
On OpenShift (e.g. restricted-v2 SCC), the API server rejects the pod at admission. Representative event:
Error creating: pods "grafana-mcp-..." is forbidden: unable to validate against any
security context constraint: ... runAsUser: Invalid value: 1000: must be in the
ranges: [1001150000, 1001159999]
The Deployment then sits at 0/1. To install the chart we currently have to override each component's securityContext.runAsUser/runAsGroup to a value inside the namespace's assigned range — which is cluster/namespace-specific and not knowable ahead of time.
Proposed fix
Don't pin runAsUser/runAsGroup in the subchart default values. Keep the rest of the hardening that is already there (runAsNonRoot: true, capabilities.drop: [ALL], readOnlyRootFilesystem: true, seccompProfile). With no runAsUser set:
- OpenShift injects a valid in-range UID automatically via the SCC.
- Vanilla Kubernetes runs as the image's
USER and runAsNonRoot: true still enforces non-root.
This assumes the grafana-mcp / querydoc images declare a non-root USER. If they don't, the alternative is to make the UID cleanly nullable/overridable (so it can be unset) and document the OpenShift guidance, rather than shipping a hardcoded out-of-range default.
For the vendored oauth2-proxy dependency, surfacing/recommending an override (or unsetting it via the umbrella values) would cover it.
I'm happy to send a PR for the grafana-mcp and querydoc subcharts once you confirm the preferred approach (unset default vs. nullable+documented).
Environment
- kagent helm chart
0.9.9 (oci://ghcr.io/kagent-dev/kagent/helm/kagent)
- OpenShift (ARO),
restricted-v2 SCC with per-namespace dynamic UID ranges
Summary
Several bundled subcharts pin
securityContext.runAsUser/runAsGroup(and onepodSecurityContext) to fixed UIDs in their default values. On OpenShift this makes the chart undeployable out of the box: each namespace is assigned a dynamic UID range and therestricted-v2SCC rejects any pod whoserunAsUserfalls outside that range. The affected Deployments stay at0/1with aFailedCreateevent, and every component has to be overridden to an in-range UID by hand.Relates to #459 ("[FEATURE] OpenShift support", closed as stale).
Affected defaults (chart
0.9.9)grafana-mcpcharts/grafana-mcp/values.yaml(securityContext)runAsUser: 1000,runAsGroup: 999querydoccharts/querydoc/values.yaml(securityContext)runAsUser: 14000,runAsGroup: 14000oauth2-proxy(vendored dependency)charts/oauth2-proxy/values.yaml(podSecurityContext)runAsUser: 2000,runAsGroup: 2000values.yaml(...postgresql.podSecurityContext)runAsUser: 999,runAsGroup: 999,fsGroup: 999Impact / symptom
On OpenShift (e.g.
restricted-v2SCC), the API server rejects the pod at admission. Representative event:The Deployment then sits at
0/1. To install the chart we currently have to override each component'ssecurityContext.runAsUser/runAsGroupto a value inside the namespace's assigned range — which is cluster/namespace-specific and not knowable ahead of time.Proposed fix
Don't pin
runAsUser/runAsGroupin the subchart default values. Keep the rest of the hardening that is already there (runAsNonRoot: true,capabilities.drop: [ALL],readOnlyRootFilesystem: true,seccompProfile). With norunAsUserset:USERandrunAsNonRoot: truestill enforces non-root.This assumes the
grafana-mcp/querydocimages declare a non-rootUSER. If they don't, the alternative is to make the UID cleanly nullable/overridable (so it can be unset) and document the OpenShift guidance, rather than shipping a hardcoded out-of-range default.For the vendored
oauth2-proxydependency, surfacing/recommending an override (or unsetting it via the umbrella values) would cover it.I'm happy to send a PR for the
grafana-mcpandquerydocsubcharts once you confirm the preferred approach (unset default vs. nullable+documented).Environment
0.9.9(oci://ghcr.io/kagent-dev/kagent/helm/kagent)restricted-v2SCC with per-namespace dynamic UID ranges