mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-31 15:25:57 +00:00
Merge pull request #33663 from pmorie/selinux-fixes
Automatic merge from submit-queue SELinux Overhaul Overhauls handling of SELinux in Kubernetes. TLDR: Kubelet dir no longer has to be labeled `svirt_sandbox_file_t`. Fixes #33351 and #33510. Implements #33951.
This commit is contained in:
commit
44b684ad53
@ -418,18 +418,6 @@ function start_kubelet {
|
|||||||
|
|
||||||
mkdir -p /var/lib/kubelet
|
mkdir -p /var/lib/kubelet
|
||||||
if [[ -z "${DOCKERIZE_KUBELET}" ]]; then
|
if [[ -z "${DOCKERIZE_KUBELET}" ]]; then
|
||||||
# On selinux enabled systems, it might
|
|
||||||
# require to relabel /var/lib/kubelet
|
|
||||||
if which selinuxenabled &> /dev/null && \
|
|
||||||
selinuxenabled && \
|
|
||||||
which chcon > /dev/null ; then
|
|
||||||
if [[ ! $(ls -Zd /var/lib/kubelet) =~ system_u:object_r:svirt_sandbox_file_t:s0 ]] ; then
|
|
||||||
echo "Applying SELinux label to /var/lib/kubelet directory."
|
|
||||||
if ! sudo chcon -Rt svirt_sandbox_file_t /var/lib/kubelet; then
|
|
||||||
echo "Failed to apply selinux label to /var/lib/kubelet."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Enable dns
|
# Enable dns
|
||||||
if [[ "${ENABLE_CLUSTER_DNS}" = true ]]; then
|
if [[ "${ENABLE_CLUSTER_DNS}" = true ]]; then
|
||||||
dns_args="--cluster-dns=${DNS_SERVER_IP} --cluster-domain=${DNS_DOMAIN}"
|
dns_args="--cluster-dns=${DNS_SERVER_IP} --cluster-domain=${DNS_DOMAIN}"
|
||||||
@ -509,7 +497,7 @@ function start_kubelet {
|
|||||||
--volume=/var/run:/var/run:rw \
|
--volume=/var/run:/var/run:rw \
|
||||||
--volume=/sys:/sys:ro \
|
--volume=/sys:/sys:ro \
|
||||||
--volume=/var/lib/docker/:/var/lib/docker:ro \
|
--volume=/var/lib/docker/:/var/lib/docker:ro \
|
||||||
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw,z \
|
--volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
|
||||||
--volume=/dev:/dev \
|
--volume=/dev:/dev \
|
||||||
${cred_bind} \
|
${cred_bind} \
|
||||||
--net=host \
|
--net=host \
|
||||||
|
@ -152,20 +152,6 @@ else
|
|||||||
test_args="$test_args --disable-kubenet=true"
|
test_args="$test_args --disable-kubenet=true"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# On selinux enabled systems, it might
|
|
||||||
# require to relabel /var/lib/kubelet
|
|
||||||
if which selinuxenabled &> /dev/null && \
|
|
||||||
selinuxenabled && \
|
|
||||||
which chcon > /dev/null ; then
|
|
||||||
mkdir -p /var/lib/kubelet
|
|
||||||
if [[ ! $(ls -Zd /var/lib/kubelet) =~ svirt_sandbox_file_t ]] ; then
|
|
||||||
echo "Applying SELinux label to /var/lib/kubelet directory."
|
|
||||||
if ! sudo chcon -Rt svirt_sandbox_file_t /var/lib/kubelet; then
|
|
||||||
echo "Failed to apply selinux label to /var/lib/kubelet."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Test using the host the script was run on
|
# Test using the host the script was run on
|
||||||
# Provided for backwards compatibility
|
# Provided for backwards compatibility
|
||||||
go run test/e2e_node/runner/local/run_local.go --ginkgo-flags="$ginkgoflags" \
|
go run test/e2e_node/runner/local/run_local.go --ginkgo-flags="$ginkgoflags" \
|
||||||
|
@ -106,7 +106,6 @@ go_library(
|
|||||||
"//pkg/util/oom:go_default_library",
|
"//pkg/util/oom:go_default_library",
|
||||||
"//pkg/util/procfs:go_default_library",
|
"//pkg/util/procfs:go_default_library",
|
||||||
"//pkg/util/runtime:go_default_library",
|
"//pkg/util/runtime:go_default_library",
|
||||||
"//pkg/util/selinux:go_default_library",
|
|
||||||
"//pkg/util/sets:go_default_library",
|
"//pkg/util/sets:go_default_library",
|
||||||
"//pkg/util/term:go_default_library",
|
"//pkg/util/term:go_default_library",
|
||||||
"//pkg/util/validation:go_default_library",
|
"//pkg/util/validation:go_default_library",
|
||||||
|
@ -56,6 +56,7 @@ go_library(
|
|||||||
"//pkg/util/oom:go_default_library",
|
"//pkg/util/oom:go_default_library",
|
||||||
"//pkg/util/procfs:go_default_library",
|
"//pkg/util/procfs:go_default_library",
|
||||||
"//pkg/util/runtime:go_default_library",
|
"//pkg/util/runtime:go_default_library",
|
||||||
|
"//pkg/util/selinux:go_default_library",
|
||||||
"//pkg/util/sets:go_default_library",
|
"//pkg/util/sets:go_default_library",
|
||||||
"//pkg/util/strings:go_default_library",
|
"//pkg/util/strings:go_default_library",
|
||||||
"//pkg/util/term:go_default_library",
|
"//pkg/util/term:go_default_library",
|
||||||
|
@ -65,6 +65,7 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/util/oom"
|
"k8s.io/kubernetes/pkg/util/oom"
|
||||||
"k8s.io/kubernetes/pkg/util/procfs"
|
"k8s.io/kubernetes/pkg/util/procfs"
|
||||||
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
utilruntime "k8s.io/kubernetes/pkg/util/runtime"
|
||||||
|
"k8s.io/kubernetes/pkg/util/selinux"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
utilstrings "k8s.io/kubernetes/pkg/util/strings"
|
utilstrings "k8s.io/kubernetes/pkg/util/strings"
|
||||||
"k8s.io/kubernetes/pkg/util/term"
|
"k8s.io/kubernetes/pkg/util/term"
|
||||||
@ -507,20 +508,14 @@ func makeEnvList(envs []kubecontainer.EnvVar) (result []string) {
|
|||||||
// '<HostPath>:<ContainerPath>', or
|
// '<HostPath>:<ContainerPath>', or
|
||||||
// '<HostPath>:<ContainerPath>:ro', if the path is read only, or
|
// '<HostPath>:<ContainerPath>:ro', if the path is read only, or
|
||||||
// '<HostPath>:<ContainerPath>:Z', if the volume requires SELinux
|
// '<HostPath>:<ContainerPath>:Z', if the volume requires SELinux
|
||||||
// relabeling and the pod provides an SELinux label
|
// relabeling
|
||||||
func makeMountBindings(mounts []kubecontainer.Mount, podHasSELinuxLabel bool) (result []string) {
|
func makeMountBindings(mounts []kubecontainer.Mount) (result []string) {
|
||||||
for _, m := range mounts {
|
for _, m := range mounts {
|
||||||
bind := fmt.Sprintf("%s:%s", m.HostPath, m.ContainerPath)
|
bind := fmt.Sprintf("%s:%s", m.HostPath, m.ContainerPath)
|
||||||
if m.ReadOnly {
|
if m.ReadOnly {
|
||||||
bind += ":ro"
|
bind += ":ro"
|
||||||
}
|
}
|
||||||
// Only request relabeling if the pod provides an
|
if m.SELinuxRelabel && selinux.SELinuxEnabled() {
|
||||||
// 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.SELinuxRelabel && podHasSELinuxLabel {
|
|
||||||
if m.ReadOnly {
|
if m.ReadOnly {
|
||||||
bind += ",Z"
|
bind += ",Z"
|
||||||
} else {
|
} else {
|
||||||
@ -646,8 +641,7 @@ func (dm *DockerManager) runContainer(
|
|||||||
{PathOnHost: "/dev/nvidia-uvm", PathInContainer: "/dev/nvidia-uvm", CgroupPermissions: "mrw"},
|
{PathOnHost: "/dev/nvidia-uvm", PathInContainer: "/dev/nvidia-uvm", CgroupPermissions: "mrw"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
podHasSELinuxLabel := pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SELinuxOptions != nil
|
binds := makeMountBindings(opts.Mounts)
|
||||||
binds := makeMountBindings(opts.Mounts, podHasSELinuxLabel)
|
|
||||||
// The reason we create and mount the log file in here (not in kubelet) is because
|
// The reason we create and mount the log file in here (not in kubelet) is because
|
||||||
// the file's location depends on the ID of the container, and we need to create and
|
// the file's location depends on the ID of the container, and we need to create and
|
||||||
// mount the file before actually starting the container.
|
// mount the file before actually starting the container.
|
||||||
@ -666,6 +660,13 @@ func (dm *DockerManager) runContainer(
|
|||||||
} else {
|
} else {
|
||||||
fs.Close() // Close immediately; we're just doing a `touch` here
|
fs.Close() // Close immediately; we're just doing a `touch` here
|
||||||
b := fmt.Sprintf("%s:%s", containerLogPath, container.TerminationMessagePath)
|
b := fmt.Sprintf("%s:%s", containerLogPath, container.TerminationMessagePath)
|
||||||
|
|
||||||
|
// Have docker relabel the termination log path if SELinux is
|
||||||
|
// enabled.
|
||||||
|
if selinux.SELinuxEnabled() {
|
||||||
|
b += ":Z"
|
||||||
|
}
|
||||||
|
|
||||||
binds = append(binds, b)
|
binds = append(binds, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,10 +133,11 @@ func makeHostsMount(podDir, podIP, hostName, hostDomainName string) (*kubecontai
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &kubecontainer.Mount{
|
return &kubecontainer.Mount{
|
||||||
Name: "k8s-managed-etc-hosts",
|
Name: "k8s-managed-etc-hosts",
|
||||||
ContainerPath: etcHostsPath,
|
ContainerPath: etcHostsPath,
|
||||||
HostPath: hostsFilePath,
|
HostPath: hostsFilePath,
|
||||||
ReadOnly: false,
|
ReadOnly: false,
|
||||||
|
SELinuxRelabel: true,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,15 +252,6 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *api.Pod, container *api.Cont
|
|||||||
volumes := kl.volumeManager.GetMountedVolumesForPod(podName)
|
volumes := kl.volumeManager.GetMountedVolumesForPod(podName)
|
||||||
|
|
||||||
opts.PortMappings = makePortMappings(container)
|
opts.PortMappings = makePortMappings(container)
|
||||||
// Docker does not relabel volumes if the container is running
|
|
||||||
// in the host pid or ipc namespaces so the kubelet must
|
|
||||||
// relabel the volumes
|
|
||||||
if pod.Spec.SecurityContext != nil && (pod.Spec.SecurityContext.HostIPC || pod.Spec.SecurityContext.HostPID) {
|
|
||||||
err = kl.relabelVolumes(pod, volumes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
|
opts.Mounts, err = makeMounts(pod, kl.getPodDir(pod.UID), container, hostname, hostDomainName, podIP, volumes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,16 +19,13 @@ package kubelet
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
|
||||||
"k8s.io/kubernetes/pkg/securitycontext"
|
|
||||||
"k8s.io/kubernetes/pkg/types"
|
"k8s.io/kubernetes/pkg/types"
|
||||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
"k8s.io/kubernetes/pkg/util/selinux"
|
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume"
|
||||||
volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
|
volumetypes "k8s.io/kubernetes/pkg/volume/util/types"
|
||||||
@ -81,51 +78,6 @@ func (kl *Kubelet) newVolumeMounterFromPlugins(spec *volume.Spec, pod *api.Pod,
|
|||||||
return physicalMounter, nil
|
return physicalMounter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// relabelVolumes relabels SELinux volumes to match the pod's
|
|
||||||
// SELinuxOptions specification. This is only needed if the pod uses
|
|
||||||
// hostPID or hostIPC. Otherwise relabeling is delegated to docker.
|
|
||||||
func (kl *Kubelet) relabelVolumes(pod *api.Pod, volumes kubecontainer.VolumeMap) error {
|
|
||||||
if pod.Spec.SecurityContext.SELinuxOptions == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rootDirContext, err := kl.getRootDirContext()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
selinuxRunner := selinux.NewSelinuxContextRunner()
|
|
||||||
// Apply the pod's Level to the rootDirContext
|
|
||||||
rootDirSELinuxOptions, err := securitycontext.ParseSELinuxOptions(rootDirContext)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
rootDirSELinuxOptions.Level = pod.Spec.SecurityContext.SELinuxOptions.Level
|
|
||||||
volumeContext := fmt.Sprintf("%s:%s:%s:%s", rootDirSELinuxOptions.User, rootDirSELinuxOptions.Role, rootDirSELinuxOptions.Type, rootDirSELinuxOptions.Level)
|
|
||||||
|
|
||||||
for _, vol := range volumes {
|
|
||||||
if vol.Mounter.GetAttributes().Managed && vol.Mounter.GetAttributes().SupportsSELinux {
|
|
||||||
// Relabel the volume and its content to match the 'Level' of the pod
|
|
||||||
path, err := volume.GetPath(vol.Mounter)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return selinuxRunner.SetContext(path, volumeContext)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
vol.SELinuxLabeled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// cleanupOrphanedPodDirs removes the volumes of pods that should not be
|
// cleanupOrphanedPodDirs removes the volumes of pods that should not be
|
||||||
// running and that have no containers running.
|
// running and that have no containers running.
|
||||||
func (kl *Kubelet) cleanupOrphanedPodDirs(
|
func (kl *Kubelet) cleanupOrphanedPodDirs(
|
||||||
|
@ -1082,7 +1082,7 @@ func (r *Runtime) preparePodArgs(manifest *appcschema.PodManifest, manifestFileN
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runtime) getSelinuxContext(opt *api.SELinuxOptions) (string, error) {
|
func (r *Runtime) getSelinuxContext(opt *api.SELinuxOptions) (string, error) {
|
||||||
selinuxRunner := selinux.NewSelinuxContextRunner()
|
selinuxRunner := selinux.NewSELinuxRunner()
|
||||||
str, err := selinuxRunner.Getfilecon(r.config.Dir)
|
str, err := selinuxRunner.Getfilecon(r.config.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -14,5 +14,6 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Package selinux contains selinux utility functions.
|
// Package selinux contains wrapper functions for the libcontainer SELinux
|
||||||
|
// package. A NOP implementation is provided for non-linux platforms.
|
||||||
package selinux // import "k8s.io/kubernetes/pkg/util/selinux"
|
package selinux // import "k8s.io/kubernetes/pkg/util/selinux"
|
||||||
|
@ -16,14 +16,24 @@ limitations under the License.
|
|||||||
|
|
||||||
package selinux
|
package selinux
|
||||||
|
|
||||||
// SelinuxContextRunner knows how to chcon of a directory and
|
// Note: the libcontainer SELinux package is only built for Linux, so it is
|
||||||
// how to get the selinux context of a file.
|
// necessary to have a NOP wrapper which is built for non-Linux platforms to
|
||||||
type SelinuxContextRunner interface {
|
// allow code that links to this package not to differentiate its own methods
|
||||||
SetContext(dir, context string) error
|
// for Linux and non-Linux platforms.
|
||||||
|
//
|
||||||
|
// SELinuxRunner wraps certain libcontainer SELinux calls. For more
|
||||||
|
// information, see:
|
||||||
|
//
|
||||||
|
// https://github.com/opencontainers/runc/blob/master/libcontainer/selinux/selinux.go
|
||||||
|
type SELinuxRunner interface {
|
||||||
|
// Getfilecon returns the SELinux context for the given path or returns an
|
||||||
|
// error.
|
||||||
Getfilecon(path string) (string, error)
|
Getfilecon(path string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSelinuxContextRunner returns a new chconRunner.
|
// NewSELinuxRunner returns a new SELinuxRunner appropriate for the platform.
|
||||||
func NewSelinuxContextRunner() SelinuxContextRunner {
|
// On Linux, all methods short-circuit and return NOP values if SELinux is
|
||||||
return &realSelinuxContextRunner{}
|
// disabled. On non-Linux platforms, a NOP implementation is returned.
|
||||||
|
func NewSELinuxRunner() SELinuxRunner {
|
||||||
|
return &realSELinuxRunner{}
|
||||||
}
|
}
|
||||||
|
@ -19,25 +19,34 @@ limitations under the License.
|
|||||||
package selinux
|
package selinux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/opencontainers/runc/libcontainer/selinux"
|
"github.com/opencontainers/runc/libcontainer/selinux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type realSelinuxContextRunner struct{}
|
// SELinuxEnabled returns whether SELinux is enabled on the system. SELinux
|
||||||
|
// has a tri-state:
|
||||||
func (_ *realSelinuxContextRunner) SetContext(dir, context string) error {
|
//
|
||||||
// If SELinux is not enabled, return an empty string
|
// 1. disabled: SELinux Kernel modules not loaded, SELinux policy is not
|
||||||
if !selinux.SelinuxEnabled() {
|
// checked during Kernel MAC checks
|
||||||
return nil
|
// 2. enforcing: Enabled; SELinux policy violations are denied and logged
|
||||||
}
|
// in the audit log
|
||||||
|
// 3. permissive: Enabled, but SELinux policy violations are permitted and
|
||||||
return selinux.Setfilecon(dir, context)
|
// logged in the audit log
|
||||||
|
//
|
||||||
|
// SELinuxEnabled returns true if SELinux is enforcing or permissive, and
|
||||||
|
// false if it is disabled.
|
||||||
|
func SELinuxEnabled() bool {
|
||||||
|
return selinux.SelinuxEnabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *realSelinuxContextRunner) Getfilecon(path string) (string, error) {
|
// realSELinuxRunner is the real implementation of SELinuxRunner interface for
|
||||||
if !selinux.SelinuxEnabled() {
|
// Linux.
|
||||||
return "", fmt.Errorf("SELinux is not enabled")
|
type realSELinuxRunner struct{}
|
||||||
|
|
||||||
|
var _ SELinuxRunner = &realSELinuxRunner{}
|
||||||
|
|
||||||
|
func (_ *realSELinuxRunner) Getfilecon(path string) (string, error) {
|
||||||
|
if !SELinuxEnabled() {
|
||||||
|
return "", nil
|
||||||
}
|
}
|
||||||
return selinux.Getfilecon(path)
|
return selinux.Getfilecon(path)
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,16 @@ limitations under the License.
|
|||||||
|
|
||||||
package selinux
|
package selinux
|
||||||
|
|
||||||
type realSelinuxContextRunner struct{}
|
// SELinuxEnabled always returns false on non-linux platforms.
|
||||||
|
func SELinuxEnabled() bool {
|
||||||
func (_ *realSelinuxContextRunner) SetContext(dir, context string) error {
|
return false
|
||||||
// NOP
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (_ *realSelinuxContextRunner) Getfilecon(path string) (string, error) {
|
// realSELinuxRunner is the NOP implementation of the SELinuxRunner interface.
|
||||||
// NOP
|
type realSELinuxRunner struct{}
|
||||||
|
|
||||||
|
var _ SELinuxRunner = &realSELinuxRunner{}
|
||||||
|
|
||||||
|
func (_ *realSELinuxRunner) Getfilecon(path string) (string, error) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ go_library(
|
|||||||
"//pkg/volume:go_default_library",
|
"//pkg/volume:go_default_library",
|
||||||
"//pkg/volume/util:go_default_library",
|
"//pkg/volume/util:go_default_library",
|
||||||
"//vendor:github.com/golang/glog",
|
"//vendor:github.com/golang/glog",
|
||||||
"//vendor:github.com/opencontainers/runc/libcontainer/selinux",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -105,7 +105,6 @@ func (plugin *emptyDirPlugin) newMounterInternal(spec *volume.Spec, pod *api.Pod
|
|||||||
mounter: mounter,
|
mounter: mounter,
|
||||||
mountDetector: mountDetector,
|
mountDetector: mountDetector,
|
||||||
plugin: plugin,
|
plugin: plugin,
|
||||||
rootContext: plugin.host.GetRootContext(),
|
|
||||||
MetricsProvider: volume.NewMetricsDu(getPath(pod.UID, spec.Name(), plugin.host)),
|
MetricsProvider: volume.NewMetricsDu(getPath(pod.UID, spec.Name(), plugin.host)),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -164,7 +163,6 @@ type emptyDir struct {
|
|||||||
mounter mount.Interface
|
mounter mount.Interface
|
||||||
mountDetector mountDetector
|
mountDetector mountDetector
|
||||||
plugin *emptyDirPlugin
|
plugin *emptyDirPlugin
|
||||||
rootContext string
|
|
||||||
volume.MetricsProvider
|
volume.MetricsProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,17 +200,11 @@ func (ed *emptyDir) SetUpAt(dir string, fsGroup *int64) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the effective SELinuxOptions to use for this volume.
|
|
||||||
securityContext := ""
|
|
||||||
if selinuxEnabled() {
|
|
||||||
securityContext = ed.rootContext
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ed.medium {
|
switch ed.medium {
|
||||||
case api.StorageMediumDefault:
|
case api.StorageMediumDefault:
|
||||||
err = ed.setupDir(dir)
|
err = ed.setupDir(dir)
|
||||||
case api.StorageMediumMemory:
|
case api.StorageMediumMemory:
|
||||||
err = ed.setupTmpfs(dir, securityContext)
|
err = ed.setupTmpfs(dir)
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("unknown storage medium %q", ed.medium)
|
err = fmt.Errorf("unknown storage medium %q", ed.medium)
|
||||||
}
|
}
|
||||||
@ -228,7 +220,7 @@ func (ed *emptyDir) SetUpAt(dir string, fsGroup *int64) error {
|
|||||||
|
|
||||||
// setupTmpfs creates a tmpfs mount at the specified directory with the
|
// setupTmpfs creates a tmpfs mount at the specified directory with the
|
||||||
// specified SELinux context.
|
// specified SELinux context.
|
||||||
func (ed *emptyDir) setupTmpfs(dir string, selinux string) error {
|
func (ed *emptyDir) setupTmpfs(dir string) error {
|
||||||
if ed.mounter == nil {
|
if ed.mounter == nil {
|
||||||
return fmt.Errorf("memory storage requested, but mounter is nil")
|
return fmt.Errorf("memory storage requested, but mounter is nil")
|
||||||
}
|
}
|
||||||
@ -246,17 +238,8 @@ func (ed *emptyDir) setupTmpfs(dir string, selinux string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default a tmpfs mount will receive a different SELinux context
|
glog.V(3).Infof("pod %v: mounting tmpfs for volume %v", ed.pod.UID, ed.volName)
|
||||||
// which is not readable from the SELinux context of a docker container.
|
return ed.mounter.Mount("tmpfs", dir, "tmpfs", nil /* options */)
|
||||||
var opts []string
|
|
||||||
if selinux != "" {
|
|
||||||
opts = []string{fmt.Sprintf("rootcontext=\"%v\"", selinux)}
|
|
||||||
} else {
|
|
||||||
opts = []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
glog.V(3).Infof("pod %v: mounting tmpfs for volume %v with opts %v", ed.pod.UID, ed.volName, opts)
|
|
||||||
return ed.mounter.Mount("tmpfs", dir, "tmpfs", opts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// setupDir creates the directory with the specified SELinux context and
|
// setupDir creates the directory with the specified SELinux context and
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/opencontainers/runc/libcontainer/selinux"
|
|
||||||
"k8s.io/kubernetes/pkg/util/mount"
|
"k8s.io/kubernetes/pkg/util/mount"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,8 +51,3 @@ func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, er
|
|||||||
}
|
}
|
||||||
return mediumUnknown, !notMnt, nil
|
return mediumUnknown, !notMnt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// selinuxEnabled determines whether SELinux is enabled.
|
|
||||||
func selinuxEnabled() bool {
|
|
||||||
return selinux.SelinuxEnabled()
|
|
||||||
}
|
|
||||||
|
@ -33,9 +33,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Construct an instance of a plugin, by name.
|
// Construct an instance of a plugin, by name.
|
||||||
func makePluginUnderTest(t *testing.T, plugName, basePath, rootContext string) volume.VolumePlugin {
|
func makePluginUnderTest(t *testing.T, plugName, basePath string) volume.VolumePlugin {
|
||||||
plugMgr := volume.VolumePluginMgr{}
|
plugMgr := volume.VolumePluginMgr{}
|
||||||
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(basePath, nil, nil, rootContext))
|
plugMgr.InitPlugins(ProbeVolumePlugins(), volumetest.NewFakeVolumeHost(basePath, nil, nil, "" /* rootContext */))
|
||||||
|
|
||||||
plug, err := plugMgr.FindPluginByName(plugName)
|
plug, err := plugMgr.FindPluginByName(plugName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -50,7 +50,7 @@ func TestCanSupport(t *testing.T) {
|
|||||||
t.Fatalf("can't make a temp dir: %v", err)
|
t.Fatalf("can't make a temp dir: %v", err)
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", tmpDir, "" /* rootContext */)
|
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", tmpDir)
|
||||||
|
|
||||||
if plug.GetPluginName() != "kubernetes.io/empty-dir" {
|
if plug.GetPluginName() != "kubernetes.io/empty-dir" {
|
||||||
t.Errorf("Wrong name: %s", plug.GetPluginName())
|
t.Errorf("Wrong name: %s", plug.GetPluginName())
|
||||||
@ -75,44 +75,13 @@ func (fake *fakeMountDetector) GetMountMedium(path string) (storageMedium, bool,
|
|||||||
func TestPluginEmptyRootContext(t *testing.T) {
|
func TestPluginEmptyRootContext(t *testing.T) {
|
||||||
doTestPlugin(t, pluginTestConfig{
|
doTestPlugin(t, pluginTestConfig{
|
||||||
medium: api.StorageMediumDefault,
|
medium: api.StorageMediumDefault,
|
||||||
rootContext: "",
|
|
||||||
expectedSetupMounts: 0,
|
expectedSetupMounts: 0,
|
||||||
expectedTeardownMounts: 0})
|
expectedTeardownMounts: 0})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPluginRootContextSet(t *testing.T) {
|
|
||||||
if !selinuxEnabled() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
doTestPlugin(t, pluginTestConfig{
|
|
||||||
medium: api.StorageMediumDefault,
|
|
||||||
rootContext: "user:role:type:range",
|
|
||||||
expectedSELinux: "user:role:type:range",
|
|
||||||
expectedSetupMounts: 0,
|
|
||||||
expectedTeardownMounts: 0})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPluginTmpfs(t *testing.T) {
|
|
||||||
if !selinuxEnabled() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
doTestPlugin(t, pluginTestConfig{
|
|
||||||
medium: api.StorageMediumMemory,
|
|
||||||
rootContext: "user:role:type:range",
|
|
||||||
expectedSELinux: "user:role:type:range",
|
|
||||||
expectedSetupMounts: 1,
|
|
||||||
shouldBeMountedBeforeTeardown: true,
|
|
||||||
expectedTeardownMounts: 1})
|
|
||||||
}
|
|
||||||
|
|
||||||
type pluginTestConfig struct {
|
type pluginTestConfig struct {
|
||||||
medium api.StorageMedium
|
medium api.StorageMedium
|
||||||
rootContext string
|
|
||||||
SELinuxOptions *api.SELinuxOptions
|
|
||||||
idempotent bool
|
idempotent bool
|
||||||
expectedSELinux string
|
|
||||||
expectedSetupMounts int
|
expectedSetupMounts int
|
||||||
shouldBeMountedBeforeTeardown bool
|
shouldBeMountedBeforeTeardown bool
|
||||||
expectedTeardownMounts int
|
expectedTeardownMounts int
|
||||||
@ -130,7 +99,7 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) {
|
|||||||
volumePath = path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/test-volume")
|
volumePath = path.Join(basePath, "pods/poduid/volumes/kubernetes.io~empty-dir/test-volume")
|
||||||
metadataDir = path.Join(basePath, "pods/poduid/plugins/kubernetes.io~empty-dir/test-volume")
|
metadataDir = path.Join(basePath, "pods/poduid/plugins/kubernetes.io~empty-dir/test-volume")
|
||||||
|
|
||||||
plug = makePluginUnderTest(t, "kubernetes.io/empty-dir", basePath, config.rootContext)
|
plug = makePluginUnderTest(t, "kubernetes.io/empty-dir", basePath)
|
||||||
volumeName = "test-volume"
|
volumeName = "test-volume"
|
||||||
spec = &api.Volume{
|
spec = &api.Volume{
|
||||||
Name: volumeName,
|
Name: volumeName,
|
||||||
@ -142,24 +111,6 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) {
|
|||||||
pod = &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
pod = &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set up the SELinux options on the pod
|
|
||||||
if config.SELinuxOptions != nil {
|
|
||||||
pod.Spec = api.PodSpec{
|
|
||||||
Containers: []api.Container{
|
|
||||||
{
|
|
||||||
SecurityContext: &api.SecurityContext{
|
|
||||||
SELinuxOptions: config.SELinuxOptions,
|
|
||||||
},
|
|
||||||
VolumeMounts: []api.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: volumeName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.idempotent {
|
if config.idempotent {
|
||||||
physicalMounter.MountPoints = []mount.MountPoint{
|
physicalMounter.MountPoints = []mount.MountPoint{
|
||||||
{
|
{
|
||||||
@ -258,7 +209,7 @@ func TestPluginBackCompat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(basePath)
|
defer os.RemoveAll(basePath)
|
||||||
|
|
||||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", basePath, "" /* rootContext */)
|
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", basePath)
|
||||||
|
|
||||||
spec := &api.Volume{
|
spec := &api.Volume{
|
||||||
Name: "vol1",
|
Name: "vol1",
|
||||||
@ -287,7 +238,7 @@ func TestMetrics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", tmpDir, "" /* rootContext */)
|
plug := makePluginUnderTest(t, "kubernetes.io/empty-dir", tmpDir)
|
||||||
|
|
||||||
spec := &api.Volume{
|
spec := &api.Volume{
|
||||||
Name: "vol1",
|
Name: "vol1",
|
||||||
|
@ -30,7 +30,3 @@ type realMountDetector struct {
|
|||||||
func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
|
func (m *realMountDetector) GetMountMedium(path string) (storageMedium, bool, error) {
|
||||||
return mediumUnknown, false, nil
|
return mediumUnknown, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selinuxEnabled() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user