Commit 99ee3f4b authored by Random-Liu's avatar Random-Liu

Add non-numeric user name support.

parent d8fa6a99
......@@ -159,8 +159,9 @@ message LinuxSandboxSecurityContext {
optional NamespaceOption namespace_options = 1;
// Optional SELinux context to be applied.
optional SELinuxOption selinux_options = 2;
// The UID to run the entrypoint of the sandbox process.
optional int64 run_as_user = 3;
// The user to run the entrypoint of the sandbox process, it could be uid or
// user name.
optional string run_as_user = 3;
// If set, the root filesystem of the sandbox is read-only.
optional bool readonly_rootfs = 4;
// A list of groups applied to the first process run in the sandbox, in addition
......@@ -439,9 +440,10 @@ message LinuxContainerSecurityContext {
optional NamespaceOption namespace_options = 3;
// Optional SELinux context to be applied.
optional SELinuxOption selinux_options = 4;
// The UID to run the the container process as.
// The user to run the the container process as, it could be uid or user
// name.
// Defaults to user specified in image metadata if unspecified.
optional int64 run_as_user = 5;
optional string run_as_user = 5;
// If set, the root filesystem of the container is read-only.
optional bool readonly_rootfs = 6;
// A list of groups applied to the first process run in the container, in addition
......@@ -758,8 +760,8 @@ message Image {
repeated string repo_digests = 3;
// The size of the image in bytes.
optional uint64 size = 4;
// The uid that will run the command(s).
optional int64 uid = 5;
// The user that will run the command(s).
optional string user = 5;
}
message ListImagesResponse {
......
......@@ -18,7 +18,6 @@ package dockershim
import (
"fmt"
"strconv"
"strings"
"time"
......@@ -57,24 +56,14 @@ func imageInspectToRuntimeAPIImage(image *dockertypes.ImageInspect) (*runtimeApi
return nil, fmt.Errorf("unable to convert a nil pointer to a runtime API image")
}
var err error
var uid int64
size := uint64(image.VirtualSize)
imageUid := dockertools.GetUidFromUser(image.Config.User)
// Convert image UID to int64 format. Not that it assumes the process in
// the image is running as root if image.Config.User is not set.
if imageUid != "" {
uid, err = strconv.ParseInt(imageUid, 10, 64)
if err != nil {
return nil, fmt.Errorf("non-numeric user (%q)", imageUid)
}
}
user := dockertools.GetUserFromImageUser(image.Config.User)
return &runtimeApi.Image{
Id: &image.ID,
RepoTags: image.RepoTags,
RepoDigests: image.RepoDigests,
Size_: &size,
Uid: &uid,
User: &user,
}, nil
}
......
......@@ -61,9 +61,7 @@ func applyContainerSecurityContext(lc *runtimeapi.LinuxContainerConfig, sandboxI
// modifyContainerConfig applies container security context config to dockercontainer.Config.
func modifyContainerConfig(sc *runtimeapi.LinuxContainerSecurityContext, config *dockercontainer.Config) {
if sc != nil && sc.RunAsUser != nil {
config.User = strconv.FormatInt(sc.GetRunAsUser(), 10)
}
config.User = sc.GetRunAsUser()
}
// modifyHostConfig applies security context config to dockercontainer.HostConfig.
......
......@@ -18,7 +18,6 @@ package dockershim
import (
"fmt"
"strconv"
"testing"
dockercontainer "github.com/docker/engine-api/types/container"
......@@ -29,7 +28,7 @@ import (
)
func TestModifyContainerConfig(t *testing.T) {
var uid int64 = 123
var uid string = "123"
cases := []struct {
name string
......@@ -42,7 +41,7 @@ func TestModifyContainerConfig(t *testing.T) {
RunAsUser: &uid,
},
expected: &dockercontainer.Config{
User: strconv.FormatInt(uid, 10),
User: uid,
},
},
{
......
......@@ -2474,7 +2474,7 @@ func (dm *DockerManager) isImageRoot(image string) (bool, error) {
return false, fmt.Errorf("unable to inspect image %s, nil Config", image)
}
user := GetUidFromUser(img.Config.User)
user := GetUserFromImageUser(img.Config.User)
// if no user is defined container will run as root
if user == "" {
return true, nil
......@@ -2488,16 +2488,16 @@ func (dm *DockerManager) isImageRoot(image string) (bool, error) {
return uid == 0, nil
}
// GetUidFromUser splits the uid out of an uid:gid string.
func GetUidFromUser(id string) string {
// GetUserFromImageUser splits the user out of an user:group string.
func GetUserFromImageUser(id string) string {
if id == "" {
return id
}
// split instances where the id may contain uid:gid
// split instances where the id may contain user:group
if strings.Contains(id, ":") {
return strings.Split(id, ":")[0]
}
// no gid, just return the id
// no group, just return the id
return id
}
......
......@@ -1431,7 +1431,7 @@ func TestVerifyNonRoot(t *testing.T) {
}
}
func TestGetUidFromUser(t *testing.T) {
func TestGetUserFromImageUser(t *testing.T) {
tests := map[string]struct {
input string
expect string
......@@ -1452,9 +1452,17 @@ func TestGetUidFromUser(t *testing.T) {
input: "1:2:3",
expect: "1",
},
"root username": {
input: "root:root",
expect: "root",
},
"username": {
input: "test:test",
expect: "test",
},
}
for k, v := range tests {
actual := GetUidFromUser(v.input)
actual := GetUserFromImageUser(v.input)
if actual != v.expect {
t.Errorf("%s failed. Expected %s but got %s", k, v.expect, actual)
}
......
......@@ -60,6 +60,7 @@ go_library(
"//vendor:github.com/coreos/go-semver/semver",
"//vendor:github.com/docker/docker/pkg/jsonlog",
"//vendor:github.com/fsnotify/fsnotify",
"//vendor:github.com/gogo/protobuf/proto",
"//vendor:github.com/golang/glog",
"//vendor:github.com/google/cadvisor/info/v1",
],
......
......@@ -147,13 +147,18 @@ func getContainerSpec(pod *api.Pod, containerName string) *api.Container {
}
// getImageUID gets uid that will run the command(s) from image.
func (m *kubeGenericRuntimeManager) getImageUser(image string) (int64, error) {
func (m *kubeGenericRuntimeManager) getImageUser(image string) (string, error) {
imageStatus, err := m.imageService.ImageStatus(&runtimeApi.ImageSpec{Image: &image})
if err != nil {
return 0, err
return "", err
}
return imageStatus.GetUid(), nil
user := imageStatus.GetUser()
// kuberuntime treats empty user as root.
if user == "" {
return "0", nil
}
return user, nil
}
// isContainerFailed returns true if container has exited and exitcode is not zero.
......
......@@ -184,7 +184,7 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *api.Conta
}
// generateLinuxContainerConfig generates linux container config for kubelet runtime api.
func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *api.Container, pod *api.Pod, imageUser int64) *runtimeApi.LinuxContainerConfig {
func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *api.Container, pod *api.Pod, imageUser string) *runtimeApi.LinuxContainerConfig {
lc := &runtimeApi.LinuxContainerConfig{
Resources: &runtimeApi.LinuxContainerResources{},
SecurityContext: m.determineEffectiveSecurityContext(pod, container, imageUser),
......
......@@ -146,7 +146,7 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *api.Pod,
HostIpc: &sc.HostIPC,
HostPid: &sc.HostPID,
},
RunAsUser: sc.RunAsUser,
RunAsUser: convertToRuntimeRunAsUser(sc.RunAsUser),
}
if sc.FSGroup != nil {
......
......@@ -18,6 +18,10 @@ package kuberuntime
import (
"fmt"
"strconv"
"github.com/gogo/protobuf/proto"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
......@@ -25,7 +29,7 @@ import (
)
// determineEffectiveSecurityContext gets container's security context from api.Pod and api.Container.
func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *api.Pod, container *api.Container, imageUser int64) *runtimeapi.LinuxContainerSecurityContext {
func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *api.Pod, container *api.Container, imageUser string) *runtimeapi.LinuxContainerSecurityContext {
effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
synthesized := convertToRuntimeSecurityContext(effectiveSc)
if synthesized == nil {
......@@ -61,17 +65,29 @@ func (m *kubeGenericRuntimeManager) determineEffectiveSecurityContext(pod *api.P
}
// verifyRunAsNonRoot verifies RunAsNonRoot.
func verifyRunAsNonRoot(pod *api.Pod, container *api.Container, imageUser int64) error {
func verifyRunAsNonRoot(pod *api.Pod, container *api.Container, imageUser string) error {
effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
if effectiveSc == nil || effectiveSc.RunAsNonRoot == nil {
return nil
}
if effectiveSc.RunAsUser != nil && *effectiveSc.RunAsUser == 0 {
if effectiveSc.RunAsUser != nil {
if *effectiveSc.RunAsUser == 0 {
return fmt.Errorf("container's runAsUser breaks non-root policy")
}
return nil
}
// Non-root verification only supports numeric user now. For non-numeric user,
// just return nil to by-pass the verfication.
// TODO: Support non-numeric user.
uid, err := strconv.ParseInt(imageUser, 10, 64)
if err != nil {
glog.Warningf("Non-root verification doesn't support non-numeric user (%s)", imageUser)
return nil
}
if imageUser == 0 {
if uid == 0 {
return fmt.Errorf("container has runAsNonRoot and image will run as root")
}
......@@ -85,7 +101,7 @@ func convertToRuntimeSecurityContext(securityContext *api.SecurityContext) *runt
}
return &runtimeapi.LinuxContainerSecurityContext{
RunAsUser: securityContext.RunAsUser,
RunAsUser: convertToRuntimeRunAsUser(securityContext.RunAsUser),
Privileged: securityContext.Privileged,
ReadonlyRootfs: securityContext.ReadOnlyRootFilesystem,
Capabilities: convertToRuntimeCapabilities(securityContext.Capabilities),
......@@ -93,6 +109,14 @@ func convertToRuntimeSecurityContext(securityContext *api.SecurityContext) *runt
}
}
// convertToRuntimeRunAsUser converts RunAsUser from *int64 to *string.
func convertToRuntimeRunAsUser(runAsUser *int64) *string {
if runAsUser == nil {
return nil
}
return proto.String(strconv.FormatInt(*runAsUser, 10))
}
// convertToRuntimeSELinuxOption converts api.SELinuxOptions to runtimeapi.SELinuxOption.
func convertToRuntimeSELinuxOption(opts *api.SELinuxOptions) *runtimeapi.SELinuxOption {
if opts == nil {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment