diff options
-rw-r--r-- | pkg/domain/infra/abi/play.go | 64 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 54 | ||||
-rw-r--r-- | test/e2e/play_kube_test.go | 100 |
3 files changed, 160 insertions, 58 deletions
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index b3ded7db6..f44b46a6d 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -412,22 +412,23 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } specgenOpts := kube.CtrSpecGenOptions{ - Annotations: annotations, - Container: initCtr, - Image: pulledImage, - Volumes: volumes, - PodID: pod.ID(), - PodName: podName, - PodInfraID: podInfraID, - ConfigMaps: configMaps, - SeccompPaths: seccompPaths, - RestartPolicy: ctrRestartPolicy, - NetNSIsHost: p.NetNS.IsHost(), - SecretsManager: secretsManager, - LogDriver: options.LogDriver, - LogOptions: options.LogOptions, - Labels: labels, - InitContainerType: define.AlwaysInitContainer, + Annotations: annotations, + ConfigMaps: configMaps, + Container: initCtr, + Image: pulledImage, + InitContainerType: define.AlwaysInitContainer, + Labels: labels, + LogDriver: options.LogDriver, + LogOptions: options.LogOptions, + NetNSIsHost: p.NetNS.IsHost(), + PodID: pod.ID(), + PodInfraID: podInfraID, + PodName: podName, + PodSecurityContext: podYAML.Spec.SecurityContext, + RestartPolicy: ctrRestartPolicy, + SeccompPaths: seccompPaths, + SecretsManager: secretsManager, + Volumes: volumes, } specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { @@ -460,21 +461,22 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } specgenOpts := kube.CtrSpecGenOptions{ - Annotations: annotations, - Container: container, - Image: pulledImage, - Volumes: volumes, - PodID: pod.ID(), - PodName: podName, - PodInfraID: podInfraID, - ConfigMaps: configMaps, - SeccompPaths: seccompPaths, - RestartPolicy: ctrRestartPolicy, - NetNSIsHost: p.NetNS.IsHost(), - SecretsManager: secretsManager, - LogDriver: options.LogDriver, - LogOptions: options.LogOptions, - Labels: labels, + Annotations: annotations, + ConfigMaps: configMaps, + Container: container, + Image: pulledImage, + Labels: labels, + LogDriver: options.LogDriver, + LogOptions: options.LogOptions, + NetNSIsHost: p.NetNS.IsHost(), + PodID: pod.ID(), + PodInfraID: podInfraID, + PodName: podName, + PodSecurityContext: podYAML.Spec.SecurityContext, + RestartPolicy: ctrRestartPolicy, + SeccompPaths: seccompPaths, + SecretsManager: secretsManager, + Volumes: volumes, } specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index d56b50fd5..04195d15a 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -133,6 +133,8 @@ type CtrSpecGenOptions struct { // InitContainerType sets what type the init container is // Note: When playing a kube yaml, the inti container type will be set to "always" only InitContainerType string + // PodSecurityContext is the security context specified for the pod + PodSecurityContext *v1.PodSecurityContext } func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) { @@ -188,7 +190,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener s.InitContainerType = opts.InitContainerType - setupSecurityContext(s, opts.Container) + setupSecurityContext(s, opts.Container.SecurityContext, opts.PodSecurityContext) err := setupLivenessProbe(s, opts.Container, opts.RestartPolicy) if err != nil { return nil, errors.Wrap(err, "Failed to configure livenessProbe") @@ -531,22 +533,30 @@ func makeHealthCheck(inCmd string, interval int32, retries int32, timeout int32, return &hc, nil } -func setupSecurityContext(s *specgen.SpecGenerator, containerYAML v1.Container) { - if containerYAML.SecurityContext == nil { - return +func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.SecurityContext, podSecurityContext *v1.PodSecurityContext) { + if securityContext == nil { + securityContext = &v1.SecurityContext{} } - if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil { - s.ReadOnlyFilesystem = *containerYAML.SecurityContext.ReadOnlyRootFilesystem + if podSecurityContext == nil { + podSecurityContext = &v1.PodSecurityContext{} } - if containerYAML.SecurityContext.Privileged != nil { - s.Privileged = *containerYAML.SecurityContext.Privileged + + if securityContext.ReadOnlyRootFilesystem != nil { + s.ReadOnlyFilesystem = *securityContext.ReadOnlyRootFilesystem + } + if securityContext.Privileged != nil { + s.Privileged = *securityContext.Privileged } - if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil { - s.NoNewPrivileges = !*containerYAML.SecurityContext.AllowPrivilegeEscalation + if securityContext.AllowPrivilegeEscalation != nil { + s.NoNewPrivileges = !*securityContext.AllowPrivilegeEscalation } - if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil { + seopt := securityContext.SELinuxOptions + if seopt == nil { + seopt = podSecurityContext.SELinuxOptions + } + if seopt != nil { if seopt.User != "" { s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("user:%s", seopt.User)) } @@ -560,7 +570,7 @@ func setupSecurityContext(s *specgen.SpecGenerator, containerYAML v1.Container) s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("level:%s", seopt.Level)) } } - if caps := containerYAML.SecurityContext.Capabilities; caps != nil { + if caps := securityContext.Capabilities; caps != nil { for _, capability := range caps.Add { s.CapAdd = append(s.CapAdd, string(capability)) } @@ -568,14 +578,26 @@ func setupSecurityContext(s *specgen.SpecGenerator, containerYAML v1.Container) s.CapDrop = append(s.CapDrop, string(capability)) } } - if containerYAML.SecurityContext.RunAsUser != nil { - s.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser) + runAsUser := securityContext.RunAsUser + if runAsUser == nil { + runAsUser = podSecurityContext.RunAsUser + } + if runAsUser != nil { + s.User = fmt.Sprintf("%d", *runAsUser) } - if containerYAML.SecurityContext.RunAsGroup != nil { + + runAsGroup := securityContext.RunAsGroup + if runAsGroup == nil { + runAsGroup = podSecurityContext.RunAsGroup + } + if runAsGroup != nil { if s.User == "" { s.User = "0" } - s.User = fmt.Sprintf("%s:%d", s.User, *containerYAML.SecurityContext.RunAsGroup) + s.User = fmt.Sprintf("%s:%d", s.User, *runAsGroup) + } + for _, group := range podSecurityContext.SupplementalGroups { + s.Groups = append(s.Groups, fmt.Sprintf("%d", group)) } } diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go index fb01dc1e9..c627ada53 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -327,6 +327,11 @@ spec: name: {{ .Name }} {{ end }} {{ end }} +{{ if .SecurityContext }} + securityContext: + {{ if .RunAsUser }}runAsUser: {{ .RunAsUser }}{{- end }} + {{ if .RunAsGroup }}runAsGroup: {{ .RunAsGroup }}{{- end }} +{{ end }} containers: {{ with .Ctrs }} {{ range . }} @@ -393,6 +398,8 @@ spec: {{- end }} {{ if .SecurityContext }} securityContext: + {{ if .RunAsUser }}runAsUser: {{ .RunAsUser }}{{- end }} + {{ if .RunAsGroup }}runAsGroup: {{ .RunAsGroup }}{{- end }} allowPrivilegeEscalation: true {{ if .Caps }} capabilities: @@ -758,16 +765,19 @@ func withPVCAnnotations(k, v string) pvcOption { // Pod describes the options a kube yaml can be configured at pod level type Pod struct { - Name string - RestartPolicy string - Hostname string - HostNetwork bool - HostAliases []HostAlias - Ctrs []*Ctr - InitCtrs []*Ctr - Volumes []*Volume - Labels map[string]string - Annotations map[string]string + Name string + RestartPolicy string + Hostname string + HostNetwork bool + HostAliases []HostAlias + Ctrs []*Ctr + InitCtrs []*Ctr + Volumes []*Volume + Labels map[string]string + Annotations map[string]string + SecurityContext bool + RunAsUser string + RunAsGroup string } type HostAlias struct { @@ -802,6 +812,24 @@ func getPod(options ...podOption) *Pod { type podOption func(*Pod) +func withPodSecurityContext(sc bool) podOption { + return func(p *Pod) { + p.SecurityContext = sc + } +} + +func withPodRunAsUser(runAsUser string) podOption { + return func(p *Pod) { + p.RunAsUser = runAsUser + } +} + +func withPodRunAsGroup(runAsGroup string) podOption { + return func(p *Pod) { + p.RunAsGroup = runAsGroup + } +} + func withPodName(name string) podOption { return func(pod *Pod) { pod.Name = name @@ -949,6 +977,8 @@ type Ctr struct { Env []Env EnvFrom []EnvFrom InitCtrType string + RunAsUser string + RunAsGroup string } // getCtr takes a list of ctrOptions and returns a Ctr with sane defaults @@ -1042,6 +1072,18 @@ func withSecurityContext(sc bool) ctrOption { } } +func withRunAsUser(runAsUser string) ctrOption { + return func(c *Ctr) { + c.RunAsUser = runAsUser + } +} + +func withRunAsGroup(runAsGroup string) ctrOption { + return func(c *Ctr) { + c.RunAsGroup = runAsGroup + } +} + func withCapAdd(caps []string) ctrOption { return func(c *Ctr) { c.CapAdd = caps @@ -1105,8 +1147,12 @@ func withEnvFrom(name, from string, optional bool) ctrOption { } } +func makeCtrNameInPod(pod *Pod, containerName string) string { + return fmt.Sprintf("%s-%s", pod.Name, containerName) +} + func getCtrNameInPod(pod *Pod) string { - return fmt.Sprintf("%s-%s", pod.Name, defaultCtrName) + return makeCtrNameInPod(pod, defaultCtrName) } type HostPath struct { @@ -3222,6 +3268,38 @@ invalid kube kind Expect(ls.OutputToStringArray()).To(HaveLen(1)) }) + It("podman play kube RunAsUser", func() { + ctr1Name := "ctr1" + ctr2Name := "ctr2" + ctr1 := getCtr(withName(ctr1Name), withSecurityContext(true), withRunAsUser("101"), withRunAsGroup("102")) + ctr2 := getCtr(withName(ctr2Name), withSecurityContext(true)) + + pod := getPod( + withCtr(ctr1), + withCtr(ctr2), + withPodSecurityContext(true), + withPodRunAsUser("103"), + withPodRunAsGroup("104"), + ) + + err := generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + cmd := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + cmd.WaitWithDefaultTimeout() + Expect(cmd).Should(Exit(0)) + + // we expect the user:group as configured for the container + inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "'{{.Config.User}}'", makeCtrNameInPod(pod, ctr1Name)}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.OutputToString()).To(Equal("'101:102'")) + + // we expect the user:group as configured for the pod + inspect = podmanTest.Podman([]string{"container", "inspect", "--format", "'{{.Config.User}}'", makeCtrNameInPod(pod, ctr2Name)}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.OutputToString()).To(Equal("'103:104'")) + }) + Describe("verify environment variables", func() { var maxLength int BeforeEach(func() { |