commit
3f59e18a7c
1 changed files with 100 additions and 9 deletions
|
@ -4,16 +4,21 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/pkg/stringid"
|
"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/oci"
|
||||||
"github.com/kubernetes-incubator/cri-o/server/apparmor"
|
"github.com/kubernetes-incubator/cri-o/server/apparmor"
|
||||||
"github.com/kubernetes-incubator/cri-o/server/seccomp"
|
"github.com/kubernetes-incubator/cri-o/server/seccomp"
|
||||||
"github.com/opencontainers/image-spec/specs-go/v1"
|
"github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/user"
|
||||||
"github.com/opencontainers/runtime-tools/generate"
|
"github.com/opencontainers/runtime-tools/generate"
|
||||||
"github.com/opencontainers/selinux/go-selinux/label"
|
"github.com/opencontainers/selinux/go-selinux/label"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
@ -153,6 +158,51 @@ func buildOCIProcessArgs(containerKubeConfig *pb.ContainerConfig, imageOCIConfig
|
||||||
return processArgs, nil
|
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
|
// CreateContainer creates a new container in specified PodSandbox
|
||||||
func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (res *pb.CreateContainerResponse, err error) {
|
func (s *Server) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (res *pb.CreateContainerResponse, err error) {
|
||||||
logrus.Debugf("CreateContainerRequest %+v", req)
|
logrus.Debugf("CreateContainerRequest %+v", req)
|
||||||
|
@ -345,15 +395,6 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
|
||||||
specgen.SetProcessSelinuxLabel(sb.processLabel)
|
specgen.SetProcessSelinuxLabel(sb.processLabel)
|
||||||
specgen.SetLinuxMountLabel(sb.mountLabel)
|
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.
|
// Join the namespace paths for the pod sandbox container.
|
||||||
podInfraState := s.runtime.ContainerStatus(sb.infraContainer)
|
podInfraState := s.runtime.ContainerStatus(sb.infraContainer)
|
||||||
|
@ -483,6 +524,13 @@ func (s *Server) createSandboxContainer(ctx context.Context, containerID string,
|
||||||
specgen.SetProcessCwd(cwd)
|
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.
|
// by default, the root path is an empty string. set it now.
|
||||||
specgen.SetRootPath(mountPoint)
|
specgen.SetRootPath(mountPoint)
|
||||||
|
|
||||||
|
@ -567,3 +615,46 @@ func (s *Server) getAppArmorProfileName(annotations map[string]string, ctrName s
|
||||||
|
|
||||||
return strings.TrimPrefix(profile, apparmor.ProfileNamePrefix)
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
logrus.Warnf("Failed to open /etc/passwd: %v", err)
|
||||||
|
} else {
|
||||||
|
defer passwdFile.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
groupFile, err := openContainerFile(rootfs, "/etc/group")
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Failed to open /etc/group: %v", err)
|
||||||
|
} else {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue