Skip to content

Commit f55a3d5

Browse files
committed
KEP-3619: Fine-grained SupplementalGroups control (SupplementalGroupsPolicy).
1 parent e921c6b commit f55a3d5

File tree

1 file changed

+143
-51
lines changed

1 file changed

+143
-51
lines changed

Diff for: pkg/validate/security_context_linux.go

+143-51
Original file line numberDiff line numberDiff line change
@@ -300,57 +300,6 @@ var _ = framework.KubeDescribe("Security Context", func() {
300300
Expect(groups).To(ContainElement("5678"))
301301
})
302302

303-
It("if the container's primary UID belongs to some groups in the image, runtime should add SupplementalGroups to them", func() {
304-
By("create pod")
305-
podID, podConfig, podLogDir = createPodSandboxWithLogDirectory(rc)
306-
307-
By("create container for security context SupplementalGroups")
308-
supplementalGroup := int64(1234)
309-
containerName := "container-with-SupplementalGroups-and-predefined-group-image-test-" + framework.NewUUID()
310-
logPath := containerName + ".log"
311-
containerConfig := &runtimeapi.ContainerConfig{
312-
Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt),
313-
Image: &runtimeapi.ImageSpec{Image: testImagePreDefinedGroup},
314-
Command: []string{"sh", "-c", "id -G; while :; do sleep 1; done"},
315-
Linux: &runtimeapi.LinuxContainerConfig{
316-
SecurityContext: &runtimeapi.LinuxContainerSecurityContext{
317-
RunAsUser: &runtimeapi.Int64Value{Value: imagePredefinedGroupUID},
318-
SupplementalGroups: []int64{supplementalGroup},
319-
},
320-
},
321-
LogPath: logPath,
322-
}
323-
containerID := framework.CreateContainer(rc, ic, containerConfig, podID, podConfig)
324-
325-
By("start container")
326-
startContainer(rc, containerID)
327-
Eventually(func(g Gomega) {
328-
g.Expect(getContainerStatus(rc, containerID).State).To(Equal(runtimeapi.ContainerState_CONTAINER_RUNNING))
329-
g.Expect(parseLogLine(podConfig, logPath)).NotTo(BeEmpty())
330-
}, time.Minute, time.Second*4).Should(Succeed())
331-
332-
// In testImagePreDefinedGroup,
333-
// - its default user is default-user(uid=1000)
334-
// - default-user belongs to group-defined-in-image(gid=50000)
335-
//
336-
// thus, supplementary group of the container processes should be
337-
// - 1000: self
338-
// - 1234: SupplementalGroups
339-
// - 50000: groups define in the container image
340-
//
341-
// $ id -G
342-
// 1000 1234 5678 50000
343-
expectedOutput := fmt.Sprintf("%d %d %d\n", imagePredefinedGroupUID, supplementalGroup, imagePredefinedGroupGID)
344-
345-
By("verify groups for the first process of the container")
346-
verifyLogContents(podConfig, logPath, expectedOutput, stdoutType)
347-
348-
By("verify groups for 'exec'-ed process of container")
349-
command := []string{"id", "-G"}
350-
o := execSyncContainer(rc, containerID, command)
351-
Expect(o).To(BeEquivalentTo(expectedOutput))
352-
})
353-
354303
It("runtime should support RunAsUser", func() {
355304
By("create pod")
356305
podID, podConfig = framework.CreatePodSandboxForContainer(rc)
@@ -633,6 +582,149 @@ var _ = framework.KubeDescribe("Security Context", func() {
633582
})
634583
})
635584

