From a8eeddc6c8d84f567c3e0edf515f6d9ae951a5b6 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 17 Jun 2025 14:41:36 +0300 Subject: [PATCH 1/4] The Operator configures a default Pod securityContext if one is not configured in the Coherence resource spec --- api/v1/coherenceresourcespec_types.go | 27 ++++++++++++++++++++++++++- api/v1/common_test.go | 1 + api/v1/constants.go | 9 +++++++++ api/v1/create_statefulset_test.go | 4 ++-- docs/about/04_coherence_spec.adoc | 10 +++++++++- 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 6e9001f2f..b31c5c99f 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -193,6 +193,14 @@ type CoherenceResourceSpec struct { // +optional Tolerations []corev1.Toleration `json:"tolerations,omitempty"` // SecurityContext is the PodSecurityContext that will be added to all the Pods in this deployment. + // If no security context is specified the Operator will create one with the following spec + // + // securityContext: + // runAsNonRoot: true + // runAsUser: 1000 + // runAsGroup: 2000 + // fsGroup: 2000 + // // See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ // +optional SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"` @@ -739,7 +747,7 @@ func (in *CoherenceResourceSpec) CreatePodTemplateSpec(deployment CoherenceResou ReadinessGates: in.ReadinessGates, RuntimeClassName: in.RuntimeClassName, SchedulerName: notNilString(in.SchedulerName), - SecurityContext: in.SecurityContext, + SecurityContext: in.GetSecurityContext(), ServiceAccountName: in.GetServiceAccountName(), ShareProcessNamespace: in.ShareProcessNamespace, Tolerations: in.Tolerations, @@ -821,6 +829,23 @@ func (in *CoherenceResourceSpec) GetImagePullSecrets() []corev1.LocalObjectRefer return secrets } +// GetSecurityContext returns the Pod security context to use. +func (in *CoherenceResourceSpec) GetSecurityContext() *corev1.PodSecurityContext { + if in == nil || in.SecurityContext == nil { + return DefaultSecurityContext() + } + return in.SecurityContext +} + +func DefaultSecurityContext() *corev1.PodSecurityContext { + return &corev1.PodSecurityContext{ + RunAsNonRoot: ptr.To(DefaultRunAsNonRoot), + RunAsUser: ptr.To(DefaultRunAsUser), + RunAsGroup: ptr.To(DefaultRunAsGroup), + FSGroup: ptr.To(DefaultFsGroup), + } +} + // GetServiceAccountName returns the service account name for the cluster. func (in *CoherenceResourceSpec) GetServiceAccountName() string { if in != nil { diff --git a/api/v1/common_test.go b/api/v1/common_test.go index e8bf465c7..aced0c4fb 100644 --- a/api/v1/common_test.go +++ b/api/v1/common_test.go @@ -503,6 +503,7 @@ func createMinimalExpectedPodSpec(deployment coh.CoherenceResource) corev1.PodTe VolumeSource: emptyVolume, }, }, + SecurityContext: coh.DefaultSecurityContext(), TopologySpreadConstraints: spec.EnsureTopologySpreadConstraints(deployment), Affinity: spec.CreateDefaultPodAffinity(deployment), ServiceAccountName: spec.GetServiceAccountName(), diff --git a/api/v1/constants.go b/api/v1/constants.go index 1279f7dca..6c5c797a3 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -74,6 +74,15 @@ const ( // DefaultServiceAccount is the default k8s service account name. DefaultServiceAccount = "default" + // DefaultRunAsNonRoot is the default value for the runAsNonRoot field in the Pod security context + DefaultRunAsNonRoot = true + // DefaultRunAsUser is the default value for the runAsUser field in the Pod security context + DefaultRunAsUser int64 = 1000 + // DefaultRunAsGroup is the default value for the runAsGroup field in the Pod security context + DefaultRunAsGroup int64 = 2000 + // DefaultFsGroup is the default value for the fsGroup field in the Pod security context + DefaultFsGroup int64 = DefaultRunAsGroup + // ContainerNameCoherence is the Coherence container name ContainerNameCoherence = "coherence" // ContainerNameOperatorInit is the Operator init-container name diff --git a/api/v1/create_statefulset_test.go b/api/v1/create_statefulset_test.go index 920fcb1a6..bb17e02f2 100644 --- a/api/v1/create_statefulset_test.go +++ b/api/v1/create_statefulset_test.go @@ -405,8 +405,8 @@ func TestCreateStatefulSetWithTolerations(t *testing.T) { func TestCreateStatefulSetWithSecurityContext(t *testing.T) { ctx := corev1.PodSecurityContext{ - RunAsUser: ptr.To(int64(1000)), - RunAsNonRoot: boolPtr(true), + RunAsUser: ptr.To(int64(5000)), + RunAsNonRoot: boolPtr(false), } spec := coh.CoherenceResourceSpec{ diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index a7b4475bc..f10597d97 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -332,7 +332,15 @@ For example: + effect: "NoSchedule" + + + ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + m| []https://{k8s-doc-link}/#toleration-v1-core[corev1.Toleration] | false -m| securityContext | SecurityContext is the PodSecurityContext that will be added to all the Pods in this deployment. See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ m| *https://{k8s-doc-link}/#podsecuritycontext-v1-core[corev1.PodSecurityContext] | false +m| securityContext | SecurityContext is the PodSecurityContext that will be added to all the Pods in this deployment. If no security context is specified the Operator will create one with the following spec + + + + securityContext: + + + runAsNonRoot: true + + + runAsUser: 1000 + + + runAsGroup: 2000 + + + fsGroup: 2000 + + + + +See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ m| *https://{k8s-doc-link}/#podsecuritycontext-v1-core[corev1.PodSecurityContext] | false m| containerSecurityContext | ContainerSecurityContext is the SecurityContext that will be added to the Coherence container in each Pod in this deployment. See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ m| *https://{k8s-doc-link}/#securitycontext-v1-core[corev1.SecurityContext] | false m| shareProcessNamespace | Share a single process namespace between all the containers in a pod. When this is set containers will be able to view and signal processes from other containers in the same pod, and the first process in each container will not be assigned PID 1. HostPID and ShareProcessNamespace cannot both be set. Optional: Default to false. m| *bool | false m| hostIPC | Use the host's ipc namespace. Optional: Default to false. m| *bool | false From 96c1d2de53e3f4cef95f470d6ec3d0ec94da99b2 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 17 Jun 2025 17:28:19 +0300 Subject: [PATCH 2/4] Fix tests --- api/v1/coherenceresourcespec_types.go | 28 ++++++++++++---------- api/v1/constants.go | 7 +++++- docs/about/04_coherence_spec.adoc | 1 + test/e2e/remote/persistence-on-demand.yaml | 1 + 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index b31c5c99f..4d24bf5b2 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -200,6 +200,7 @@ type CoherenceResourceSpec struct { // runAsUser: 1000 // runAsGroup: 2000 // fsGroup: 2000 + // fsGroupChangePolicy: "OnRootMismatch" // // See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ // +optional @@ -839,10 +840,11 @@ func (in *CoherenceResourceSpec) GetSecurityContext() *corev1.PodSecurityContext func DefaultSecurityContext() *corev1.PodSecurityContext { return &corev1.PodSecurityContext{ - RunAsNonRoot: ptr.To(DefaultRunAsNonRoot), - RunAsUser: ptr.To(DefaultRunAsUser), - RunAsGroup: ptr.To(DefaultRunAsGroup), - FSGroup: ptr.To(DefaultFsGroup), + RunAsNonRoot: ptr.To(DefaultRunAsNonRoot), + RunAsUser: ptr.To(DefaultRunAsUser), + RunAsGroup: ptr.To(DefaultRunAsGroup), + FSGroup: ptr.To(DefaultFsGroup), + FSGroupChangePolicy: ptr.To(DefaultFSGroupChangePolicy), } } @@ -951,25 +953,25 @@ func (in *CoherenceResourceSpec) CreateCommonEnv(deployment CoherenceResource) [ env := []corev1.EnvVar{ { Name: EnvVarCohMachineName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", - }, + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "spec.nodeName", }, }, + }, { Name: EnvVarCohMemberName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.name", - }, + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", }, }, + }, { Name: EnvVarCohPodUID, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.uid", - }, + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.uid", }, }, + }, {Name: EnvVarCohRole, Value: deployment.GetRoleName()}, } diff --git a/api/v1/constants.go b/api/v1/constants.go index 6c5c797a3..4afac0d90 100644 --- a/api/v1/constants.go +++ b/api/v1/constants.go @@ -6,7 +6,10 @@ package v1 -import "github.com/oracle/coherence-operator/pkg/operator" +import ( + "github.com/oracle/coherence-operator/pkg/operator" + corev1 "k8s.io/api/core/v1" +) const ( // DefaultReplicas is the default number of replicas that will be created for a deployment if no value is specified in the spec @@ -82,6 +85,8 @@ const ( DefaultRunAsGroup int64 = 2000 // DefaultFsGroup is the default value for the fsGroup field in the Pod security context DefaultFsGroup int64 = DefaultRunAsGroup + // DefaultFSGroupChangePolicy is the default value for the fsGroup field in the Pod security context + DefaultFSGroupChangePolicy = corev1.FSGroupChangeOnRootMismatch // ContainerNameCoherence is the Coherence container name ContainerNameCoherence = "coherence" diff --git a/docs/about/04_coherence_spec.adoc b/docs/about/04_coherence_spec.adoc index f10597d97..e8ce31571 100644 --- a/docs/about/04_coherence_spec.adoc +++ b/docs/about/04_coherence_spec.adoc @@ -339,6 +339,7 @@ m| securityContext | SecurityContext is the PodSecurityContext that will be adde runAsUser: 1000 + + runAsGroup: 2000 + + fsGroup: 2000 + + + fsGroupChangePolicy: "OnRootMismatch" + + + See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ m| *https://{k8s-doc-link}/#podsecuritycontext-v1-core[corev1.PodSecurityContext] | false m| containerSecurityContext | ContainerSecurityContext is the SecurityContext that will be added to the Coherence container in each Pod in this deployment. See: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ m| *https://{k8s-doc-link}/#securitycontext-v1-core[corev1.SecurityContext] | false diff --git a/test/e2e/remote/persistence-on-demand.yaml b/test/e2e/remote/persistence-on-demand.yaml index dc1ad0811..e6f961939 100644 --- a/test/e2e/remote/persistence-on-demand.yaml +++ b/test/e2e/remote/persistence-on-demand.yaml @@ -16,6 +16,7 @@ spec: jvm: args: - "-Dcoherence.operator.health.logs=true" + - "-Dcoherence.distributed.persistence.base.dir=/coherence" application: main: com.oracle.coherence.k8s.testing.RestServer ports: From f599ff4e1f51a440d7039191ea14abaf1be83aff Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 17 Jun 2025 17:32:04 +0300 Subject: [PATCH 3/4] Fix tests --- api/v1/coherenceresourcespec_types.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/api/v1/coherenceresourcespec_types.go b/api/v1/coherenceresourcespec_types.go index 4d24bf5b2..cd197b5a8 100644 --- a/api/v1/coherenceresourcespec_types.go +++ b/api/v1/coherenceresourcespec_types.go @@ -953,25 +953,25 @@ func (in *CoherenceResourceSpec) CreateCommonEnv(deployment CoherenceResource) [ env := []corev1.EnvVar{ { Name: EnvVarCohMachineName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "spec.nodeName", + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "spec.nodeName", + }, }, }, - }, { Name: EnvVarCohMemberName, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.name", + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.name", + }, }, }, - }, { Name: EnvVarCohPodUID, ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - FieldPath: "metadata.uid", + FieldRef: &corev1.ObjectFieldSelector{ + FieldPath: "metadata.uid", + }, }, }, - }, {Name: EnvVarCohRole, Value: deployment.GetRoleName()}, } From 75a7e99111f3ae651d4347d3751e280d001f1618 Mon Sep 17 00:00:00 2001 From: Jonathan Knight Date: Tue, 17 Jun 2025 19:26:06 +0300 Subject: [PATCH 4/4] Doc update --- docs/other/045_security_context.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/other/045_security_context.adoc b/docs/other/045_security_context.adoc index bde70e6c9..242760bd5 100644 --- a/docs/other/045_security_context.adoc +++ b/docs/other/045_security_context.adoc @@ -16,6 +16,20 @@ Kubernetes allows you to configure a https://kubernetes.io/docs/tasks/configure- For more details see the Kubernetes https://kubernetes.io/docs/tasks/configure-pod-container/security-context/[Security Context] documentation. +The Coherence Operator configures a default security context for the Coherence Pods is none is specified in the `Coherence` resource yaml. +The default security context looks like this: +[source,yaml] +---- +securityContext: + runAsNonRoot: true + runAsUser: 1000 + runAsGroup: 2000 + fsGroup: 2000 + fsGroupChangePolicy: "OnRootMismatch" +---- + +It is possible to override this as described below. + === Setting the Pod Security Context To specify security settings for a Pod, include the `securityContext` field in the Coherence resource specification.