From f422235b3ee0eda56774854a5797679791cce693 Mon Sep 17 00:00:00 2001 From: Mrunal Patel Date: Wed, 29 Mar 2017 11:16:53 -0700 Subject: [PATCH 1/3] Add function to safely open a file in container rootfs Signed-off-by: Mrunal Patel --- server/container_create.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/server/container_create.go b/server/container_create.go index dd39a4de..146229e3 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -4,12 +4,15 @@ import ( "encoding/json" "errors" "fmt" + "io" + "os" "path/filepath" "strings" "syscall" "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/stringid" + "github.com/docker/docker/pkg/symlink" "github.com/kubernetes-incubator/cri-o/oci" "github.com/kubernetes-incubator/cri-o/server/apparmor" "github.com/kubernetes-incubator/cri-o/server/seccomp" @@ -567,3 +570,12 @@ func (s *Server) getAppArmorProfileName(annotations map[string]string, ctrName s return strings.TrimPrefix(profile, apparmor.ProfileNamePrefix) } + +// openContainerFile opens a file inside a container rootfs safely +func openContainerFile(rootfs string, path string) (io.ReadCloser, error) { + fp, err := symlink.FollowSymlinkInScope(filepath.Join(rootfs, path), rootfs) + if err != nil { + return nil, err + } + return os.Open(fp) +} From 505bc2cbd522939c127a3f3690e68dbc500f47a6 Mon Sep 17 00:00:00 2001 From: Mrunal Patel Date: Wed, 29 Mar 2017 11:18:35 -0700 Subject: [PATCH 2/3] Add function to lookup user in container /etc/{passwd,group} Signed-off-by: Mrunal Patel --- server/container_create.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/server/container_create.go b/server/container_create.go index 146229e3..ed5ccb0e 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -17,6 +17,7 @@ import ( "github.com/kubernetes-incubator/cri-o/server/apparmor" "github.com/kubernetes-incubator/cri-o/server/seccomp" "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/opencontainers/runc/libcontainer/user" "github.com/opencontainers/runtime-tools/generate" "github.com/opencontainers/selinux/go-selinux/label" "golang.org/x/net/context" @@ -579,3 +580,32 @@ func openContainerFile(rootfs string, path string) (io.ReadCloser, error) { } return os.Open(fp) } + +// getUserInfo returns UID, GID and additional groups for specified user +// by looking them up in /etc/passwd and /etc/group +func getUserInfo(rootfs string, userName string) (uint32, uint32, []uint32, error) { + // We don't care if we can't open the file because + // not all images will have these files + passwdFile, err := openContainerFile(rootfs, "/etc/passwd") + if err == nil { + defer passwdFile.Close() + } + groupFile, err := openContainerFile(rootfs, "/etc/group") + if err == nil { + defer groupFile.Close() + } + + execUser, err := user.GetExecUser(userName, nil, passwdFile, groupFile) + if err != nil { + return 0, 0, nil, err + } + + uid := uint32(execUser.Uid) + gid := uint32(execUser.Gid) + var additionalGids []uint32 + for _, g := range execUser.Sgids { + additionalGids = append(additionalGids, uint32(g)) + } + + return uid, gid, additionalGids, nil +} From c6897b5f6297c87f97a002dfc57979f5643282d4 Mon Sep 17 00:00:00 2001 From: Mrunal Patel Date: Wed, 29 Mar 2017 11:23:33 -0700 Subject: [PATCH 3/3] Set the uid, gid and groups from container user Signed-off-by: Mrunal Patel --- server/container_create.go | 71 ++++++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/server/container_create.go b/server/container_create.go index ed5ccb0e..74df8727 100644 --- a/server/container_create.go +++ b/server/container_create.go @@ -7,6 +7,7 @@ import ( "io" "os" "path/filepath" + "strconv" "strings" "syscall" @@ -157,6 +158,51 @@ func buildOCIProcessArgs(containerKubeConfig *pb.ContainerConfig, imageOCIConfig return processArgs, nil } +// setupContainerUser sets the UID, GID and supplemental groups in OCI runtime config +func setupContainerUser(specgen *generate.Generator, rootfs string, sc *pb.LinuxContainerSecurityContext, imageConfig *v1.Image) error { + if sc != nil { + containerUser := "" + // Case 1: run as user is set by kubelet + if sc.RunAsUser != nil { + containerUser = strconv.FormatInt(sc.GetRunAsUser().Value, 10) + } else { + // Case 2: run as username is set by kubelet + userName := sc.RunAsUsername + if userName != "" { + containerUser = userName + } else { + // Case 3: get user from image config + imageUser := imageConfig.Config.User + if imageUser != "" { + containerUser = imageUser + } + } + } + + logrus.Debugf("CONTAINER USER: %+v", containerUser) + + // Add uid, gid and groups from user + uid, gid, addGroups, err1 := getUserInfo(rootfs, containerUser) + if err1 != nil { + return err1 + } + + logrus.Debugf("UID: %v, GID: %v, Groups: %+v", uid, gid, addGroups) + specgen.SetProcessUID(uid) + specgen.SetProcessGID(gid) + for _, group := range addGroups { + specgen.AddProcessAdditionalGid(group) + } + + // Add groups from CRI + groups := sc.SupplementalGroups + for _, group := range groups { + specgen.AddProcessAdditionalGid(uint32(group)) + } + } + return nil +} + // CreateContainer creates a new container in specified PodSandbox func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (res *pb.CreateContainerResponse, err error) { logrus.Debugf("CreateContainerRequest %+v", req) @@ -349,15 +395,6 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, specgen.SetProcessSelinuxLabel(sb.processLabel) specgen.SetLinuxMountLabel(sb.mountLabel) - if linux.GetSecurityContext() != nil { - user := linux.GetSecurityContext().GetRunAsUser() - specgen.SetProcessUID(uint32(user.Value)) - specgen.SetProcessGID(uint32(user.Value)) - groups := linux.GetSecurityContext().SupplementalGroups - for _, group := range groups { - specgen.AddProcessAdditionalGid(uint32(group)) - } - } } // Join the namespace paths for the pod sandbox container. podInfraState := s.runtime.ContainerStatus(sb.infraContainer) @@ -487,6 +524,13 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string, specgen.SetProcessCwd(cwd) } + // Setup user and groups + if linux != nil { + if err = setupContainerUser(&specgen, mountPoint, linux.GetSecurityContext(), containerInfo.Config); err != nil { + return nil, err + } + } + // by default, the root path is an empty string. set it now. specgen.SetRootPath(mountPoint) @@ -587,11 +631,16 @@ func getUserInfo(rootfs string, userName string) (uint32, uint32, []uint32, erro // We don't care if we can't open the file because // not all images will have these files passwdFile, err := openContainerFile(rootfs, "/etc/passwd") - if err == nil { + if err != nil { + logrus.Warnf("Failed to open /etc/passwd: %v", err) + } else { defer passwdFile.Close() } + groupFile, err := openContainerFile(rootfs, "/etc/group") - if err == nil { + if err != nil { + logrus.Warnf("Failed to open /etc/group: %v", err) + } else { defer groupFile.Close() }