585+
Context("SupplementalGroupsPolicy", func() {
586+
BeforeEach(func(ctx context.Context) {
587+
By("skip if the runtime does not support SupplementalGroupsPolicy")
588+
statusResponse, err := rc.Status(ctx, false)
589+
Expect(err).NotTo(HaveOccurred())
590+
if !(statusResponse.Features != nil && statusResponse.Features.SupplementalGroupsPolicy) {
591+
Skip("The runtime does not support SupplementalGroupsPolicy feature")
592+
}
593+
})
594+
595+
When("SupplementalGroupsPolicy=Merge (Default)", func() {
596+
It("if the container's primary UID belongs to some groups in the image, runtime should add SupplementalGroups to them", func() {
597+
By("create pod")
598+
podID, podConfig, podLogDir = createPodSandboxWithLogDirectory(rc)
599+
600+
By("create container for security context SupplementalGroups")
601+
supplementalGroup := int64(1234)
602+
containerName := "container-with-SupplementalGroupsPolicyMerge-" + framework.NewUUID()
603+
logPath := containerName + ".log"
604+
containerConfig := &runtimeapi.ContainerConfig{
605+
Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt),
606+
Image: &runtimeapi.ImageSpec{Image: testImagePreDefinedGroup},
607+
Command: []string{"sh", "-c", "id -G; while :; do sleep 1; done"},
608+
Linux: &runtimeapi.LinuxContainerConfig{
609+
SecurityContext: &runtimeapi.LinuxContainerSecurityContext{
610+
RunAsUser: &runtimeapi.Int64Value{Value: imagePredefinedGroupUID},
611+
SupplementalGroups: []int64{supplementalGroup},
612+
// SupplementalGroupsPolicy_Merge is default(0)
613+
// SupplementalGroupsPolicy: runtimeapi.SupplementalGroupsPolicy_Merge,
614+
},
615+
},
616+
LogPath: logPath,
617+
}
618+
containerID := framework.CreateContainer(rc, ic, containerConfig, podID, podConfig)
619+
620+
By("start container")
621+
startContainer(rc, containerID)
622+
623+
Eventually(func(g Gomega) {
624+
containerStatus := getContainerStatus(rc, containerID)
625+
g.Expect(containerStatus.State).To(Equal(runtimeapi.ContainerState_CONTAINER_RUNNING))
626+
// In testImagePreDefinedGroup,
627+
// - its default user is default-user(uid=1000)
628+
// - default-user belongs to group-defined-in-image(gid=50000) in /etc/group
629+
// And, SupplementalGroupsPolicy is Merge(default)
630+
//
631+
// Thus, firstly attached process identity of the first container processes should be
632+
// - uid: 1000 (RunAsUser)
633+
// - gid: 1000 (default group for uid=1000)
634+
// - supplementary groups
635+
// - 1000: self
636+
// - 1234: SupplementalGroups
637+
// - 50000: groups defined in the container image (/etc/group)
638+
g.Expect(containerStatus.User).To(BeEquivalentTo(&runtimeapi.ContainerUser{
639+
Linux: &runtimeapi.LinuxContainerUser{
640+
Uid: imagePredefinedGroupUID,
641+
Gid: imagePredefinedGroupUID,
642+
SupplementalGroups: []int64{imagePredefinedGroupUID, supplementalGroup, imagePredefinedGroupGID},
643+
},
644+
}))
645+
g.Expect(parseLogLine(podConfig, logPath)).NotTo(BeEmpty())
646+
}, time.Minute, time.Second*4).Should(Succeed())
647+
648+
// $ id -G
649+
// 1000 1234 50000
650+
expectedOutput := fmt.Sprintf("%d %d %d\n", imagePredefinedGroupUID, supplementalGroup, imagePredefinedGroupGID)
651+
652+
By("verify groups for the first process of the container")
653+
verifyLogContents(podConfig, logPath, expectedOutput, stdoutType)
654+
655+
By("verify groups for 'exec'-ed process of container")
656+
command := []string{"id", "-G"}
657+
o := execSyncContainer(rc, containerID, command)
658+
Expect(o).To(BeEquivalentTo(expectedOutput))
659+
})
660+
})
661+
When("SupplementalGroupsPolicy=Strict", func() {
662+
It("even if the container's primary UID belongs to some groups in the image, runtime should not add SupplementalGroups to them", func() {
663+
By("create pod")
664+
podID, podConfig, podLogDir = createPodSandboxWithLogDirectory(rc)
665+
666+
By("create container for security context SupplementalGroups")
667+
supplementalGroup := int64(1234)
668+
containerName := "container-with-SupplementalGroupsPolicyMerge-" + framework.NewUUID()
669+
logPath := containerName + ".log"
670+
containerConfig := &runtimeapi.ContainerConfig{
671+
Metadata: framework.BuildContainerMetadata(containerName, framework.DefaultAttempt),
672+
Image: &runtimeapi.ImageSpec{Image: testImagePreDefinedGroup},
673+
Command: []string{"sh", "-c", "id -G; while :; do sleep 1; done"},
674+
Linux: &runtimeapi.LinuxContainerConfig{
675+
SecurityContext: &runtimeapi.LinuxContainerSecurityContext{
676+
RunAsUser: &runtimeapi.Int64Value{Value: imagePredefinedGroupUID},
677+
SupplementalGroups: []int64{supplementalGroup},
678+
SupplementalGroupsPolicy: runtimeapi.SupplementalGroupsPolicy_Strict,
679+
},
680+
},
681+
LogPath: logPath,
682+
}
683+
containerID := framework.CreateContainer(rc, ic, containerConfig, podID, podConfig)
684+
685+
By("start container")
686+
startContainer(rc, containerID)
687+
688+
Eventually(func(g Gomega) {
689+
containerStatus := getContainerStatus(rc, containerID)
690+
g.Expect(containerStatus.State).To(Equal(runtimeapi.ContainerState_CONTAINER_RUNNING))
691+
// In testImagePreDefinedGroup,
692+
// - its default user is default-user(uid=1000)
693+
// - default-user belongs to group-defined-in-image(gid=50000) in /etc/group
694+
// And, SupplementalGroupsPolicy is Strict
695+
//
696+
// Thus, firstly attached process identity of the first container processes should be
697+
// (5000(defined in /etc/group) is not appended to supplementary groups)
698+
// - uid: 1000 (RunAsUser)
699+
// - gid: 1000 (default group for uid=1000)
700+
// - supplementary groups
701+
// - 1000: self
702+
// - 1234: SupplementalGroups
703+
g.Expect(containerStatus.User).To(BeEquivalentTo(&runtimeapi.ContainerUser{
704+
Linux: &runtimeapi.LinuxContainerUser{
705+
Uid: imagePredefinedGroupUID,
706+
Gid: imagePredefinedGroupUID,
707+
SupplementalGroups: []int64{imagePredefinedGroupUID, supplementalGroup},
708+
},
709+
}))
710+
g.Expect(parseLogLine(podConfig, logPath)).NotTo(BeEmpty())
711+
}, time.Minute, time.Second*4).Should(Succeed())
712+
713+
// $ id -G
714+
// 1000 1234
715+
expectedOutput := fmt.Sprintf("%d %d\n", imagePredefinedGroupUID, supplementalGroup)
716+
717+
By("verify groups for the first process of the container")
718+
verifyLogContents(podConfig, logPath, expectedOutput, stdoutType)
719+
720+
By("verify groups for 'exec'-ed process of container")
721+
command := []string{"id", "-G"}
722+
o := execSyncContainer(rc, containerID, command)
723+
Expect(o).To(BeEquivalentTo(expectedOutput))
724+
})
725+
})
726+
})
727+
636728
// TODO(random-liu): We should set apparmor to unconfined in seccomp test to prevent
637729
// them from interfering with each other.
638730
Context("SeccompProfilePath", func() {

0 commit comments

Comments
 (0)