Add support for RunAsUser and RunAsGroup

Currently podman generate kube does not generate the correct RunAsUser and RunAsGroup
options in the yaml file.  This patch fixes this.

This patch also make `podman play kube` use the RunAdUser and RunAsGroup options if
they are specified in the yaml file.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
Daniel J Walsh 2019-11-04 18:07:58 -05:00
parent 581a7ec298
commit a6108f1c19
No known key found for this signature in database
GPG key ID: A2DF901DABE2C028
4 changed files with 95 additions and 43 deletions

View file

@ -487,13 +487,16 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
if err := c.syncContainer(); err != nil {
return nil, errors.Wrapf(err, "unable to sync container during YAML generation")
}
logrus.Debugf("Looking in container for user: %s", c.User())
u, err := lookup.GetUser(c.state.Mountpoint, c.User())
execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, c.User(), nil)
if err != nil {
return nil, err
}
user := int64(u.Uid)
sc.RunAsUser = &user
uid := int64(execUser.Uid)
gid := int64(execUser.Gid)
sc.RunAsUser = &uid
sc.RunAsGroup = &gid
}
return &sc, nil
}

View file

@ -666,6 +666,58 @@ func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
return infraPorts
}
func setupSecurityContext(containerConfig *createconfig.CreateConfig, containerYAML v1.Container) {
if containerYAML.SecurityContext == nil {
return
}
if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
}
if containerYAML.SecurityContext.Privileged != nil {
containerConfig.Privileged = *containerYAML.SecurityContext.Privileged
}
if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
}
if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
if seopt.User != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
}
if seopt.Role != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
}
if seopt.Type != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
}
if seopt.Level != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
}
}
if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
for _, capability := range caps.Add {
containerConfig.CapAdd = append(containerConfig.CapAdd, string(capability))
}
for _, capability := range caps.Drop {
containerConfig.CapDrop = append(containerConfig.CapDrop, string(capability))
}
}
if containerYAML.SecurityContext.RunAsUser != nil {
containerConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
}
if containerYAML.SecurityContext.RunAsGroup != nil {
if containerConfig.User == "" {
containerConfig.User = "0"
}
containerConfig.User = fmt.Sprintf("%s:%d", containerConfig.User, *containerYAML.SecurityContext.RunAsGroup)
}
}
// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID string) (*createconfig.CreateConfig, error) {
var (
@ -690,47 +742,8 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container
containerConfig.User = imageData.Config.User
}
if containerYAML.SecurityContext != nil {
if containerConfig.SecurityOpts != nil {
if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
containerConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
}
if containerYAML.SecurityContext.Privileged != nil {
containerConfig.Privileged = *containerYAML.SecurityContext.Privileged
}
setupSecurityContext(&containerConfig, containerYAML)
if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
containerConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
}
}
if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
if seopt.User != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
}
if seopt.Role != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
}
if seopt.Type != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
}
if seopt.Level != "" {
containerConfig.SecurityOpts = append(containerConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
containerConfig.LabelOpts = append(containerConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
}
}
if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
for _, capability := range caps.Add {
containerConfig.CapAdd = append(containerConfig.CapAdd, string(capability))
}
for _, capability := range caps.Drop {
containerConfig.CapDrop = append(containerConfig.CapDrop, string(capability))
}
}
}
var err error
containerConfig.SeccompProfilePath, err = libpod.DefaultSeccompPath()
if err != nil {

View file

@ -208,6 +208,39 @@ var _ = Describe("Podman generate kube", func() {
Expect(psOut).To(ContainSubstring("test2"))
})
It("podman generate with user and reimport kube on pod", func() {
podName := "toppod"
_, rc, _ := podmanTest.CreatePod(podName)
Expect(rc).To(Equal(0))
session := podmanTest.Podman([]string{"create", "--pod", podName, "--name", "test1", "--user", "100:200", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.Config.User}}", "test1"})
inspect.WaitWithDefaultTimeout()
Expect(inspect.ExitCode()).To(Equal(0))
Expect(inspect.OutputToString()).To(ContainSubstring("100:200"))
outputFile := filepath.Join(podmanTest.RunRoot, "pod.yaml")
kube := podmanTest.Podman([]string{"generate", "kube", "-f", outputFile, podName})
kube.WaitWithDefaultTimeout()
Expect(kube.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"pod", "rm", "-af"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"play", "kube", outputFile})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
inspect1 := podmanTest.Podman([]string{"inspect", "--format", "{{.Config.User}}", "test1"})
inspect1.WaitWithDefaultTimeout()
Expect(inspect1.ExitCode()).To(Equal(0))
Expect(inspect1.OutputToString()).To(ContainSubstring(inspect.OutputToString()))
})
It("podman generate kube with volume", func() {
vol1 := filepath.Join(podmanTest.TempDir, "vol-test1")
err := os.MkdirAll(vol1, 0755)

View file

@ -24,6 +24,9 @@ spec:
name: test
resources: {}
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
allowPrivilegeEscalation: true
capabilities: {}
privileged: false