Skip to content

Commit 618aac7

Browse files
authored
fix: set securityContext values for extractContent containers (#3270)
Signed-off-by: Joe Lanford <joe.lanford@gmail.com>
1 parent 91aaffe commit 618aac7

File tree

2 files changed

+256
-30
lines changed

2 files changed

+256
-30
lines changed

pkg/controller/registry/reconciler/reconciler.go

+35-20
Original file line numberDiff line numberDiff line change
@@ -207,23 +207,6 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img s
207207
},
208208
}
209209

210-
// Determine the security context configuration
211-
var securityContextConfig operatorsv1alpha1.SecurityConfig
212-
213-
// Use the user-provided security context config if it is defined
214-
if source.Spec.GrpcPodConfig != nil && source.Spec.GrpcPodConfig.SecurityContextConfig != "" {
215-
securityContextConfig = source.Spec.GrpcPodConfig.SecurityContextConfig
216-
} else {
217-
// Default to the defaultNamespace based and provided security context config
218-
securityContextConfig = defaultSecurityConfig
219-
}
220-
221-
// Apply the appropriate security context configuration
222-
if securityContextConfig == operatorsv1alpha1.Restricted {
223-
// Apply 'restricted' security settings
224-
addSecurityContext(pod, runAsUser)
225-
}
226-
227210
// Override scheduling options if specified
228211
if source.Spec.GrpcPodConfig != nil {
229212
grpcPodConfig := source.Spec.GrpcPodConfig
@@ -325,6 +308,23 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img s
325308
}
326309
}
327310

