From a1ad220417825f62a20a7f989ed1cd782d19958c Mon Sep 17 00:00:00 2001 From: Aman Raj Date: Wed, 17 Jun 2026 02:30:00 +0530 Subject: [PATCH 1/2] feat(chart): make DaemonSet securityContext configurable via values The csi-driver DaemonSet hardcoded the pod-level and per-container securityContext, including privileged: true and runAsUser: 0 on the cert-manager-csi-driver container. Operators with Pod Security Standards or compliance requirements could not adjust the security posture without forking the chart (#583). Move the securityContext blocks into values.yaml: - podSecurityContext (pod-level) - securityContext (cert-manager-csi-driver) - nodeDriverRegistrarSecurityContext (node-driver-registrar) - livenessProbeSecurityContext (liveness-probe) Each default reproduces the previously hardcoded value exactly, so the rendered DaemonSet is unchanged. The cert-manager-csi-driver container keeps privileged: true by default because it mounts pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which Kubernetes only permits for privileged containers. Operators may now opt into a hardened context at their own discretion. Regenerated values.schema.json and README.md, and added helm-unittest coverage for the defaults and overrides. Refs #583 Signed-off-by: Aman Raj --- deploy/charts/csi-driver/README.md | 50 +++++++++++++ .../csi-driver/templates/daemonset.yaml | 25 +++---- .../tests/securitycontext_test.yaml | 75 +++++++++++++++++++ deploy/charts/csi-driver/values.schema.json | 63 ++++++++++++++++ deploy/charts/csi-driver/values.yaml | 43 +++++++++++ 5 files changed, 243 insertions(+), 13 deletions(-) create mode 100644 deploy/charts/csi-driver/tests/securitycontext_test.yaml diff --git a/deploy/charts/csi-driver/README.md b/deploy/charts/csi-driver/README.md index f4690ee5..af3dc02a 100644 --- a/deploy/charts/csi-driver/README.md +++ b/deploy/charts/csi-driver/README.md @@ -407,6 +407,56 @@ Optional additional annotations to add to the csi-driver pods. > ``` Optional additional labels to add to the csi-driver pods. +#### **podSecurityContext** ~ `object` +> Default value: +> ```yaml +> seccompProfile: +> type: RuntimeDefault +> ``` + +Pod-level security context for the csi-driver DaemonSet pods. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). + +#### **securityContext** ~ `object` +> Default value: +> ```yaml +> capabilities: +> drop: +> - ALL +> privileged: true +> readOnlyRootFilesystem: true +> runAsUser: 0 +> ``` + +Container security context for the cert-manager-csi-driver container. + +NOTE: privileged is required by default because this container mounts pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which. Kubernetes only permits for privileged containers. Setting privileged: false without also changing the mount propagation will prevent the driver pods from starting. See https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation + +#### **nodeDriverRegistrarSecurityContext** ~ `object` +> Default value: +> ```yaml +> allowPrivilegeEscalation: false +> capabilities: +> drop: +> - ALL +> readOnlyRootFilesystem: true +> runAsUser: 0 +> ``` + +Container security context for the node-driver-registrar container. + +#### **livenessProbeSecurityContext** ~ `object` +> Default value: +> ```yaml +> allowPrivilegeEscalation: false +> capabilities: +> drop: +> - ALL +> readOnlyRootFilesystem: true +> runAsUser: 0 +> ``` + +Container security context for the liveness-probe container. + #### **resources** ~ `object` > Default value: > ```yaml diff --git a/deploy/charts/csi-driver/templates/daemonset.yaml b/deploy/charts/csi-driver/templates/daemonset.yaml index 8d4aacac..9369913f 100644 --- a/deploy/charts/csi-driver/templates/daemonset.yaml +++ b/deploy/charts/csi-driver/templates/daemonset.yaml @@ -27,8 +27,10 @@ spec: {{- toYaml .Values.podAnnotations | nindent 8 }} {{- end }} spec: + {{- with .Values.podSecurityContext }} securityContext: - seccompProfile: { type: RuntimeDefault } + {{- toYaml . | nindent 8 }} + {{- end }} {{- with .Values.imagePullSecrets }} imagePullSecrets: @@ -42,11 +44,10 @@ spec: containers: - name: node-driver-registrar + {{- with .Values.nodeDriverRegistrarSecurityContext }} securityContext: - runAsUser: 0 - allowPrivilegeEscalation: false - capabilities: { drop: [ "ALL" ] } - readOnlyRootFilesystem: true + {{- toYaml . | nindent 12 }} + {{- end }} image: "{{ template "cert-manager-csi-driver.image" (tuple .Values.nodeDriverRegistrarImage .Values.imageRegistry .Values.imageNamespace .Values.nodeDriverRegistrarImage._defaultReference) }}" imagePullPolicy: {{ .Values.nodeDriverRegistrarImage.pullPolicy }} args: @@ -65,11 +66,10 @@ spec: mountPath: /registration - name: liveness-probe + {{- with .Values.livenessProbeSecurityContext }} securityContext: - runAsUser: 0 - allowPrivilegeEscalation: false - capabilities: { drop: [ "ALL" ] } - readOnlyRootFilesystem: true + {{- toYaml . | nindent 12 }} + {{- end }} image: "{{ template "cert-manager-csi-driver.image" (tuple .Values.livenessProbeImage .Values.imageRegistry .Values.imageNamespace .Values.livenessProbeImage._defaultReference) }}" imagePullPolicy: {{ .Values.livenessProbeImage.pullPolicy }} args: @@ -82,11 +82,10 @@ spec: mountPath: /plugin - name: cert-manager-csi-driver + {{- with .Values.securityContext }} securityContext: - runAsUser: 0 - privileged: true - capabilities: { drop: [ "ALL" ] } - readOnlyRootFilesystem: true + {{- toYaml . | nindent 12 }} + {{- end }} image: "{{ template "cert-manager-csi-driver.image" (tuple .Values.image .Values.imageRegistry .Values.imageNamespace (printf ":%s" $.Chart.AppVersion)) }}" imagePullPolicy: {{ .Values.image.pullPolicy }} args : diff --git a/deploy/charts/csi-driver/tests/securitycontext_test.yaml b/deploy/charts/csi-driver/tests/securitycontext_test.yaml new file mode 100644 index 00000000..4e526180 --- /dev/null +++ b/deploy/charts/csi-driver/tests/securitycontext_test.yaml @@ -0,0 +1,75 @@ +suite: securityContext configurability +templates: + - daemonset.yaml +tests: + - it: preserves the default securityContext on the cert-manager-csi-driver container + asserts: + - equal: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.privileged + value: true + - equal: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.runAsUser + value: 0 + - equal: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.readOnlyRootFilesystem + value: true + - contains: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.capabilities.drop + content: ALL + + - it: preserves the default securityContext on the sidecar containers + asserts: + - equal: + path: spec.template.spec.containers[?(@.name=="node-driver-registrar")].securityContext.allowPrivilegeEscalation + value: false + - equal: + path: spec.template.spec.containers[?(@.name=="liveness-probe")].securityContext.allowPrivilegeEscalation + value: false + + - it: preserves the default pod-level securityContext + asserts: + - equal: + path: spec.template.spec.securityContext.seccompProfile.type + value: RuntimeDefault + + - it: lets operators opt into a non-privileged context with CAP_SYS_ADMIN + set: + securityContext: + runAsUser: 0 + privileged: false + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + add: + - SYS_ADMIN + drop: + - ALL + asserts: + - equal: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.privileged + value: false + - contains: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.capabilities.add + content: SYS_ADMIN + + - it: lets operators override the pod-level securityContext + set: + podSecurityContext: + runAsNonRoot: true + fsGroup: 1000 + seccompProfile: + type: RuntimeDefault + asserts: + - equal: + path: spec.template.spec.securityContext.runAsNonRoot + value: true + - equal: + path: spec.template.spec.securityContext.fsGroup + value: 1000 + + - it: omits the container securityContext entirely when set to null + set: + securityContext: null + asserts: + - notExists: + path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext diff --git a/deploy/charts/csi-driver/values.schema.json b/deploy/charts/csi-driver/values.schema.json index c669b53a..b68590d9 100644 --- a/deploy/charts/csi-driver/values.schema.json +++ b/deploy/charts/csi-driver/values.schema.json @@ -36,12 +36,18 @@ "livenessProbeImage": { "$ref": "#/$defs/helm-values.livenessProbeImage" }, + "livenessProbeSecurityContext": { + "$ref": "#/$defs/helm-values.livenessProbeSecurityContext" + }, "metrics": { "$ref": "#/$defs/helm-values.metrics" }, "nodeDriverRegistrarImage": { "$ref": "#/$defs/helm-values.nodeDriverRegistrarImage" }, + "nodeDriverRegistrarSecurityContext": { + "$ref": "#/$defs/helm-values.nodeDriverRegistrarSecurityContext" + }, "nodeSelector": { "$ref": "#/$defs/helm-values.nodeSelector" }, @@ -54,12 +60,18 @@ "podLabels": { "$ref": "#/$defs/helm-values.podLabels" }, + "podSecurityContext": { + "$ref": "#/$defs/helm-values.podSecurityContext" + }, "priorityClassName": { "$ref": "#/$defs/helm-values.priorityClassName" }, "resources": { "$ref": "#/$defs/helm-values.resources" }, + "securityContext": { + "$ref": "#/$defs/helm-values.securityContext" + }, "tolerations": { "$ref": "#/$defs/helm-values.tolerations" } @@ -320,6 +332,20 @@ "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used.", "type": "string" }, + "helm-values.livenessProbeSecurityContext": { + "default": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsUser": 0 + }, + "description": "Container security context for the liveness-probe container.", + "type": "object" + }, "helm-values.metrics": { "additionalProperties": false, "properties": { @@ -481,6 +507,20 @@ "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used.", "type": "string" }, + "helm-values.nodeDriverRegistrarSecurityContext": { + "default": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true, + "runAsUser": 0 + }, + "description": "Container security context for the node-driver-registrar container.", + "type": "object" + }, "helm-values.nodeSelector": { "default": { "kubernetes.io/os": "linux" @@ -528,6 +568,15 @@ "description": "Optional additional labels to add to the csi-driver pods.", "type": "object" }, + "helm-values.podSecurityContext": { + "default": { + "seccompProfile": { + "type": "RuntimeDefault" + } + }, + "description": "Pod-level security context for the csi-driver DaemonSet pods. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", + "type": "object" + }, "helm-values.priorityClassName": { "default": "", "description": "Optional priority class to be used for the csi-driver pods.", @@ -538,6 +587,20 @@ "description": "Kubernetes pod resources requests/limits for cert-manager-csi-driver.\n\nFor example:\nresources:\n limits:\n cpu: 100m\n memory: 128Mi\n requests:\n cpu: 100m\n memory: 128Mi", "type": "object" }, + "helm-values.securityContext": { + "default": { + "capabilities": { + "drop": [ + "ALL" + ] + }, + "privileged": true, + "readOnlyRootFilesystem": true, + "runAsUser": 0 + }, + "description": "Container security context for the cert-manager-csi-driver container.\n\nNOTE: privileged is required by default because this container mounts pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which. Kubernetes only permits for privileged containers. Setting privileged: false without also changing the mount propagation will prevent the driver pods from starting. See https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation", + "type": "object" + }, "helm-values.tolerations": { "default": [], "description": "Kubernetes pod tolerations for cert-manager-csi-driver.\n\nFor example:\ntolerations:\n- operator: \"Exists\"", diff --git a/deploy/charts/csi-driver/values.yaml b/deploy/charts/csi-driver/values.yaml index 921b3ad8..93aa8aa7 100644 --- a/deploy/charts/csi-driver/values.yaml +++ b/deploy/charts/csi-driver/values.yaml @@ -256,6 +256,49 @@ podAnnotations: {} # Optional additional labels to add to the csi-driver pods. podLabels: {} +# Pod-level security context for the csi-driver DaemonSet pods. +# For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). +# +docs:property +podSecurityContext: + seccompProfile: + type: RuntimeDefault + +# Container security context for the cert-manager-csi-driver container. +# +# NOTE: privileged is required by default because this container mounts +# pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which +# Kubernetes only permits for privileged containers. Setting privileged: false +# without also changing the mount propagation will prevent the driver pods from +# starting. See https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation +# +docs:property +securityContext: + runAsUser: 0 + privileged: true + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +# Container security context for the node-driver-registrar container. +# +docs:property +nodeDriverRegistrarSecurityContext: + runAsUser: 0 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +# Container security context for the liveness-probe container. +# +docs:property +livenessProbeSecurityContext: + runAsUser: 0 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + # Kubernetes pod resources requests/limits for cert-manager-csi-driver. # # For example: From 435900ba1231ef2975fcbf5761fda7d7a3818aba Mon Sep 17 00:00:00 2001 From: Aman Raj Date: Thu, 18 Jun 2026 21:27:18 +0530 Subject: [PATCH 2/2] fix(chart): scope configurable securityContext to pod and sidecars Following @wallrj-cyberark's empirical testing in #583, the cert-manager-csi-driver container must run privileged: it mounts pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which Kubernetes only permits for privileged containers. Exposing its securityContext let operators set privileged: false to satisfy a scanner and silently break the driver, so keep it hardcoded with an explanatory comment. Keep the pod-level securityContext and the two sidecar securityContext knobs (node-driver-registrar, liveness-probe), which are legitimate operator customisation points matching the cert-manager/trust-manager#836 precedent. Signed-off-by: Aman Raj --- deploy/charts/csi-driver/README.md | 15 ----------- .../csi-driver/templates/daemonset.yaml | 11 +++++--- .../tests/securitycontext_test.yaml | 26 ++++--------------- deploy/charts/csi-driver/values.schema.json | 17 ------------ deploy/charts/csi-driver/values.yaml | 16 ------------ 5 files changed, 13 insertions(+), 72 deletions(-) diff --git a/deploy/charts/csi-driver/README.md b/deploy/charts/csi-driver/README.md index af3dc02a..ffc4e25b 100644 --- a/deploy/charts/csi-driver/README.md +++ b/deploy/charts/csi-driver/README.md @@ -416,21 +416,6 @@ Optional additional labels to add to the csi-driver pods. Pod-level security context for the csi-driver DaemonSet pods. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). -#### **securityContext** ~ `object` -> Default value: -> ```yaml -> capabilities: -> drop: -> - ALL -> privileged: true -> readOnlyRootFilesystem: true -> runAsUser: 0 -> ``` - -Container security context for the cert-manager-csi-driver container. - -NOTE: privileged is required by default because this container mounts pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which. Kubernetes only permits for privileged containers. Setting privileged: false without also changing the mount propagation will prevent the driver pods from starting. See https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation - #### **nodeDriverRegistrarSecurityContext** ~ `object` > Default value: > ```yaml diff --git a/deploy/charts/csi-driver/templates/daemonset.yaml b/deploy/charts/csi-driver/templates/daemonset.yaml index 9369913f..79d75c2b 100644 --- a/deploy/charts/csi-driver/templates/daemonset.yaml +++ b/deploy/charts/csi-driver/templates/daemonset.yaml @@ -82,10 +82,15 @@ spec: mountPath: /plugin - name: cert-manager-csi-driver - {{- with .Values.securityContext }} + # This container mounts pods-mount-dir and csi-data-dir with + # mountPropagation: Bidirectional, which Kubernetes only permits for + # privileged containers, so it must run privileged. See + # https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation securityContext: - {{- toYaml . | nindent 12 }} - {{- end }} + runAsUser: 0 + privileged: true + capabilities: { drop: [ "ALL" ] } + readOnlyRootFilesystem: true image: "{{ template "cert-manager-csi-driver.image" (tuple .Values.image .Values.imageRegistry .Values.imageNamespace (printf ":%s" $.Chart.AppVersion)) }}" imagePullPolicy: {{ .Values.image.pullPolicy }} args : diff --git a/deploy/charts/csi-driver/tests/securitycontext_test.yaml b/deploy/charts/csi-driver/tests/securitycontext_test.yaml index 4e526180..fa7d9720 100644 --- a/deploy/charts/csi-driver/tests/securitycontext_test.yaml +++ b/deploy/charts/csi-driver/tests/securitycontext_test.yaml @@ -32,25 +32,16 @@ tests: path: spec.template.spec.securityContext.seccompProfile.type value: RuntimeDefault - - it: lets operators opt into a non-privileged context with CAP_SYS_ADMIN + - it: lets operators override a sidecar securityContext set: - securityContext: - runAsUser: 0 - privileged: false + nodeDriverRegistrarSecurityContext: + runAsUser: 1000 allowPrivilegeEscalation: false readOnlyRootFilesystem: true - capabilities: - add: - - SYS_ADMIN - drop: - - ALL asserts: - equal: - path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.privileged - value: false - - contains: - path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext.capabilities.add - content: SYS_ADMIN + path: spec.template.spec.containers[?(@.name=="node-driver-registrar")].securityContext.runAsUser + value: 1000 - it: lets operators override the pod-level securityContext set: @@ -66,10 +57,3 @@ tests: - equal: path: spec.template.spec.securityContext.fsGroup value: 1000 - - - it: omits the container securityContext entirely when set to null - set: - securityContext: null - asserts: - - notExists: - path: spec.template.spec.containers[?(@.name=="cert-manager-csi-driver")].securityContext diff --git a/deploy/charts/csi-driver/values.schema.json b/deploy/charts/csi-driver/values.schema.json index b68590d9..20c89239 100644 --- a/deploy/charts/csi-driver/values.schema.json +++ b/deploy/charts/csi-driver/values.schema.json @@ -69,9 +69,6 @@ "resources": { "$ref": "#/$defs/helm-values.resources" }, - "securityContext": { - "$ref": "#/$defs/helm-values.securityContext" - }, "tolerations": { "$ref": "#/$defs/helm-values.tolerations" } @@ -587,20 +584,6 @@ "description": "Kubernetes pod resources requests/limits for cert-manager-csi-driver.\n\nFor example:\nresources:\n limits:\n cpu: 100m\n memory: 128Mi\n requests:\n cpu: 100m\n memory: 128Mi", "type": "object" }, - "helm-values.securityContext": { - "default": { - "capabilities": { - "drop": [ - "ALL" - ] - }, - "privileged": true, - "readOnlyRootFilesystem": true, - "runAsUser": 0 - }, - "description": "Container security context for the cert-manager-csi-driver container.\n\nNOTE: privileged is required by default because this container mounts pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which. Kubernetes only permits for privileged containers. Setting privileged: false without also changing the mount propagation will prevent the driver pods from starting. See https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation", - "type": "object" - }, "helm-values.tolerations": { "default": [], "description": "Kubernetes pod tolerations for cert-manager-csi-driver.\n\nFor example:\ntolerations:\n- operator: \"Exists\"", diff --git a/deploy/charts/csi-driver/values.yaml b/deploy/charts/csi-driver/values.yaml index 93aa8aa7..30b6eec8 100644 --- a/deploy/charts/csi-driver/values.yaml +++ b/deploy/charts/csi-driver/values.yaml @@ -263,22 +263,6 @@ podSecurityContext: seccompProfile: type: RuntimeDefault -# Container security context for the cert-manager-csi-driver container. -# -# NOTE: privileged is required by default because this container mounts -# pods-mount-dir and csi-data-dir with mountPropagation: Bidirectional, which -# Kubernetes only permits for privileged containers. Setting privileged: false -# without also changing the mount propagation will prevent the driver pods from -# starting. See https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation -# +docs:property -securityContext: - runAsUser: 0 - privileged: true - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - # Container security context for the node-driver-registrar container. # +docs:property nodeDriverRegistrarSecurityContext: