From c907540979af86f20c6d54c5fe637bb8b1ce98bd Mon Sep 17 00:00:00 2001 From: Alexander Alexandrowitz Date: Mon, 8 Sep 2025 13:45:34 +0200 Subject: [PATCH 1/3] Added defaultInitContainerSecurityContext --- api/v1beta1/common_types.go | 4 + controllers/solrcloud_controller_test.go | 15 ++ controllers/util/solr_util.go | 12 +- helm/solr-operator/crds/crds.yaml | 150 ++++++++++++++++++ helm/solr/README.md | 1 + .../solr/templates/_custom_option_helpers.tpl | 4 + helm/solr/values.yaml | 3 + 7 files changed, 186 insertions(+), 3 deletions(-) diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 22002243..8f8105c3 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -161,6 +161,10 @@ type PodOptions struct { // DefaultInitContainerResources are the resource requirements for the default init container(s) created by the Solr Operator, if any are created. // +optional DefaultInitContainerResources corev1.ResourceRequirements `json:"defaultInitContainerResources,omitempty"` + + // DefaultInitContainerSecurityContext is the security context for the default init container(s) created by the Solr Operator, if any are created. + // +optional + DefaultInitContainerSecurityContext *corev1.SecurityContext `json:"defaultInitContainerSecurityContext,omitempty"` } // ServiceOptions defines custom options for services diff --git a/controllers/solrcloud_controller_test.go b/controllers/solrcloud_controller_test.go index b41f0527..0fdc731e 100644 --- a/controllers/solrcloud_controller_test.go +++ b/controllers/solrcloud_controller_test.go @@ -217,6 +217,12 @@ var _ = FDescribe("SolrCloud controller - General", func() { ServiceAccountName: testServiceAccountName, TopologySpreadConstraints: testTopologySpreadConstraints, DefaultInitContainerResources: testResources2, + DefaultInitContainerSecurityContext: &corev1.SecurityContext{ + RunAsNonRoot: newBoolPtr(true), + Capabilities: &corev1.Capabilities{ + Add: []corev1.Capability{"CHOWN", "DAC_OVERRIDE"}, + }, + }, InitContainers: extraContainers1, ContainerSecurityContext: &corev1.SecurityContext{ RunAsNonRoot: newBoolPtr(true), @@ -297,6 +303,15 @@ var _ = FDescribe("SolrCloud controller - General", func() { Expect(statefulSet.Spec.Template.Spec.InitContainers[0].Resources).To(Equal(testResources2), "Incorrect initContainer[0] resources") Expect(statefulSet.Spec.Template.Spec.InitContainers[1].Resources).To(Equal(testResources2), "Incorrect initContainer[1] resources") Expect(statefulSet.Spec.Template.Spec.InitContainers[2].Resources).ToNot(Equal(testResources2), "Incorrect initContainer[2] resources, should not use the default override") + Expect(statefulSet.Spec.Template.Spec.InitContainers[0].SecurityContext).To(Not(BeNil()), "InitContainer[0] should have security context") + Expect(statefulSet.Spec.Template.Spec.InitContainers[0].SecurityContext.RunAsNonRoot).To(PointTo(BeTrue()), "Incorrect initContainer[0] security context runAsNonRoot") + Expect(statefulSet.Spec.Template.Spec.InitContainers[0].SecurityContext.Capabilities.Add).To(HaveLen(2), "Incorrect number of capabilities in initContainer[0]") + Expect(statefulSet.Spec.Template.Spec.InitContainers[0].SecurityContext.Capabilities.Add).To(ContainElements(corev1.Capability("CHOWN"), corev1.Capability("DAC_OVERRIDE")), "Incorrect capabilities in initContainer[0]") + Expect(statefulSet.Spec.Template.Spec.InitContainers[1].SecurityContext).To(Not(BeNil()), "InitContainer[1] should have security context") + Expect(statefulSet.Spec.Template.Spec.InitContainers[1].SecurityContext.RunAsNonRoot).To(PointTo(BeTrue()), "Incorrect initContainer[1] security context runAsNonRoot") + Expect(statefulSet.Spec.Template.Spec.InitContainers[1].SecurityContext.Capabilities.Add).To(HaveLen(2), "Incorrect number of capabilities in initContainer[1]") + Expect(statefulSet.Spec.Template.Spec.InitContainers[1].SecurityContext.Capabilities.Add).To(ContainElements(corev1.Capability("CHOWN"), corev1.Capability("DAC_OVERRIDE")), "Incorrect capabilities in initContainer[1]") + Expect(statefulSet.Spec.Template.Spec.InitContainers[2].SecurityContext).To(BeNil(), "InitContainer[2] should not have custom security context since it's user-provided") Expect(statefulSet.Spec.Template.Spec.Tolerations).To(Equal(testTolerations), "Incorrect Tolerations for Pod") Expect(statefulSet.Spec.Template.Spec.PriorityClassName).To(Equal(testPriorityClass), "Incorrect Priority class name for Pod Spec") Expect(statefulSet.Spec.Template.Spec.ImagePullSecrets).To(ConsistOf(append(testAdditionalImagePullSecrets, corev1.LocalObjectReference{Name: testImagePullSecretName})), "Incorrect imagePullSecrets") diff --git a/controllers/util/solr_util.go b/controllers/util/solr_util.go index 50fdbc48..56a456b6 100644 --- a/controllers/util/solr_util.go +++ b/controllers/util/solr_util.go @@ -781,13 +781,19 @@ func generateSolrSetupInitContainers(solrCloud *solr.SolrCloud, solrCloudStatus containers = append(containers, zkSetupContainer) } - // If the user has provided custom resources for the default init containers, use them + // If the user has provided custom resources or security context for the default init containers, use them customPodOptions := solrCloud.Spec.CustomSolrKubeOptions.PodOptions if nil != customPodOptions { resources := customPodOptions.DefaultInitContainerResources - if resources.Limits != nil || resources.Requests != nil { + securityContext := customPodOptions.DefaultInitContainerSecurityContext + if resources.Limits != nil || resources.Requests != nil || securityContext != nil { for i := range containers { - containers[i].Resources = resources + if resources.Limits != nil || resources.Requests != nil { + containers[i].Resources = resources + } + if securityContext != nil { + containers[i].SecurityContext = securityContext + } } } } diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml index a1229dcf..8b2123f3 100644 --- a/helm/solr-operator/crds/crds.yaml +++ b/helm/solr-operator/crds/crds.yaml @@ -3660,6 +3660,81 @@ spec: More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object + defaultInitContainerSecurityContext: + description: DefaultInitContainerSecurityContext is the security + context for the default init container(s) created by the Solr + Operator, if any are created. + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + type: object envVars: description: Additional environment variables to pass to the default container. @@ -19172,6 +19247,81 @@ spec: More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ type: object type: object + defaultInitContainerSecurityContext: + description: DefaultInitContainerSecurityContext is the security + context for the default init container(s) created by the Solr + Operator, if any are created. + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities type + type: string + type: array + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + type: object envVars: description: Additional environment variables to pass to the default container. diff --git a/helm/solr/README.md b/helm/solr/README.md index a02cfa10..05fcc5c3 100644 --- a/helm/solr/README.md +++ b/helm/solr/README.md @@ -280,6 +280,7 @@ When using the helm chart, omit `customSolrKubeOptions.` | podOptions.resources.requests | map[string]string | | Provide Resource requests for the Solr container | | podOptions.defaultInitContainerResources.limits | map[string]string | | Provide Resource limits for Solr's default initContainer(s) | | podOptions.defaultInitContainerResources.requests | map[string]string | | Provide Resource requests for Solr's default initContainer(s) | +| podOptions.defaultInitContainerSecurityContext | object | | Provide SecurityContext for Solr's default initContainer(s) | | podOptions.nodeSelector | map[string]string | | Add a node selector for the Solr pod, to specify where it can be scheduled | | podOptions.affinity | object | | Add Kubernetes affinity information for the Solr pod | | podOptions.tolerations | []object | | Specify a list of Kubernetes tolerations for the Solr pod | diff --git a/helm/solr/templates/_custom_option_helpers.tpl b/helm/solr/templates/_custom_option_helpers.tpl index 34f72981..6555e360 100644 --- a/helm/solr/templates/_custom_option_helpers.tpl +++ b/helm/solr/templates/_custom_option_helpers.tpl @@ -109,6 +109,10 @@ topologySpreadConstraints: defaultInitContainerResources: {{- toYaml .Values.podOptions.defaultInitContainerResources | nindent 2 }} {{ end }} +{{- if .Values.podOptions.defaultInitContainerSecurityContext -}} +defaultInitContainerSecurityContext: + {{- toYaml .Values.podOptions.defaultInitContainerSecurityContext | nindent 2 }} +{{ end }} {{- end -}} {{/* diff --git a/helm/solr/values.yaml b/helm/solr/values.yaml index e6addba7..c59b932c 100644 --- a/helm/solr/values.yaml +++ b/helm/solr/values.yaml @@ -335,6 +335,9 @@ podOptions: # Resources for the init containers created by the Solr Operator defaultInitContainerResources: {} + # Security context for the init containers created by the Solr Operator + defaultInitContainerSecurityContext: {} + volumes: [] # - name: # defaultContainerMount: {} From d2e51017e39dd85babd8f19583cbb7a8a316f7df Mon Sep 17 00:00:00 2001 From: Alexander Alexandrowitz Date: Thu, 11 Sep 2025 08:15:20 +0200 Subject: [PATCH 2/3] fixed formatting --- controllers/solrcloud_controller_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/solrcloud_controller_test.go b/controllers/solrcloud_controller_test.go index 0fdc731e..10167ffc 100644 --- a/controllers/solrcloud_controller_test.go +++ b/controllers/solrcloud_controller_test.go @@ -223,7 +223,7 @@ var _ = FDescribe("SolrCloud controller - General", func() { Add: []corev1.Capability{"CHOWN", "DAC_OVERRIDE"}, }, }, - InitContainers: extraContainers1, + InitContainers: extraContainers1, ContainerSecurityContext: &corev1.SecurityContext{ RunAsNonRoot: newBoolPtr(true), ReadOnlyRootFilesystem: newBoolPtr(true), From 93edd1307f04997c1a40493aecaf2af2a7d20a29 Mon Sep 17 00:00:00 2001 From: Alexander Alexandrowitz Date: Mon, 24 Nov 2025 11:29:37 +0100 Subject: [PATCH 3/3] added changelog entry --- helm/solr-operator/Chart.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/helm/solr-operator/Chart.yaml b/helm/solr-operator/Chart.yaml index fb16b8e8..2e6871b3 100644 --- a/helm/solr-operator/Chart.yaml +++ b/helm/solr-operator/Chart.yaml @@ -72,6 +72,13 @@ annotations: url: https://github.com/apache/solr-operator/issues/778 - name: Github PR url: https://github.com/apache/solr-operator/pull/779 + - kind: added + description: Ability to set a securityContext for the default initContainers + links: + - name: Github Issue + url: https://github.com/apache/solr-operator/issues/797 + - name: Github PR + url: https://github.com/apache/solr-operator/pull/796 artifacthub.io/images: | - name: solr-operator image: apache/solr-operator:v0.10.0-prerelease