Skip to content

Commit 5994ce7

Browse files
committed
KEP-3619: Fine-grained SupplementalGroups control (SupplementalGroupsPolicy).
1 parent 6334081 commit 5994ce7

File tree

1 file changed

+134
-51
lines changed

1 file changed

+134
-51
lines changed

Diff for: pkg/validate/security_context_linux.go

+134-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,140 @@ var _ = framework.KubeDescribe("Security Context", func() {
633582
})
634583
})
635584

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

0 commit comments

Comments
 (0)