Skip to content

Commit e840613

Browse files
authored
CLOUDP-127633 Use read-only filesystem (#1042)
* CLOUDP-127633 Use read-only filesystem * Update the project layout to be acceptable by the operator-sdk * Moved SecurityContext to podspec_template.go
1 parent 24aa5b6 commit e840613

File tree

10 files changed

+93
-28
lines changed

10 files changed

+93
-28
lines changed

PROJECT

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
domain: mongodb.com
2-
layout: go.kubebuilder.io/v3
2+
layout:
3+
- go.kubebuilder.io/v3
4+
plugins:
5+
manifests.sdk.operatorframework.io/v2: {}
6+
scorecard.sdk.operatorframework.io/v2: {}
37
projectName: mko-v1
48
repo: github.com/mongodb/mongodb-kubernetes-operator
59
resources:
6-
- crdVersion: v1
10+
- api:
11+
crdVersion: v1
12+
namespaced: true
713
group: mongodbcommunity
814
kind: MongoDBCommunity
915
version: v1
10-
version: 3-alpha
11-
plugins:
12-
manifests.sdk.operatorframework.io/v2: {}
13-
scorecard.sdk.operatorframework.io/v2: {}
16+
- api:
17+
crdVersion: v1
18+
namespaced: true
19+
controller: true
20+
domain: mongodb.com
21+
group: mongodbcommunity
22+
kind: SimpleMongoDBCommunity
23+
path: github.com/mongodb/mongodb-kubernetes-operator/api/v1alpha1
24+
version: v1alpha1
25+
version: "3"

controllers/construct/build_statefulset_test.go

+22-6
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func TestManagedSecurityContext(t *testing.T) {
6666
_ = os.Setenv(MongodbRepoUrl, "repo")
6767
_ = os.Setenv(MongodbImageEnv, "mongo")
6868
_ = os.Setenv(AgentImageEnv, "agent-image")
69-
_ = os.Setenv(ManagedSecurityContextEnv, "true")
69+
_ = os.Setenv(podtemplatespec.ManagedSecurityContextEnv, "true")
7070

7171
mdb := newTestReplicaSet()
7272
stsFunc := BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, mdb)
@@ -105,7 +105,7 @@ func assertStatefulSetIsBuiltCorrectly(t *testing.T, mdb mdbv1.MongoDBCommunity,
105105
assert.Len(t, sts.Spec.Template.Spec.Containers[0].Env, 4)
106106
assert.Len(t, sts.Spec.Template.Spec.Containers[1].Env, 1)
107107

108-
managedSecurityContext := envvar.ReadBool(ManagedSecurityContextEnv)
108+
managedSecurityContext := envvar.ReadBool(podtemplatespec.ManagedSecurityContextEnv)
109109
if !managedSecurityContext {
110110
assert.NotNil(t, sts.Spec.Template.Spec.SecurityContext)
111111
assert.Equal(t, podtemplatespec.DefaultPodSecurityContext(), *sts.Spec.Template.Spec.SecurityContext)
@@ -118,9 +118,14 @@ func assertStatefulSetIsBuiltCorrectly(t *testing.T, mdb mdbv1.MongoDBCommunity,
118118
probe := agentContainer.ReadinessProbe
119119
assert.True(t, reflect.DeepEqual(probes.New(DefaultReadiness()), *probe))
120120
assert.Equal(t, probes.New(DefaultReadiness()).FailureThreshold, probe.FailureThreshold)
121-
assert.Len(t, agentContainer.VolumeMounts, 6)
121+
assert.Len(t, agentContainer.VolumeMounts, 7)
122122
assert.NotNil(t, agentContainer.ReadinessProbe)
123-
assert.Nil(t, agentContainer.SecurityContext)
123+
if !managedSecurityContext {
124+
assert.NotNil(t, sts.Spec.Template.Spec.Containers[0].SecurityContext)
125+
assert.Equal(t, container.DefaultSecurityContext(), *sts.Spec.Template.Spec.Containers[0].SecurityContext)
126+
} else {
127+
assert.Nil(t, agentContainer.SecurityContext)
128+
}
124129

125130
assertContainsVolumeMountWithName(t, agentContainer.VolumeMounts, "agent-scripts")
126131
assertContainsVolumeMountWithName(t, agentContainer.VolumeMounts, "automation-config")
@@ -131,8 +136,13 @@ func assertStatefulSetIsBuiltCorrectly(t *testing.T, mdb mdbv1.MongoDBCommunity,
131136

132137
mongodContainer := sts.Spec.Template.Spec.Containers[1]
133138
assert.Equal(t, "repo/mongo:4.2.2", mongodContainer.Image)
134-
assert.Len(t, mongodContainer.VolumeMounts, 5)
135-
assert.Nil(t, mongodContainer.SecurityContext)
139+
assert.Len(t, mongodContainer.VolumeMounts, 6)
140+
if !managedSecurityContext {
141+
assert.NotNil(t, sts.Spec.Template.Spec.Containers[1].SecurityContext)
142+
assert.Equal(t, container.DefaultSecurityContext(), *sts.Spec.Template.Spec.Containers[1].SecurityContext)
143+
} else {
144+
assert.Nil(t, agentContainer.SecurityContext)
145+
}
136146

137147
assertContainsVolumeMountWithName(t, mongodContainer.VolumeMounts, "data-volume")
138148
assertContainsVolumeMountWithName(t, mongodContainer.VolumeMounts, "healthstatus")
@@ -144,6 +154,12 @@ func assertStatefulSetIsBuiltCorrectly(t *testing.T, mdb mdbv1.MongoDBCommunity,
144154
assert.Equal(t, versionUpgradeHookName, initContainer.Name)
145155
assert.Equal(t, "version-upgrade-hook-image", initContainer.Image)
146156
assert.Len(t, initContainer.VolumeMounts, 1)
157+
if !managedSecurityContext {
158+
assert.NotNil(t, sts.Spec.Template.Spec.InitContainers[0].SecurityContext)
159+
assert.Equal(t, container.DefaultSecurityContext(), *sts.Spec.Template.Spec.InitContainers[0].SecurityContext)
160+
} else {
161+
assert.Nil(t, agentContainer.SecurityContext)
162+
}
147163
}
148164

149165
func assertContainsVolumeMountWithName(t *testing.T, mounts []corev1.VolumeMount, name string) {

controllers/construct/mongodbstatefulset.go

+17-9
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/probes"
1313
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/resourcerequirements"
1414
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/statefulset"
15-
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/envvar"
1615
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/scale"
1716
appsv1 "k8s.io/api/apps/v1"
1817
"k8s.io/apimachinery/pkg/types"
@@ -42,7 +41,6 @@ const (
4241
MongodbImageEnv = "MONGODB_IMAGE"
4342
VersionUpgradeHookImageEnv = "VERSION_UPGRADE_HOOK_IMAGE"
4443
ReadinessProbeImageEnv = "READINESS_PROBE_IMAGE"
45-
ManagedSecurityContextEnv = "MANAGED_SECURITY_CONTEXT"
4644

4745
automationMongodConfFileName = "automation-mongod.conf"
4846
keyfileFilePath = "/var/lib/mongodb-mms-automation/authentication/keyfile"
@@ -115,12 +113,16 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe
115113
scriptsVolume := statefulset.CreateVolumeFromEmptyDir("agent-scripts")
116114
scriptsVolumeMount := statefulset.CreateVolumeMount(scriptsVolume.Name, "/opt/scripts", statefulset.WithReadOnly(false))
117115

116+
// tmp volume is required by the mongodb-agent and mongod
117+
tmpVolume := statefulset.CreateVolumeFromEmptyDir("tmp")
118+
tmpVolumeMount := statefulset.CreateVolumeMount(tmpVolume.Name, "/tmp", statefulset.WithReadOnly(false))
119+
118120
keyFileNsName := mdb.GetAgentKeyfileSecretNamespacedName()
119121
keyFileVolume := statefulset.CreateVolumeFromEmptyDir(keyFileNsName.Name)
120122
keyFileVolumeVolumeMount := statefulset.CreateVolumeMount(keyFileVolume.Name, "/var/lib/mongodb-mms-automation/authentication", statefulset.WithReadOnly(false))
121123
keyFileVolumeVolumeMountMongod := statefulset.CreateVolumeMount(keyFileVolume.Name, "/var/lib/mongodb-mms-automation/authentication", statefulset.WithReadOnly(false))
122124

123-
mongodbAgentVolumeMounts := []corev1.VolumeMount{agentHealthStatusVolumeMount, scriptsVolumeMount, keyFileVolumeVolumeMount}
125+
mongodbAgentVolumeMounts := []corev1.VolumeMount{agentHealthStatusVolumeMount, scriptsVolumeMount, keyFileVolumeVolumeMount, tmpVolumeMount}
124126

125127
automationConfigVolumeFunc := podtemplatespec.NOOP()
126128
if mdb.NeedsAutomationConfigVolume() {
@@ -129,7 +131,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe
129131
automationConfigVolumeMount := statefulset.CreateVolumeMount(automationConfigVolume.Name, "/var/lib/automation/config", statefulset.WithReadOnly(true))
130132
mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, automationConfigVolumeMount)
131133
}
132-
mongodVolumeMounts := []corev1.VolumeMount{mongodHealthStatusVolumeMount, hooksVolumeMount, keyFileVolumeVolumeMountMongod}
134+
mongodVolumeMounts := []corev1.VolumeMount{mongodHealthStatusVolumeMount, hooksVolumeMount, keyFileVolumeVolumeMountMongod, tmpVolumeMount}
133135
dataVolumeClaim := statefulset.NOOP()
134136
logVolumeClaim := statefulset.NOOP()
135137
singleModeVolumeClaim := func(s *appsv1.StatefulSet) {}
@@ -150,11 +152,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe
150152
singleModeVolumeClaim = statefulset.WithVolumeClaim(mdb.DataVolumeName(), dataPvc(mdb.DataVolumeName()))
151153
}
152154

153-
podSecurityContext := podtemplatespec.NOOP()
154-
managedSecurityContext := envvar.ReadBool(ManagedSecurityContextEnv)
155-
if !managedSecurityContext {
156-
podSecurityContext = podtemplatespec.WithSecurityContext(podtemplatespec.DefaultPodSecurityContext())
157-
}
155+
podSecurityContext, _ := podtemplatespec.WithDefaultSecurityContextsModifications()
158156

159157
return statefulset.Apply(
160158
statefulset.WithName(mdb.GetName()),
@@ -175,6 +173,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe
175173
podtemplatespec.WithVolume(hooksVolume),
176174
automationConfigVolumeFunc,
177175
podtemplatespec.WithVolume(scriptsVolume),
176+
podtemplatespec.WithVolume(tmpVolume),
178177
podtemplatespec.WithVolume(keyFileVolume),
179178
podtemplatespec.WithServiceAccount(mongodbDatabaseServiceAccountName),
180179
podtemplatespec.WithContainer(AgentName, mongodbAgentContainer(mdb.AutomationConfigSecretName(), mongodbAgentVolumeMounts)),
@@ -194,6 +193,7 @@ func AutomationAgentCommand() []string {
194193
}
195194

196195
func mongodbAgentContainer(automationConfigSecretName string, volumeMounts []corev1.VolumeMount) container.Modification {
196+
_, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications()
197197
return container.Apply(
198198
container.WithName(AgentName),
199199
container.WithImage(os.Getenv(AgentImageEnv)),
@@ -202,6 +202,7 @@ func mongodbAgentContainer(automationConfigSecretName string, volumeMounts []cor
202202
container.WithResourceRequirements(resourcerequirements.Defaults()),
203203
container.WithVolumeMounts(volumeMounts),
204204
container.WithCommand(AutomationAgentCommand()),
205+
containerSecurityContext,
205206
container.WithEnvs(
206207
corev1.EnvVar{
207208
Name: headlessAgentEnv,
@@ -229,12 +230,14 @@ func mongodbAgentContainer(automationConfigSecretName string, volumeMounts []cor
229230
}
230231

231232
func versionUpgradeHookInit(volumeMount []corev1.VolumeMount) container.Modification {
233+
_, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications()
232234
return container.Apply(
233235
container.WithName(versionUpgradeHookName),
234236
container.WithCommand([]string{"cp", "version-upgrade-hook", "/hooks/version-upgrade"}),
235237
container.WithImage(os.Getenv(VersionUpgradeHookImageEnv)),
236238
container.WithImagePullPolicy(corev1.PullAlways),
237239
container.WithVolumeMounts(volumeMount),
240+
containerSecurityContext,
238241
)
239242
}
240243

@@ -265,12 +268,14 @@ func logsPvc(logsVolumeName string) persistentvolumeclaim.Modification {
265268
// readinessProbeInit returns a modification function which will add the readiness probe container.
266269
// this container will copy the readiness probe binary into the /opt/scripts directory.
267270
func readinessProbeInit(volumeMount []corev1.VolumeMount) container.Modification {
271+
_, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications()
268272
return container.Apply(
269273
container.WithName(ReadinessProbeContainerName),
270274
container.WithCommand([]string{"cp", "/probes/readinessprobe", "/opt/scripts/readinessprobe"}),
271275
container.WithImage(os.Getenv(ReadinessProbeImageEnv)),
272276
container.WithImagePullPolicy(corev1.PullAlways),
273277
container.WithVolumeMounts(volumeMount),
278+
containerSecurityContext,
274279
)
275280
}
276281

@@ -303,11 +308,14 @@ exec mongod -f %s;
303308
mongoDbCommand,
304309
}
305310

311+
_, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications()
312+
306313
return container.Apply(
307314
container.WithName(MongodbName),
308315
container.WithImage(getMongoDBImage(version)),
309316
container.WithResourceRequirements(resourcerequirements.Defaults()),
310317
container.WithCommand(containerCommand),
318+
containerSecurityContext,
311319
container.WithEnvs(
312320
corev1.EnvVar{
313321
Name: agentHealthStatusFilePathEnv,

controllers/mongodb_tls_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func TestStatefulSet_IsCorrectlyConfiguredWithTLS(t *testing.T) {
4141
}
4242

4343
func assertStatefulsetVolumesAndVolumeMounts(t *testing.T, sts appsv1.StatefulSet, expectedTLSCASecretName string, expectedTLSOperatorSecretName string) {
44-
assert.Len(t, sts.Spec.Template.Spec.Volumes, 7)
44+
assert.Len(t, sts.Spec.Template.Spec.Volumes, 8)
4545
permission := int32(416)
4646
assert.Contains(t, sts.Spec.Template.Spec.Volumes, corev1.Volume{
4747
Name: "tls-ca",

docs/RELEASE_NOTES.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ If above conditions are met, it is strongly advised to upgrade the MongoDB Kuber
2323
- The names of connection string secrets generated for configured users are RFC1123 validated.
2424
- Changes
2525
- Support for changing port number in running cluster.
26+
- Security Context is now defined on pod level (previously was on container level)
27+
- Our containers now use the `readOnlyRootFilesystem` setting.
2628

2729
## MongoDBCommunity Resource
2830

cmd/manager/main.go main.go

File renamed without changes.

pkg/kube/container/container_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestContainer(t *testing.T) {
2020
WithImage("image"),
2121
WithImagePullPolicy(corev1.PullAlways),
2222
WithPorts([]corev1.ContainerPort{{Name: "port-1", ContainerPort: int32(1000)}}),
23-
WithSecurityContext(&corev1.SecurityContext{
23+
WithSecurityContext(corev1.SecurityContext{
2424
RunAsGroup: int64Ref(100),
2525
RunAsNonRoot: boolRef(true),
2626
}),

pkg/kube/container/containers.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,16 @@ func WithPorts(ports []corev1.ContainerPort) Modification {
177177
}
178178
}
179179

180-
// WithSecurityContext sets teh container's SecurityContext
181-
func WithSecurityContext(context *corev1.SecurityContext) Modification {
180+
// WithSecurityContext sets the container's SecurityContext
181+
func WithSecurityContext(context corev1.SecurityContext) Modification {
182182
return func(container *corev1.Container) {
183-
container.SecurityContext = context
183+
container.SecurityContext = &context
184184
}
185185
}
186+
187+
// DefaultSecurityContext returns the default container security context with:
188+
// - readOnlyRootFilesystem set to true
189+
func DefaultSecurityContext() corev1.SecurityContext {
190+
readOnlyRootFilesystem := true
191+
return corev1.SecurityContext{ReadOnlyRootFilesystem: &readOnlyRootFilesystem}
192+
}

pkg/kube/podtemplatespec/podspec_template.go

+15-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package podtemplatespec
22

33
import (
44
"github.com/mongodb/mongodb-kubernetes-operator/pkg/kube/container"
5+
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/envvar"
56
"github.com/mongodb/mongodb-kubernetes-operator/pkg/util/merge"
67
corev1 "k8s.io/api/core/v1"
78
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -10,7 +11,8 @@ import (
1011
type Modification func(*corev1.PodTemplateSpec)
1112

1213
const (
13-
notFound = -1
14+
notFound = -1
15+
ManagedSecurityContextEnv = "MANAGED_SECURITY_CONTEXT"
1416
)
1517

1618
func New(templateMods ...Modification) corev1.PodTemplateSpec {
@@ -266,3 +268,15 @@ func FindContainerByName(name string, podTemplateSpec *corev1.PodTemplateSpec) *
266268

267269
return nil
268270
}
271+
272+
func WithDefaultSecurityContextsModifications() (Modification, container.Modification) {
273+
managedSecurityContext := envvar.ReadBool(ManagedSecurityContextEnv)
274+
configureContainerSecurityContext := container.NOOP()
275+
configurePodSpecSecurityContext := NOOP()
276+
if !managedSecurityContext {
277+
configurePodSpecSecurityContext = WithSecurityContext(DefaultPodSecurityContext())
278+
configureContainerSecurityContext = container.WithSecurityContext(container.DefaultSecurityContext())
279+
}
280+
281+
return configurePodSpecSecurityContext, configureContainerSecurityContext
282+
}

pkg/kube/podtemplatespec/podspec_template_test.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,18 @@ func TestPodTemplateSpec(t *testing.T) {
4141
container.WithName("init-container-0"),
4242
container.WithImage("init-image"),
4343
container.WithVolumeMounts([]corev1.VolumeMount{volumeMount1}),
44+
container.WithSecurityContext(container.DefaultSecurityContext()),
4445
)),
4546
WithContainerByIndex(0, container.Apply(
4647
container.WithName("container-0"),
4748
container.WithImage("image"),
4849
container.WithVolumeMounts([]corev1.VolumeMount{volumeMount1}),
50+
container.WithSecurityContext(container.DefaultSecurityContext()),
4951
)),
5052
WithContainerByIndex(1, container.Apply(
5153
container.WithName("container-1"),
5254
container.WithImage("image"),
55+
container.WithSecurityContext(container.DefaultSecurityContext()),
5356
)),
5457
WithVolumeMounts("init-container-0", volumeMount2),
5558
WithVolumeMounts("container-0", volumeMount2),
@@ -74,16 +77,19 @@ func TestPodTemplateSpec(t *testing.T) {
7477
assert.Equal(t, "init-container-0", p.Spec.InitContainers[0].Name)
7578
assert.Equal(t, "init-image", p.Spec.InitContainers[0].Image)
7679
assert.Equal(t, []corev1.VolumeMount{volumeMount1, volumeMount2}, p.Spec.InitContainers[0].VolumeMounts)
80+
assert.Equal(t, container.DefaultSecurityContext(), *p.Spec.InitContainers[0].SecurityContext)
7781

7882
assert.Len(t, p.Spec.Containers, 2)
7983

8084
assert.Equal(t, "container-0", p.Spec.Containers[0].Name)
8185
assert.Equal(t, "image", p.Spec.Containers[0].Image)
8286
assert.Equal(t, []corev1.VolumeMount{volumeMount1, volumeMount2}, p.Spec.Containers[0].VolumeMounts)
87+
assert.Equal(t, container.DefaultSecurityContext(), *p.Spec.Containers[0].SecurityContext)
8388

8489
assert.Equal(t, "container-1", p.Spec.Containers[1].Name)
8590
assert.Equal(t, "image", p.Spec.Containers[1].Image)
86-
assert.Equal(t, []corev1.VolumeMount{volumeMount1, volumeMount2}, p.Spec.Containers[0].VolumeMounts)
91+
assert.Equal(t, []corev1.VolumeMount{volumeMount1, volumeMount2}, p.Spec.Containers[1].VolumeMounts)
92+
assert.Equal(t, container.DefaultSecurityContext(), *p.Spec.Containers[1].SecurityContext)
8793
}
8894

8995
func TestPodTemplateSpec_MultipleEditsToContainer(t *testing.T) {

0 commit comments

Comments
 (0)