311+
// Determine the security context configuration
312+
var securityContextConfig operatorsv1alpha1.SecurityConfig
313+
314+
// Use the user-provided security context config if it is defined
315+
if source.Spec.GrpcPodConfig != nil && source.Spec.GrpcPodConfig.SecurityContextConfig != "" {
316+
securityContextConfig = source.Spec.GrpcPodConfig.SecurityContextConfig
317+
} else {
318+
// Default to the defaultNamespace based and provided security context config
319+
securityContextConfig = defaultSecurityConfig
320+
}
321+
322+
// Apply the appropriate security context configuration
323+
if securityContextConfig == operatorsv1alpha1.Restricted {
324+
// Apply 'restricted' security settings
325+
addSecurityContext(pod, runAsUser)
326+
}
327+
328328
// Set priorityclass if its annotation exists
329329
if prio, ok := podAnnotations[CatalogPriorityClassKey]; ok && prio != "" {
330330
pod.Spec.PriorityClassName = prio
@@ -346,10 +346,25 @@ func Pod(source *operatorsv1alpha1.CatalogSource, name, opmImg, utilImage, img s
346346
}
347347

348348
func addSecurityContext(pod *corev1.Pod, runAsUser int64) {
349-
pod.Spec.Containers[0].SecurityContext.AllowPrivilegeEscalation = ptr.To(false)
350-
pod.Spec.Containers[0].SecurityContext.Capabilities = &corev1.Capabilities{
351-
Drop: []corev1.Capability{"ALL"},
349+
for i := range pod.Spec.InitContainers {
350+
if pod.Spec.InitContainers[i].SecurityContext == nil {
351+
pod.Spec.InitContainers[i].SecurityContext = &corev1.SecurityContext{}
352+
}
353+
pod.Spec.InitContainers[i].SecurityContext.AllowPrivilegeEscalation = ptr.To(false)
354+
pod.Spec.InitContainers[i].SecurityContext.Capabilities = &corev1.Capabilities{
355+
Drop: []corev1.Capability{"ALL"},
356+
}
352357
}
358+
for i := range pod.Spec.Containers {
359+
if pod.Spec.Containers[i].SecurityContext == nil {
360+
pod.Spec.Containers[i].SecurityContext = &corev1.SecurityContext{}
361+
}
362+
pod.Spec.Containers[i].SecurityContext.AllowPrivilegeEscalation = ptr.To(false)
363+
pod.Spec.Containers[i].SecurityContext.Capabilities = &corev1.Capabilities{
364+
Drop: []corev1.Capability{"ALL"},
365+
}
366+
}
367+
353368
pod.Spec.SecurityContext = &corev1.PodSecurityContext{
354369
SeccompProfile: &corev1.SeccompProfile{
355370
Type: corev1.SeccompProfileTypeRuntimeDefault,

pkg/controller/registry/reconciler/reconciler_test.go

+221-10
Original file line numberDiff line numberDiff line change
@@ -191,18 +191,20 @@ func serviceAccount(namespace, name string) *corev1.ServiceAccount {
191191

192192
func TestPodExtractContent(t *testing.T) {
193193
var testCases = []struct {
194-
name string
195-
input *v1alpha1.CatalogSource
196-
expected *corev1.Pod
194+
name string
195+
input *v1alpha1.CatalogSource
196+
securityContextConfig v1alpha1.SecurityConfig
197+
expected *corev1.Pod
197198
}{
198199
{
199-
name: "content extraction not requested",
200+
name: "content extraction not requested - legacy security context config",
200201
input: &v1alpha1.CatalogSource{
201202
ObjectMeta: metav1.ObjectMeta{
202203
Name: "test",
203204
Namespace: "testns",
204205
},
205206
},
207+
securityContextConfig: v1alpha1.Legacy,
206208
expected: &corev1.Pod{
207209
ObjectMeta: metav1.ObjectMeta{
208210
GenerateName: "test-",
@@ -263,7 +265,7 @@ func TestPodExtractContent(t *testing.T) {
263265
},
264266
},
265267
{
266-
name: "content extraction expected",
268+
name: "content extraction expected - legacy security context config",
267269
input: &v1alpha1.CatalogSource{
268270
ObjectMeta: metav1.ObjectMeta{
269271
Name: "test",
@@ -278,6 +280,7 @@ func TestPodExtractContent(t *testing.T) {
278280
},
279281
},
280282
},
283+
securityContextConfig: v1alpha1.Legacy,
281284
expected: &corev1.Pod{
282285
ObjectMeta: metav1.ObjectMeta{
283286
GenerateName: "test-",
@@ -377,14 +380,222 @@ func TestPodExtractContent(t *testing.T) {
377380
},
378381
},
379382
},
383+
{
384+
name: "content extraction not requested - restricted security context config",
385+
input: &v1alpha1.CatalogSource{
386+
ObjectMeta: metav1.ObjectMeta{
387+
Name: "test",
388+
Namespace: "testns",
389+
},
390+
},
391+
securityContextConfig: v1alpha1.Restricted,
392+
expected: &corev1.Pod{
393+
ObjectMeta: metav1.ObjectMeta{
394+
GenerateName: "test-",
395+
Namespace: "testns",
396+
Labels: map[string]string{"olm.pod-spec-hash": "3sDLk8MMNptrqUfdnruY2gUi1g8O4wpMWC6Q52", "olm.managed": "true"},
397+
Annotations: map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
398+
},
399+
Spec: corev1.PodSpec{
400+
Containers: []corev1.Container{
401+
{
402+
Name: "name",
403+
Image: "image",
404+
Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
405+
ReadinessProbe: &corev1.Probe{
406+
ProbeHandler: corev1.ProbeHandler{
407+
Exec: &corev1.ExecAction{
408+
Command: []string{"grpc_health_probe", "-addr=:50051"},
409+
},
410+
},
411+
InitialDelaySeconds: 0,
412+
TimeoutSeconds: 5,
413+
},
414+
LivenessProbe: &corev1.Probe{
415+
ProbeHandler: corev1.ProbeHandler{
416+
Exec: &corev1.ExecAction{
417+
Command: []string{"grpc_health_probe", "-addr=:50051"},
418+
},
419+
},
420+
InitialDelaySeconds: 0,
421+
TimeoutSeconds: 5,
422+
},
423+
StartupProbe: &corev1.Probe{
424+
ProbeHandler: corev1.ProbeHandler{
425+
Exec: &corev1.ExecAction{
426+
Command: []string{"grpc_health_probe", "-addr=:50051"},
427+
},
428+
},
429+
FailureThreshold: 10,
430+
PeriodSeconds: 10,
431+
TimeoutSeconds: 5,
432+
},
433+
Resources: corev1.ResourceRequirements{
434+
Requests: corev1.ResourceList{
435+
corev1.ResourceCPU: resource.MustParse("10m"),
436+
corev1.ResourceMemory: resource.MustParse("50Mi"),
437+
},
438+
},
439+
ImagePullPolicy: image.InferImagePullPolicy("image"),
440+
SecurityContext: &corev1.SecurityContext{
441+
Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
442+
AllowPrivilegeEscalation: ptr.To(false),
443+
ReadOnlyRootFilesystem: ptr.To(false),
444+
},
445+
TerminationMessagePolicy: "FallbackToLogsOnError",
446+
},
447+
},
448+
NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
449+
SecurityContext: &corev1.PodSecurityContext{
450+
RunAsUser: ptr.To(int64(workloadUserID)),
451+
RunAsNonRoot: ptr.To(true),
452+
SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
453+
},
454+
ServiceAccountName: "service-account",
455+
},
456+
},
457+
},
458+
{
459+
name: "content extraction expected - restricted security context config",
460+
input: &v1alpha1.CatalogSource{
461+
ObjectMeta: metav1.ObjectMeta{
462+
Name: "test",
463+
Namespace: "testns",
464+
},
465+
Spec: v1alpha1.CatalogSourceSpec{
466+
GrpcPodConfig: &v1alpha1.GrpcPodConfig{
467+
ExtractContent: &v1alpha1.ExtractContentConfig{
468+
CacheDir: "/tmp/cache",
469+
CatalogDir: "/catalog",
470+
},
471+
},
472+
},
473+
},
474+
securityContextConfig: v1alpha1.Restricted,
475+
expected: &corev1.Pod{
476+
ObjectMeta: metav1.ObjectMeta{
477+
GenerateName: "test-",
478+
Namespace: "testns",
479+
Labels: map[string]string{"olm.pod-spec-hash": "1X4YqbfXuc9SB9ztW03WNOyanr9aIhKfijeBHH", "olm.managed": "true"},
480+
Annotations: map[string]string{"cluster-autoscaler.kubernetes.io/safe-to-evict": "true"},
481+
},
482+
Spec: corev1.PodSpec{
483+
Volumes: []corev1.Volume{
484+
{
485+
Name: "utilities",
486+
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
487+
},
488+
{
489+
Name: "catalog-content",
490+
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
491+
},
492+
},
493+
InitContainers: []corev1.Container{
494+
{
495+
Name: "extract-utilities",
496+
Image: "utilImage",
497+
Command: []string{"cp"},
498+
Args: []string{"/bin/copy-content", "/utilities/copy-content"},
499+
SecurityContext: &corev1.SecurityContext{
500+
Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
501+
AllowPrivilegeEscalation: ptr.To(false),
502+
},
503+
VolumeMounts: []corev1.VolumeMount{{Name: "utilities", MountPath: "/utilities"}},
504+
TerminationMessagePolicy: "FallbackToLogsOnError",
505+
},
506+
{
507+
Name: "extract-content",
508+
Image: "image",
509+
ImagePullPolicy: image.InferImagePullPolicy("image"),
510+
Command: []string{"/utilities/copy-content"},
511+
Args: []string{
512+
"--catalog.from=/catalog",
513+
"--catalog.to=/extracted-catalog/catalog",
514+
"--cache.from=/tmp/cache",
515+
"--cache.to=/extracted-catalog/cache",
516+
},
517+
SecurityContext: &corev1.SecurityContext{
518+
Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
519+
AllowPrivilegeEscalation: ptr.To(false),
520+
},
521+
VolumeMounts: []corev1.VolumeMount{
522+
{Name: "utilities", MountPath: "/utilities"},
523+
{Name: "catalog-content", MountPath: "/extracted-catalog"},
524+
},
525+
TerminationMessagePolicy: "FallbackToLogsOnError",
526+
},
527+
},
528+
Containers: []corev1.Container{
529+
{
530+
Name: "name",
531+
Image: "opmImage",
532+
Command: []string{"/bin/opm"},
533+
Args: []string{"serve", "/extracted-catalog/catalog", "--cache-dir=/extracted-catalog/cache"},
534+
Ports: []corev1.ContainerPort{{Name: "grpc", ContainerPort: 50051}},
535+
ReadinessProbe: &corev1.Probe{
536+
ProbeHandler: corev1.ProbeHandler{
537+
Exec: &corev1.ExecAction{
538+
Command: []string{"grpc_health_probe", "-addr=:50051"},
539+
},
540+
},
541+
InitialDelaySeconds: 0,
542+
TimeoutSeconds: 5,
543+
},
544+
LivenessProbe: &corev1.Probe{
545+
ProbeHandler: corev1.ProbeHandler{
546+
Exec: &corev1.ExecAction{
547+
Command: []string{"grpc_health_probe", "-addr=:50051"},
548+
},
549+
},
550+
InitialDelaySeconds: 0,
551+
TimeoutSeconds: 5,
552+
},
553+
StartupProbe: &corev1.Probe{
554+
ProbeHandler: corev1.ProbeHandler{
555+
Exec: &corev1.ExecAction{
556+
Command: []string{"grpc_health_probe", "-addr=:50051"},
557+
},
558+
},
559+
FailureThreshold: 10,
560+
PeriodSeconds: 10,
561+
TimeoutSeconds: 5,
562+
},
563+
Resources: corev1.ResourceRequirements{
564+
Requests: corev1.ResourceList{
565+
corev1.ResourceCPU: resource.MustParse("10m"),
566+
corev1.ResourceMemory: resource.MustParse("50Mi"),
567+
},
568+
},
569+
ImagePullPolicy: image.InferImagePullPolicy("image"),
570+
SecurityContext: &corev1.SecurityContext{
571+
Capabilities: &corev1.Capabilities{Drop: []corev1.Capability{"ALL"}},
572+
AllowPrivilegeEscalation: ptr.To(false),
573+
ReadOnlyRootFilesystem: ptr.To(false),
574+
},
575+
TerminationMessagePolicy: "FallbackToLogsOnError",
576+
VolumeMounts: []corev1.VolumeMount{{Name: "catalog-content", MountPath: "/extracted-catalog"}},
577+
},
578+
},
579+
NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
580+
SecurityContext: &corev1.PodSecurityContext{
581+
RunAsUser: ptr.To(int64(workloadUserID)),
582+
RunAsNonRoot: ptr.To(true),
583+
SeccompProfile: &corev1.SeccompProfile{Type: corev1.SeccompProfileTypeRuntimeDefault},
584+
},
585+
ServiceAccountName: "service-account",
586+
},
587+
},
588+
},
380589
}
381590

382591
for _, testCase := range testCases {
383-
pod, err := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID), v1alpha1.Legacy)
384-
require.NoError(t, err)
385-
if diff := cmp.Diff(pod, testCase.expected); diff != "" {
386-
t.Errorf("got incorrect pod: %v", diff)
387-
}
592+
t.Run(testCase.name, func(t *testing.T) {
593+
pod, err := Pod(testCase.input, "name", "opmImage", "utilImage", "image", serviceAccount("", "service-account"), map[string]string{}, map[string]string{}, int32(0), int32(0), int64(workloadUserID), testCase.securityContextConfig)
594+
require.NoError(t, err)
595+
if diff := cmp.Diff(testCase.expected, pod); diff != "" {
596+
t.Errorf("got incorrect pod: %v", diff)
597+
}
598+
})
388599
}
389600
}
390601

0 commit comments

Comments
 (0)