Merge pull request #34811 from feiskyer/security-contex

Automatic merge from submit-queue

CRI: Add security context for sandbox/container

Part of #29478. This PR 
- adds security context for sandbox and fixes #33139
- encaps container security context to `SecurityContext` and adds missing features
- Note that capability is not fully accomplished in this PR because it is under discussion at  #33614.

cc/ @yujuhong @yifan-gu @Random-Liu @kubernetes/sig-node
This commit is contained in:
Kubernetes Submit Queue 2016-11-07 18:55:32 -08:00 committed by GitHub
commit a132e5c580
20 changed files with 1211 additions and 541 deletions

File diff suppressed because it is too large Load Diff

View File

@ -148,6 +148,26 @@ message NamespaceOption {
optional bool host_ipc = 3;
}
// LinuxSandboxSecurityContext holds linux security configuration that will be
// applied to a sandbox. Note that:
// 1) It does not apply to containers in the pods.
// 2) It may not be applicable to a PodSandbox which does not contain any running
// process.
message LinuxSandboxSecurityContext {
// The configurations for the sandbox's namespaces.
// This will be used only if the PodSandbox uses namespace for isolation.
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;
// 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
// to the sandbox's primary GID.
repeated int64 supplemental_groups = 5;
}
// LinuxPodSandboxConfig holds platform-specific configurations for Linux
// host platforms and Linux-based containers.
message LinuxPodSandboxConfig {
@ -155,9 +175,8 @@ message LinuxPodSandboxConfig {
// The cgroupfs style syntax will be used, but the container runtime can
// convert it to systemd semantics if needed.
optional string cgroup_parent = 1;
// The configurations for the sandbox's namespaces.
// This will be used only if the PodSandbox uses namespace for isolation.
optional NamespaceOption namespace_options = 2;
// LinuxSandboxSecurityContext holds sandbox security attributes.
optional LinuxSandboxSecurityContext security_context = 2;
}
// PodSandboxMetadata holds all necessary information for building the sandbox name.
@ -409,26 +428,34 @@ message Capability {
repeated string drop_capabilities = 2;
}
// LinuxContainerSecurityContext holds linux security configuration that will be applied to a container.
message LinuxContainerSecurityContext {
// Capabilities to add or drop.
optional Capability capabilities = 1;
// If set, run container in privileged mode.
optional bool privileged = 2;
// The configurations for the container's namespaces.
// This will be used only if the container uses namespace for isolation.
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.
// Defaults to user specified in image metadata if unspecified.
optional int64 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
// to the container's primary GID.
repeated int64 supplemental_groups = 7;
}
// LinuxContainerConfig contains platform-specific configuration for
// Linux-based containers.
message LinuxContainerConfig {
// Resources specification for the container.
optional LinuxContainerResources resources = 1;
// Capabilities to add or drop.
optional Capability capabilities = 2;
// Optional SELinux context to be applied.
optional SELinuxOption selinux_options = 3;
// User contains the user for the container process.
optional LinuxUser user = 4;
}
message LinuxUser {
// uid specifies the user ID the container process has.
optional int64 uid = 1;
// gid specifies the group ID the container process has.
optional int64 gid = 2;
// additional_gids specifies additional GIDs the container process has.
repeated int64 additional_gids = 3;
// LinuxContainerSecurityContext configuration for the container.
optional LinuxContainerSecurityContext security_context = 2;
}
// ContainerMetadata holds all necessary information for building the container
@ -488,11 +515,6 @@ message ContainerConfig {
// Annotations is an unstructured key value map that may be set by external
// tools to store and retrieve arbitrary metadata.
map<string, string> annotations = 10;
// If set, run container in privileged mode.
// Processes in privileged containers are essentially equivalent to root on the host.
optional bool privileged = 11;
// If set, the root filesystem of the container is read-only.
optional bool readonly_rootfs = 12;
// Path relative to PodSandboxConfig.LogDirectory for container to store
// the log (STDOUT and STDERR) on the host.
// E.g.,
@ -503,19 +525,18 @@ message ContainerConfig {
// container logs are under active discussion in
// https://issues.k8s.io/24677. There *may* be future change of direction
// for logging as the discussion carries on.
optional string log_path = 13;
// The hash of container config
optional string log_path = 11;
// Variables for interactive containers, these have very specialized
// use-cases (e.g. debugging).
// TODO: Determine if we need to continue supporting these fields that are
// part of Kubernetes's Container Spec.
optional bool stdin = 14;
optional bool stdin_once = 15;
optional bool tty = 16;
optional bool stdin = 12;
optional bool stdin_once = 13;
optional bool tty = 14;
// Linux contains configuration specific to Linux containers.
optional LinuxContainerConfig linux = 17;
optional LinuxContainerConfig linux = 15;
}
message CreateContainerRequest {
@ -737,6 +758,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;
}
message ListImagesResponse {

View File

@ -23,6 +23,7 @@ go_library(
"helpers.go",
"legacy.go",
"naming.go",
"security_context.go",
],
tags = ["automanaged"],
deps = [
@ -41,6 +42,7 @@ go_library(
"//pkg/kubelet/server/streaming:go_default_library",
"//pkg/kubelet/types:go_default_library",
"//pkg/kubelet/util/ioutils:go_default_library",
"//pkg/securitycontext:go_default_library",
"//pkg/util/term:go_default_library",
"//vendor:github.com/docker/engine-api/types",
"//vendor:github.com/docker/engine-api/types/container",
@ -63,6 +65,7 @@ go_test(
"docker_service_test.go",
"helpers_test.go",
"naming_test.go",
"security_context_test.go",
],
library = "go_default_library",
tags = ["automanaged"],
@ -76,8 +79,10 @@ go_test(
"//pkg/kubelet/network/mock_network:go_default_library",
"//pkg/kubelet/types:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//pkg/securitycontext:go_default_library",
"//pkg/util/clock:go_default_library",
"//vendor:github.com/docker/engine-api/types",
"//vendor:github.com/docker/engine-api/types/container",
"//vendor:github.com/golang/mock/gomock",
"//vendor:github.com/stretchr/testify/assert",
],

View File

@ -18,12 +18,14 @@ package dockershim
import (
"fmt"
"strconv"
"strings"
"time"
dockertypes "github.com/docker/engine-api/types"
runtimeApi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/kubelet/dockertools"
)
// This file contains helper functions to convert docker API types to runtime
@ -55,14 +57,25 @@ 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)
}
}
return &runtimeApi.Image{
Id: &image.ID,
RepoTags: image.RepoTags,
RepoDigests: image.RepoDigests,
Size_: &size,
Uid: &uid,
}, nil
}
func toPullableImageID(id string, image *dockertypes.ImageInspect) string {

View File

@ -120,34 +120,15 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
// Fill the HostConfig.
hc := &dockercontainer.HostConfig{
Binds: generateMountBindings(config.GetMounts()),
ReadonlyRootfs: config.GetReadonlyRootfs(),
Privileged: config.GetPrivileged(),
Binds: generateMountBindings(config.GetMounts()),
}
// Apply options derived from the sandbox config.
// Apply cgroupsParent derived from the sandbox config.
if lc := sandboxConfig.GetLinux(); lc != nil {
// Apply Cgroup options.
// TODO: Check if this works with per-pod cgroups.
// TODO: we need to pass the cgroup in syntax expected by cgroup driver but shim does not use docker info yet...
hc.CgroupParent = lc.GetCgroupParent()
// Apply namespace options.
sandboxNSMode := fmt.Sprintf("container:%v", podSandboxID)
hc.NetworkMode = dockercontainer.NetworkMode(sandboxNSMode)
hc.IpcMode = dockercontainer.IpcMode(sandboxNSMode)
hc.UTSMode = ""
hc.PidMode = ""
nsOpts := lc.GetNamespaceOptions()
if nsOpts != nil {
if nsOpts.GetHostNetwork() {
hc.UTSMode = namespaceModeHost
}
if nsOpts.GetHostPid() {
hc.PidMode = namespaceModeHost
}
}
}
// Apply Linux-specific options if applicable.
@ -167,6 +148,9 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
hc.OomScoreAdj = int(rOpts.GetOomScoreAdj())
}
// Note: ShmSize is handled in kube_docker_client.go
// Apply security context.
applyContainerSecurityContext(lc, podSandboxID, createConfig.Config, hc)
}
// Set devices for container.
@ -180,12 +164,12 @@ func (ds *dockerService) CreateContainer(podSandboxID string, config *runtimeApi
}
hc.Resources.Devices = devices
var err error
hc.SecurityOpt, err = getContainerSecurityOpts(config.Metadata.GetName(), sandboxConfig, ds.seccompProfileRoot)
// Apply appArmor and seccomp options.
securityOpts, err := getContainerSecurityOpts(config.Metadata.GetName(), sandboxConfig, ds.seccompProfileRoot)
if err != nil {
return "", fmt.Errorf("failed to generate container security options for container %q: %v", config.Metadata.GetName(), err)
}
// TODO: Add or drop capabilities.
hc.SecurityOpt = append(hc.SecurityOpt, securityOpts...)
createConfig.HostConfig = hc
createResp, err := ds.client.CreateContainer(createConfig)

View File

@ -79,7 +79,7 @@ func (ds *dockerService) RunPodSandbox(config *runtimeApi.PodSandboxConfig) (str
if err != nil {
return createResp.ID, fmt.Errorf("failed to start sandbox container for pod %q: %v", config.Metadata.GetName(), err)
}
if config.GetLinux().GetNamespaceOptions().GetHostNetwork() {
if config.GetLinux().GetSecurityContext().GetNamespaceOptions().GetHostNetwork() {
return createResp.ID, nil
}
@ -286,6 +286,18 @@ func (ds *dockerService) ListPodSandbox(filter *runtimeApi.PodSandboxFilter) ([]
return result, nil
}
// applySandboxLinuxOptions applies LinuxPodSandboxConfig to dockercontainer.HostConfig and dockercontainer.ContainerCreateConfig.
func (ds *dockerService) applySandboxLinuxOptions(hc *dockercontainer.HostConfig, lc *runtimeApi.LinuxPodSandboxConfig, createConfig *dockertypes.ContainerCreateConfig, image string) error {
// Apply Cgroup options.
// TODO: Check if this works with per-pod cgroups.
hc.CgroupParent = lc.GetCgroupParent()
// Apply security context.
applySandboxSecurityContext(lc, createConfig.Config, hc)
return nil
}
// makeSandboxDockerConfig returns dockertypes.ContainerCreateConfig based on runtimeApi.PodSandboxConfig.
func (ds *dockerService) makeSandboxDockerConfig(c *runtimeApi.PodSandboxConfig, image string) (*dockertypes.ContainerCreateConfig, error) {
// Merge annotations and labels because docker supports only labels.
labels := makeLabels(c.GetLabels(), c.GetAnnotations())
@ -316,29 +328,11 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeApi.PodSandboxConfig,
// Apply linux-specific options.
if lc := c.GetLinux(); lc != nil {
// Apply Cgroup options.
// TODO: Check if this works with per-pod cgroups.
hc.CgroupParent = lc.GetCgroupParent()
// Apply namespace options.
hc.NetworkMode, hc.UTSMode, hc.PidMode = "", "", ""
nsOpts := lc.GetNamespaceOptions()
if nsOpts != nil {
if nsOpts.GetHostNetwork() {
hc.NetworkMode = namespaceModeHost
} else {
// Assume kubelet uses either the cni or the kubenet plugin.
// TODO: support docker networking.
hc.NetworkMode = "none"
}
if nsOpts.GetHostIpc() {
hc.IpcMode = namespaceModeHost
}
if nsOpts.GetHostPid() {
hc.PidMode = namespaceModeHost
}
if err := ds.applySandboxLinuxOptions(hc, lc, createConfig, image); err != nil {
return nil, err
}
}
// Set port mappings.
exposedPorts, portBindings := makePortsAndBindings(c.GetPortMappings())
createConfig.Config.ExposedPorts = exposedPorts
@ -355,10 +349,11 @@ func (ds *dockerService) makeSandboxDockerConfig(c *runtimeApi.PodSandboxConfig,
setSandboxResources(hc)
// Set security options.
hc.SecurityOpt, err = getSandboxSecurityOpts(c, ds.seccompProfileRoot)
securityOpts, err := getSandboxSecurityOpts(c, ds.seccompProfileRoot)
if err != nil {
return nil, fmt.Errorf("failed to generate sandbox security options for sandbox %q: %v", c.Metadata.GetName(), err)
}
hc.SecurityOpt = append(hc.SecurityOpt, securityOpts...)
return createConfig, nil
}

View File

@ -186,7 +186,13 @@ func TestHostNetworkPluginInvocation(t *testing.T) {
map[string]string{"annotation": ns},
)
hostNetwork := true
c.Linux = &runtimeApi.LinuxPodSandboxConfig{NamespaceOptions: &runtimeApi.NamespaceOption{HostNetwork: &hostNetwork}}
c.Linux = &runtimeApi.LinuxPodSandboxConfig{
SecurityContext: &runtimeApi.LinuxSandboxSecurityContext{
NamespaceOptions: &runtimeApi.NamespaceOption{
HostNetwork: &hostNetwork,
},
},
}
cID := kubecontainer.ContainerID{Type: runtimeName, ID: fmt.Sprintf("/%v", makeSandboxName(c))}
// No calls to network plugin are expected

View File

@ -123,13 +123,16 @@ func extractLabels(input map[string]string) (map[string]string, map[string]strin
// '<HostPath>:<ContainerPath>:Z', if the volume requires SELinux
// relabeling and the pod provides an SELinux label
func generateMountBindings(mounts []*runtimeApi.Mount) (result []string) {
// TODO: resolve podHasSELinuxLabel
for _, m := range mounts {
bind := fmt.Sprintf("%s:%s", m.GetHostPath(), m.GetContainerPath())
readOnly := m.GetReadonly()
if readOnly {
bind += ":ro"
}
// Only request relabeling if the pod provides an SELinux context. If the pod
// does not provide an SELinux context relabeling will label the volume with
// the container's randomly allocated MCS label. This would restrict access
// to the volume to the container which mounts it first.
if m.GetSelinuxRelabel() {
if readOnly {
bind += ",Z"

View File

@ -0,0 +1,153 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dockershim
import (
"fmt"
"strconv"
dockercontainer "github.com/docker/engine-api/types/container"
"k8s.io/kubernetes/pkg/api"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/securitycontext"
)
// applySandboxSecurityContext updates docker sandbox options according to security context.
func applySandboxSecurityContext(lc *runtimeapi.LinuxPodSandboxConfig, config *dockercontainer.Config, hc *dockercontainer.HostConfig) {
if lc == nil {
return
}
var sc *runtimeapi.LinuxContainerSecurityContext
if lc.SecurityContext != nil {
sc = &runtimeapi.LinuxContainerSecurityContext{
SupplementalGroups: lc.SecurityContext.SupplementalGroups,
RunAsUser: lc.SecurityContext.RunAsUser,
ReadonlyRootfs: lc.SecurityContext.ReadonlyRootfs,
SelinuxOptions: lc.SecurityContext.SelinuxOptions,
NamespaceOptions: lc.SecurityContext.NamespaceOptions,
}
}
modifyContainerConfig(sc, config)
modifyHostConfig(sc, "", hc)
}
// applyContainerSecurityContext updates docker container options according to security context.
func applyContainerSecurityContext(lc *runtimeapi.LinuxContainerConfig, sandboxID string, config *dockercontainer.Config, hc *dockercontainer.HostConfig) {
if lc == nil {
return
}
modifyContainerConfig(lc.SecurityContext, config)
modifyHostConfig(lc.SecurityContext, sandboxID, hc)
return
}
// 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)
}
}
// modifyHostConfig applies security context config to dockercontainer.HostConfig.
func modifyHostConfig(sc *runtimeapi.LinuxContainerSecurityContext, sandboxID string, hostConfig *dockercontainer.HostConfig) {
// Apply namespace options.
modifyNamespaceOptions(sc.GetNamespaceOptions(), sandboxID, hostConfig)
if sc == nil {
return
}
// Apply supplemental groups.
for _, group := range sc.SupplementalGroups {
hostConfig.GroupAdd = append(hostConfig.GroupAdd, strconv.FormatInt(group, 10))
}
// Apply security context for the container.
if sc.Privileged != nil {
hostConfig.Privileged = sc.GetPrivileged()
}
if sc.ReadonlyRootfs != nil {
hostConfig.ReadonlyRootfs = sc.GetReadonlyRootfs()
}
if sc.Capabilities != nil {
hostConfig.CapAdd = sc.GetCapabilities().GetAddCapabilities()
hostConfig.CapDrop = sc.GetCapabilities().GetDropCapabilities()
}
if sc.SelinuxOptions != nil {
hostConfig.SecurityOpt = securitycontext.ModifySecurityOptions(
hostConfig.SecurityOpt,
&api.SELinuxOptions{
User: sc.SelinuxOptions.GetUser(),
Role: sc.SelinuxOptions.GetRole(),
Type: sc.SelinuxOptions.GetType(),
Level: sc.SelinuxOptions.GetLevel(),
},
)
}
}
// modifyNamespaceOptions applies namespaceoptions to dockercontainer.HostConfig.
func modifyNamespaceOptions(nsOpts *runtimeapi.NamespaceOption, sandboxID string, hostConfig *dockercontainer.HostConfig) {
hostNetwork := false
if nsOpts != nil {
if nsOpts.HostNetwork != nil {
hostNetwork = nsOpts.GetHostNetwork()
}
if nsOpts.GetHostPid() {
hostConfig.PidMode = namespaceModeHost
}
if nsOpts.GetHostIpc() {
hostConfig.IpcMode = namespaceModeHost
}
}
// Set for sandbox if sandboxID is not provided.
if sandboxID == "" {
modifyHostNetworkOptionForSandbox(hostNetwork, hostConfig)
} else {
// Set for container if sandboxID is provided.
modifyHostNetworkOptionForContainer(hostNetwork, sandboxID, hostConfig)
}
}
// modifyHostNetworkOptionForSandbox applies NetworkMode/UTSMode to sandbox's dockercontainer.HostConfig.
func modifyHostNetworkOptionForSandbox(hostNetwork bool, hc *dockercontainer.HostConfig) {
if hostNetwork {
hc.NetworkMode = namespaceModeHost
} else {
// Assume kubelet uses either the cni or the kubenet plugin.
// TODO: support docker networking.
hc.NetworkMode = "none"
}
}
// modifyHostNetworkOptionForContainer applies NetworkMode/UTSMode to container's dockercontainer.HostConfig.
func modifyHostNetworkOptionForContainer(hostNetwork bool, sandboxID string, hc *dockercontainer.HostConfig) {
sandboxNSMode := fmt.Sprintf("container:%v", sandboxID)
hc.NetworkMode = dockercontainer.NetworkMode(sandboxNSMode)
hc.IpcMode = dockercontainer.IpcMode(sandboxNSMode)
hc.UTSMode = ""
hc.PidMode = ""
if hostNetwork {
hc.UTSMode = namespaceModeHost
}
}

View File

@ -0,0 +1,265 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package dockershim
import (
"fmt"
"strconv"
"testing"
dockercontainer "github.com/docker/engine-api/types/container"
"github.com/stretchr/testify/assert"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/securitycontext"
)
func TestModifyContainerConfig(t *testing.T) {
var uid int64 = 123
cases := []struct {
name string
sc *runtimeapi.LinuxContainerSecurityContext
expected *dockercontainer.Config
}{
{
name: "container.SecurityContext.RunAsUser set",
sc: &runtimeapi.LinuxContainerSecurityContext{
RunAsUser: &uid,
},
expected: &dockercontainer.Config{
User: strconv.FormatInt(uid, 10),
},
},
{
name: "no RunAsUser value set",
sc: &runtimeapi.LinuxContainerSecurityContext{},
expected: &dockercontainer.Config{},
},
}
for _, tc := range cases {
dockerCfg := &dockercontainer.Config{}
modifyContainerConfig(tc.sc, dockerCfg)
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
}
}
func TestModifyHostConfig(t *testing.T) {
priv := true
setNetworkHC := &dockercontainer.HostConfig{
NetworkMode: "none",
}
setPrivSC := &runtimeapi.LinuxContainerSecurityContext{}
setPrivSC.Privileged = &priv
setPrivHC := &dockercontainer.HostConfig{
Privileged: true,
NetworkMode: "none",
}
setCapsHC := &dockercontainer.HostConfig{
NetworkMode: "none",
CapAdd: []string{"addCapA", "addCapB"},
CapDrop: []string{"dropCapA", "dropCapB"},
}
setSELinuxHC := &dockercontainer.HostConfig{
NetworkMode: "none",
SecurityOpt: []string{
fmt.Sprintf("%s:%s", securitycontext.DockerLabelUser, "user"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelRole, "role"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelType, "type"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelLevel, "level"),
},
}
cases := []struct {
name string
sc *runtimeapi.LinuxContainerSecurityContext
expected *dockercontainer.HostConfig
}{
{
name: "fully set container.SecurityContext",
sc: fullValidSecurityContext(),
expected: fullValidHostConfig(),
},
{
name: "empty container.SecurityContext",
sc: &runtimeapi.LinuxContainerSecurityContext{},
expected: setNetworkHC,
},
{
name: "container.SecurityContext.Privileged",
sc: setPrivSC,
expected: setPrivHC,
},
{
name: "container.SecurityContext.Capabilities",
sc: &runtimeapi.LinuxContainerSecurityContext{
Capabilities: inputCapabilities(),
},
expected: setCapsHC,
},
{
name: "container.SecurityContext.SELinuxOptions",
sc: &runtimeapi.LinuxContainerSecurityContext{
SelinuxOptions: inputSELinuxOptions(),
},
expected: setSELinuxHC,
},
}
for _, tc := range cases {
dockerCfg := &dockercontainer.HostConfig{}
modifyHostConfig(tc.sc, "", dockerCfg)
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
}
}
func TestModifyHostConfigWithGroups(t *testing.T) {
supplementalGroupsSC := &runtimeapi.LinuxContainerSecurityContext{}
supplementalGroupsSC.SupplementalGroups = []int64{2222}
supplementalGroupHC := &dockercontainer.HostConfig{NetworkMode: "none"}
supplementalGroupHC.GroupAdd = []string{"2222"}
testCases := []struct {
name string
securityContext *runtimeapi.LinuxContainerSecurityContext
expected *dockercontainer.HostConfig
}{
{
name: "nil",
securityContext: nil,
expected: &dockercontainer.HostConfig{NetworkMode: "none"},
},
{
name: "SupplementalGroup",
securityContext: supplementalGroupsSC,
expected: supplementalGroupHC,
},
}
for _, tc := range testCases {
dockerCfg := &dockercontainer.HostConfig{}
modifyHostConfig(tc.securityContext, "", dockerCfg)
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
}
}
func TestModifyHostConfigWithSandboxID(t *testing.T) {
priv := true
sandboxID := "sandbox"
sandboxNSMode := fmt.Sprintf("container:%v", sandboxID)
setPrivSC := &runtimeapi.LinuxContainerSecurityContext{}
setPrivSC.Privileged = &priv
setPrivHC := &dockercontainer.HostConfig{
Privileged: true,
IpcMode: dockercontainer.IpcMode(sandboxNSMode),
NetworkMode: dockercontainer.NetworkMode(sandboxNSMode),
}
setCapsHC := &dockercontainer.HostConfig{
CapAdd: []string{"addCapA", "addCapB"},
CapDrop: []string{"dropCapA", "dropCapB"},
IpcMode: dockercontainer.IpcMode(sandboxNSMode),
NetworkMode: dockercontainer.NetworkMode(sandboxNSMode),
}
setSELinuxHC := &dockercontainer.HostConfig{
SecurityOpt: []string{
fmt.Sprintf("%s:%s", securitycontext.DockerLabelUser, "user"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelRole, "role"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelType, "type"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelLevel, "level"),
},
IpcMode: dockercontainer.IpcMode(sandboxNSMode),
NetworkMode: dockercontainer.NetworkMode(sandboxNSMode),
}
cases := []struct {
name string
sc *runtimeapi.LinuxContainerSecurityContext
expected *dockercontainer.HostConfig
}{
{
name: "container.SecurityContext.Privileged",
sc: setPrivSC,
expected: setPrivHC,
},
{
name: "container.SecurityContext.Capabilities",
sc: &runtimeapi.LinuxContainerSecurityContext{
Capabilities: inputCapabilities(),
},
expected: setCapsHC,
},
{
name: "container.SecurityContext.SELinuxOptions",
sc: &runtimeapi.LinuxContainerSecurityContext{
SelinuxOptions: inputSELinuxOptions(),
},
expected: setSELinuxHC,
},
}
for _, tc := range cases {
dockerCfg := &dockercontainer.HostConfig{}
modifyHostConfig(tc.sc, sandboxID, dockerCfg)
assert.Equal(t, tc.expected, dockerCfg, "[Test case %q]", tc.name)
}
}
func fullValidSecurityContext() *runtimeapi.LinuxContainerSecurityContext {
priv := true
return &runtimeapi.LinuxContainerSecurityContext{
Privileged: &priv,
Capabilities: inputCapabilities(),
SelinuxOptions: inputSELinuxOptions(),
}
}
func inputCapabilities() *runtimeapi.Capability {
return &runtimeapi.Capability{
AddCapabilities: []string{"addCapA", "addCapB"},
DropCapabilities: []string{"dropCapA", "dropCapB"},
}
}
func inputSELinuxOptions() *runtimeapi.SELinuxOption {
user := "user"
role := "role"
stype := "type"
level := "level"
return &runtimeapi.SELinuxOption{
User: &user,
Role: &role,
Type: &stype,
Level: &level,
}
}
func fullValidHostConfig() *dockercontainer.HostConfig {
return &dockercontainer.HostConfig{
Privileged: true,
NetworkMode: "none",
CapAdd: []string{"addCapA", "addCapB"},
CapDrop: []string{"dropCapA", "dropCapB"},
SecurityOpt: []string{
fmt.Sprintf("%s:%s", securitycontext.DockerLabelUser, "user"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelRole, "role"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelType, "type"),
fmt.Sprintf("%s:%s", securitycontext.DockerLabelLevel, "level"),
},
}
}

View File

@ -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 := GetUidFromUser(img.Config.User)
// if no user is defined container will run as root
if user == "" {
return true, nil
@ -2488,8 +2488,8 @@ 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 {
// GetUidFromUser splits the uid out of an uid:gid string.
func GetUidFromUser(id string) string {
if id == "" {
return id
}

View File

@ -1454,7 +1454,7 @@ func TestGetUidFromUser(t *testing.T) {
},
}
for k, v := range tests {
actual := getUidFromUser(v.input)
actual := GetUidFromUser(v.input)
if actual != v.expect {
t.Errorf("%s failed. Expected %s but got %s", k, v.expect, actual)
}

View File

@ -25,6 +25,7 @@ go_library(
"kuberuntime_sandbox.go",
"labels.go",
"legacy.go",
"security_context.go",
],
tags = ["automanaged"],
deps = [
@ -47,11 +48,13 @@ go_library(
"//pkg/kubelet/types:go_default_library",
"//pkg/kubelet/util/cache:go_default_library",
"//pkg/kubelet/util/format:go_default_library",
"//pkg/securitycontext:go_default_library",
"//pkg/types:go_default_library",
"//pkg/util/errors:go_default_library",
"//pkg/util/flowcontrol:go_default_library",
"//pkg/util/parsers:go_default_library",
"//pkg/util/runtime:go_default_library",
"//pkg/util/selinux:go_default_library",
"//pkg/util/sets:go_default_library",
"//pkg/util/term:go_default_library",
"//vendor:github.com/coreos/go-semver/semver",

View File

@ -146,6 +146,16 @@ func getContainerSpec(pod *api.Pod, containerName string) *api.Container {
return nil
}
// getImageUID gets uid that will run the command(s) from image.
func (m *kubeGenericRuntimeManager) getImageUser(image string) (int64, error) {
imageStatus, err := m.imageService.ImageStatus(&runtimeApi.ImageSpec{Image: &image})
if err != nil {
return 0, err
}
return imageStatus.GetUid(), nil
}
// isContainerFailed returns true if container has exited and exitcode is not zero.
func isContainerFailed(status *kubecontainer.ContainerStatus) bool {
if status.State == kubecontainer.ContainerStateExited && status.ExitCode != 0 {

View File

@ -40,6 +40,7 @@ import (
"k8s.io/kubernetes/pkg/kubelet/util/format"
kubetypes "k8s.io/kubernetes/pkg/types"
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
"k8s.io/kubernetes/pkg/util/selinux"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/term"
)
@ -136,9 +137,17 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *api.Conta
return nil, err
}
// Verify RunAsNonRoot.
imageUser, err := m.getImageUser(container.Image)
if err != nil {
return nil, err
}
if err := verifyRunAsNonRoot(pod, container, imageUser); err != nil {
return nil, err
}
command, args := kubecontainer.ExpandContainerCommandAndArgs(container, opts.Envs)
containerLogsPath := buildContainerLogsPath(container.Name, restartCount)
podHasSELinuxLabel := pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SELinuxOptions != nil
restartCountUint32 := uint32(restartCount)
config := &runtimeApi.ContainerConfig{
Metadata: &runtimeApi.ContainerMetadata{
@ -151,24 +160,13 @@ func (m *kubeGenericRuntimeManager) generateContainerConfig(container *api.Conta
WorkingDir: &container.WorkingDir,
Labels: newContainerLabels(container, pod),
Annotations: newContainerAnnotations(container, pod, restartCount),
Mounts: m.makeMounts(opts, container, podHasSELinuxLabel),
Devices: makeDevices(opts),
Mounts: m.makeMounts(opts, container),
LogPath: &containerLogsPath,
Stdin: &container.Stdin,
StdinOnce: &container.StdinOnce,
Tty: &container.TTY,
Linux: m.generateLinuxContainerConfig(container, pod),
}
// set privileged and readonlyRootfs
if container.SecurityContext != nil {
securityContext := container.SecurityContext
if securityContext.Privileged != nil {
config.Privileged = securityContext.Privileged
}
if securityContext.ReadOnlyRootFilesystem != nil {
config.ReadonlyRootfs = securityContext.ReadOnlyRootFilesystem
}
Linux: m.generateLinuxContainerConfig(container, pod, imageUser),
}
// set environment variables
@ -186,9 +184,10 @@ 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) *runtimeApi.LinuxContainerConfig {
linuxConfig := &runtimeApi.LinuxContainerConfig{
Resources: &runtimeApi.LinuxContainerResources{},
func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *api.Container, pod *api.Pod, imageUser int64) *runtimeApi.LinuxContainerConfig {
lc := &runtimeApi.LinuxContainerConfig{
Resources: &runtimeApi.LinuxContainerResources{},
SecurityContext: m.determineEffectiveSecurityContext(pod, container, imageUser),
}
// set linux container resources
@ -208,49 +207,23 @@ func (m *kubeGenericRuntimeManager) generateLinuxContainerConfig(container *api.
// of CPU shares.
cpuShares = milliCPUToShares(cpuRequest.MilliValue())
}
linuxConfig.Resources.CpuShares = &cpuShares
lc.Resources.CpuShares = &cpuShares
if memoryLimit != 0 {
linuxConfig.Resources.MemoryLimitInBytes = &memoryLimit
lc.Resources.MemoryLimitInBytes = &memoryLimit
}
// Set OOM score of the container based on qos policy. Processes in lower-priority pods should
// be killed first if the system runs out of memory.
linuxConfig.Resources.OomScoreAdj = &oomScoreAdj
lc.Resources.OomScoreAdj = &oomScoreAdj
if m.cpuCFSQuota {
// if cpuLimit.Amount is nil, then the appropriate default value is returned
// to allow full usage of cpu resource.
cpuQuota, cpuPeriod := milliCPUToQuota(cpuLimit.MilliValue())
linuxConfig.Resources.CpuQuota = &cpuQuota
linuxConfig.Resources.CpuPeriod = &cpuPeriod
lc.Resources.CpuQuota = &cpuQuota
lc.Resources.CpuPeriod = &cpuPeriod
}
// set security context options
if container.SecurityContext != nil {
securityContext := container.SecurityContext
if securityContext.Capabilities != nil {
linuxConfig.Capabilities = &runtimeApi.Capability{
AddCapabilities: make([]string, len(securityContext.Capabilities.Add)),
DropCapabilities: make([]string, len(securityContext.Capabilities.Drop)),
}
for index, value := range securityContext.Capabilities.Add {
linuxConfig.Capabilities.AddCapabilities[index] = string(value)
}
for index, value := range securityContext.Capabilities.Drop {
linuxConfig.Capabilities.DropCapabilities[index] = string(value)
}
}
if securityContext.SELinuxOptions != nil {
linuxConfig.SelinuxOptions = &runtimeApi.SELinuxOption{
User: &securityContext.SELinuxOptions.User,
Role: &securityContext.SELinuxOptions.Role,
Type: &securityContext.SELinuxOptions.Type,
Level: &securityContext.SELinuxOptions.Level,
}
}
}
return linuxConfig
return lc
}
// makeDevices generates container devices for kubelet runtime api.
@ -270,21 +243,20 @@ func makeDevices(opts *kubecontainer.RunContainerOptions) []*runtimeApi.Device {
}
// makeMounts generates container volume mounts for kubelet runtime api.
func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerOptions, container *api.Container, podHasSELinuxLabel bool) []*runtimeApi.Mount {
func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerOptions, container *api.Container) []*runtimeApi.Mount {
volumeMounts := []*runtimeApi.Mount{}
for idx := range opts.Mounts {
v := opts.Mounts[idx]
m := &runtimeApi.Mount{
HostPath: &v.HostPath,
ContainerPath: &v.ContainerPath,
Readonly: &v.ReadOnly,
}
if podHasSELinuxLabel && v.SELinuxRelabel {
m.SelinuxRelabel = &v.SELinuxRelabel
selinuxRelabel := v.SELinuxRelabel && selinux.SELinuxEnabled()
mount := &runtimeApi.Mount{
HostPath: &v.HostPath,
ContainerPath: &v.ContainerPath,
Readonly: &v.ReadOnly,
SelinuxRelabel: &selinuxRelabel,
}
volumeMounts = append(volumeMounts, m)
volumeMounts = append(volumeMounts, mount)
}
// The reason we create and mount the log file in here (not in kubelet) is because
@ -301,9 +273,11 @@ func (m *kubeGenericRuntimeManager) makeMounts(opts *kubecontainer.RunContainerO
glog.Errorf("Error on creating termination-log file %q: %v", containerLogPath, err)
} else {
fs.Close()
selinuxRelabel := selinux.SELinuxEnabled()
volumeMounts = append(volumeMounts, &runtimeApi.Mount{
HostPath: &containerLogPath,
ContainerPath: &container.TerminationMessagePath,
HostPath: &containerLogPath,
ContainerPath: &container.TerminationMessagePath,
SelinuxRelabel: &selinuxRelabel,
})
}
}

View File

@ -120,7 +120,7 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *api.Pod, attem
// TODO: refactor kubelet to get cgroup parent for pod instead of containers
cgroupParent = opts.CgroupParent
}
podSandboxConfig.Linux = generatePodSandboxLinuxConfig(pod, cgroupParent)
podSandboxConfig.Linux = m.generatePodSandboxLinuxConfig(pod, cgroupParent)
if len(portMappings) > 0 {
podSandboxConfig.PortMappings = portMappings
}
@ -129,26 +129,46 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *api.Pod, attem
}
// generatePodSandboxLinuxConfig generates LinuxPodSandboxConfig from api.Pod.
func generatePodSandboxLinuxConfig(pod *api.Pod, cgroupParent string) *runtimeApi.LinuxPodSandboxConfig {
func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *api.Pod, cgroupParent string) *runtimeApi.LinuxPodSandboxConfig {
if pod.Spec.SecurityContext == nil && cgroupParent == "" {
return nil
}
linuxPodSandboxConfig := &runtimeApi.LinuxPodSandboxConfig{}
lc := &runtimeApi.LinuxPodSandboxConfig{}
if cgroupParent != "" {
lc.CgroupParent = &cgroupParent
}
if pod.Spec.SecurityContext != nil {
securityContext := pod.Spec.SecurityContext
linuxPodSandboxConfig.NamespaceOptions = &runtimeApi.NamespaceOption{
HostNetwork: &securityContext.HostNetwork,
HostIpc: &securityContext.HostIPC,
HostPid: &securityContext.HostPID,
sc := pod.Spec.SecurityContext
lc.SecurityContext = &runtimeApi.LinuxSandboxSecurityContext{
NamespaceOptions: &runtimeApi.NamespaceOption{
HostNetwork: &sc.HostNetwork,
HostIpc: &sc.HostIPC,
HostPid: &sc.HostPID,
},
RunAsUser: sc.RunAsUser,
}
if sc.FSGroup != nil {
lc.SecurityContext.SupplementalGroups = append(lc.SecurityContext.SupplementalGroups, *sc.FSGroup)
}
if groups := m.runtimeHelper.GetExtraSupplementalGroupsForPod(pod); len(groups) > 0 {
lc.SecurityContext.SupplementalGroups = append(lc.SecurityContext.SupplementalGroups, groups...)
}
if sc.SupplementalGroups != nil {
lc.SecurityContext.SupplementalGroups = append(lc.SecurityContext.SupplementalGroups, sc.SupplementalGroups...)
}
if sc.SELinuxOptions != nil {
lc.SecurityContext.SelinuxOptions = &runtimeApi.SELinuxOption{
User: &sc.SELinuxOptions.User,
Role: &sc.SELinuxOptions.Role,
Type: &sc.SELinuxOptions.Type,
Level: &sc.SELinuxOptions.Level,
}
}
}
if cgroupParent != "" {
linuxPodSandboxConfig.CgroupParent = &cgroupParent
}
return linuxPodSandboxConfig
return lc
}
// getKubeletSandboxes lists all (or just the running) sandboxes managed by kubelet.

View File

@ -0,0 +1,128 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package kuberuntime
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/api/v1alpha1/runtime"
"k8s.io/kubernetes/pkg/securitycontext"
)
// 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 {
effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
synthesized := convertToRuntimeSecurityContext(effectiveSc)
if synthesized == nil {
synthesized = &runtimeapi.LinuxContainerSecurityContext{}
}
// set RunAsUser.
if synthesized.RunAsUser == nil {
synthesized.RunAsUser = &imageUser
}
// set namespace options and supplemental groups.
podSc := pod.Spec.SecurityContext
if podSc == nil {
return synthesized
}
synthesized.NamespaceOptions = &runtimeapi.NamespaceOption{
HostNetwork: &podSc.HostNetwork,
HostIpc: &podSc.HostIPC,
HostPid: &podSc.HostPID,
}
if podSc.FSGroup != nil {
synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, *podSc.FSGroup)
}
if groups := m.runtimeHelper.GetExtraSupplementalGroupsForPod(pod); len(groups) > 0 {
synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, groups...)
}
if podSc.SupplementalGroups != nil {
synthesized.SupplementalGroups = append(synthesized.SupplementalGroups, podSc.SupplementalGroups...)
}
return synthesized
}
// verifyRunAsNonRoot verifies RunAsNonRoot.
func verifyRunAsNonRoot(pod *api.Pod, container *api.Container, imageUser int64) error {
effectiveSc := securitycontext.DetermineEffectiveSecurityContext(pod, container)
if effectiveSc == nil || effectiveSc.RunAsNonRoot == nil {
return nil
}
if effectiveSc.RunAsUser != nil && *effectiveSc.RunAsUser == 0 {
return fmt.Errorf("container's runAsUser breaks non-root policy")
}
if imageUser == 0 {
return fmt.Errorf("container has runAsNonRoot and image will run as root")
}
return nil
}
// convertToRuntimeSecurityContext converts api.SecurityContext to runtimeapi.SecurityContext.
func convertToRuntimeSecurityContext(securityContext *api.SecurityContext) *runtimeapi.LinuxContainerSecurityContext {
if securityContext == nil {
return nil
}
return &runtimeapi.LinuxContainerSecurityContext{
RunAsUser: securityContext.RunAsUser,
Privileged: securityContext.Privileged,
ReadonlyRootfs: securityContext.ReadOnlyRootFilesystem,
Capabilities: convertToRuntimeCapabilities(securityContext.Capabilities),
SelinuxOptions: convertToRuntimeSELinuxOption(securityContext.SELinuxOptions),
}
}
// convertToRuntimeSELinuxOption converts api.SELinuxOptions to runtimeapi.SELinuxOption.
func convertToRuntimeSELinuxOption(opts *api.SELinuxOptions) *runtimeapi.SELinuxOption {
if opts == nil {
return nil
}
return &runtimeapi.SELinuxOption{
User: &opts.User,
Role: &opts.Role,
Type: &opts.Type,
Level: &opts.Level,
}
}
// convertToRuntimeCapabilities converts api.Capabilities to runtimeapi.Capability.
func convertToRuntimeCapabilities(opts *api.Capabilities) *runtimeapi.Capability {
if opts == nil {
return nil
}
capabilities := &runtimeapi.Capability{
AddCapabilities: make([]string, len(opts.Add)),
DropCapabilities: make([]string, len(opts.Drop)),
}
for index, value := range opts.Add {
capabilities.AddCapabilities[index] = string(value)
}
for index, value := range opts.Drop {
capabilities.DropCapabilities[index] = string(value)
}
return capabilities
}

View File

@ -91,13 +91,20 @@ func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container
}
if effectiveSC.SELinuxOptions != nil {
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelUser, effectiveSC.SELinuxOptions.User)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelRole, effectiveSC.SELinuxOptions.Role)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelType, effectiveSC.SELinuxOptions.Type)
hostConfig.SecurityOpt = modifySecurityOption(hostConfig.SecurityOpt, dockerLabelLevel, effectiveSC.SELinuxOptions.Level)
hostConfig.SecurityOpt = ModifySecurityOptions(hostConfig.SecurityOpt, effectiveSC.SELinuxOptions)
}
}
// ModifySecurityOptions adds SELinux options to config.
func ModifySecurityOptions(config []string, selinuxOpts *api.SELinuxOptions) []string {
config = modifySecurityOption(config, DockerLabelUser, selinuxOpts.User)
config = modifySecurityOption(config, DockerLabelRole, selinuxOpts.Role)
config = modifySecurityOption(config, DockerLabelType, selinuxOpts.Type)
config = modifySecurityOption(config, DockerLabelLevel, selinuxOpts.Level)
return config
}
// modifySecurityOption adds the security option of name to the config array with value in the form
// of name:value
func modifySecurityOption(config []string, name, value string) []string {

View File

@ -104,10 +104,10 @@ func TestModifyHostConfig(t *testing.T) {
setSELinuxHC := &dockercontainer.HostConfig{}
setSELinuxHC.SecurityOpt = []string{
fmt.Sprintf("%s:%s", dockerLabelUser, "user"),
fmt.Sprintf("%s:%s", dockerLabelRole, "role"),
fmt.Sprintf("%s:%s", dockerLabelType, "type"),
fmt.Sprintf("%s:%s", dockerLabelLevel, "level"),
fmt.Sprintf("%s:%s", DockerLabelUser, "user"),
fmt.Sprintf("%s:%s", DockerLabelRole, "role"),
fmt.Sprintf("%s:%s", DockerLabelType, "type"),
fmt.Sprintf("%s:%s", DockerLabelLevel, "level"),
}
// seLinuxLabelsSC := fullValidSecurityContext()
@ -325,10 +325,10 @@ func fullValidHostConfig() *dockercontainer.HostConfig {
CapAdd: []string{"addCapA", "addCapB"},
CapDrop: []string{"dropCapA", "dropCapB"},
SecurityOpt: []string{
fmt.Sprintf("%s:%s", dockerLabelUser, "user"),
fmt.Sprintf("%s:%s", dockerLabelRole, "role"),
fmt.Sprintf("%s:%s", dockerLabelType, "type"),
fmt.Sprintf("%s:%s", dockerLabelLevel, "level"),
fmt.Sprintf("%s:%s", DockerLabelUser, "user"),
fmt.Sprintf("%s:%s", DockerLabelRole, "role"),
fmt.Sprintf("%s:%s", DockerLabelType, "type"),
fmt.Sprintf("%s:%s", DockerLabelLevel, "level"),
},
}
}

View File

@ -41,9 +41,9 @@ type SecurityContextProvider interface {
}
const (
dockerLabelUser string = "label:user"
dockerLabelRole string = "label:role"
dockerLabelType string = "label:type"
dockerLabelLevel string = "label:level"
dockerLabelDisable string = "label:disable"
DockerLabelUser string = "label:user"
DockerLabelRole string = "label:role"
DockerLabelType string = "label:type"
DockerLabelLevel string = "label:level"
DockerLabelDisable string = "label:disable"
)