Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
c8a17837
Commit
c8a17837
authored
Oct 28, 2015
by
k8s-merge-robot
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #15323 from swagiaal/pod-volume-selinux
Auto commit by PR queue bot
parents
0f99c59d
1d352a16
Hide whitespace changes
Inline
Side-by-side
Showing
30 changed files
with
344 additions
and
76 deletions
+344
-76
runtime.go
pkg/kubelet/container/runtime.go
+12
-1
manager.go
pkg/kubelet/dockertools/manager.go
+20
-3
kubelet.go
pkg/kubelet/kubelet.go
+68
-4
kubelet_test.go
pkg/kubelet/kubelet_test.go
+27
-3
rkt.go
pkg/kubelet/rkt/rkt.go
+1
-1
root_context_linux.go
pkg/kubelet/root_context_linux.go
+1
-1
volumes.go
pkg/kubelet/volumes.go
+1
-1
doc.go
pkg/util/selinux/doc.go
+18
-0
selinux.go
pkg/util/selinux/selinux.go
+3
-3
selinux_linux.go
pkg/util/selinux/selinux_linux.go
+1
-1
selinux_unsupported.go
pkg/util/selinux/selinux_unsupported.go
+1
-1
aws_ebs.go
pkg/volume/aws_ebs/aws_ebs.go
+4
-0
cephfs.go
pkg/volume/cephfs/cephfs.go
+4
-0
cinder.go
pkg/volume/cinder/cinder.go
+4
-0
downwardapi.go
pkg/volume/downwardapi/downwardapi.go
+4
-0
empty_dir.go
pkg/volume/empty_dir/empty_dir.go
+9
-13
empty_dir_test.go
pkg/volume/empty_dir/empty_dir_test.go
+1
-39
fc.go
pkg/volume/fc/fc.go
+4
-0
plugin.go
pkg/volume/flocker/plugin.go
+4
-0
gce_pd.go
pkg/volume/gce_pd/gce_pd.go
+4
-0
git_repo.go
pkg/volume/git_repo/git_repo.go
+4
-0
glusterfs.go
pkg/volume/glusterfs/glusterfs.go
+4
-0
host_path.go
pkg/volume/host_path/host_path.go
+4
-0
iscsi.go
pkg/volume/iscsi/iscsi.go
+4
-0
nfs.go
pkg/volume/nfs/nfs.go
+4
-0
rbd.go
pkg/volume/rbd/rbd.go
+4
-0
secret.go
pkg/volume/secret/secret.go
+4
-0
testing.go
pkg/volume/testing.go
+4
-0
volume.go
pkg/volume/volume.go
+4
-0
security_context.go
test/e2e/security_context.go
+117
-5
No files found.
pkg/kubelet/container/runtime.go
View file @
c8a17837
...
...
@@ -238,6 +238,8 @@ type Mount struct {
HostPath
string
// Whether the mount is read-only.
ReadOnly
bool
// Whether the mount needs SELinux relabeling
SELinuxRelabel
bool
}
type
PortMapping
struct
{
...
...
@@ -273,7 +275,16 @@ type RunContainerOptions struct {
CgroupParent
string
}
type
VolumeMap
map
[
string
]
volume
.
Volume
// VolumeInfo contains information about the volume.
type
VolumeInfo
struct
{
// Builder is the volume's builder
Builder
volume
.
Builder
// SELinuxLabeled indicates whether this volume has had the
// pod's SELinux label applied to it or not
SELinuxLabeled
bool
}
type
VolumeMap
map
[
string
]
VolumeInfo
type
Pods
[]
*
Pod
...
...
pkg/kubelet/dockertools/manager.go
View file @
c8a17837
...
...
@@ -606,13 +606,29 @@ func makeEnvList(envs []kubecontainer.EnvVar) (result []string) {
// can be understood by docker.
// Each element in the string is in the form of:
// '<HostPath>:<ContainerPath>', or
// '<HostPath>:<ContainerPath>:ro', if the path is read only.
func
makeMountBindings
(
mounts
[]
kubecontainer
.
Mount
)
(
result
[]
string
)
{
// '<HostPath>:<ContainerPath>:ro', if the path is read only, or
// '<HostPath>:<ContainerPath>:Z', if the volume requires SELinux
// relabeling and the pod provides an SELinux label
func
makeMountBindings
(
mounts
[]
kubecontainer
.
Mount
,
podHasSELinuxLabel
bool
)
(
result
[]
string
)
{
for
_
,
m
:=
range
mounts
{
bind
:=
fmt
.
Sprintf
(
"%s:%s"
,
m
.
HostPath
,
m
.
ContainerPath
)
if
m
.
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
.
SELinuxRelabel
&&
podHasSELinuxLabel
{
if
m
.
ReadOnly
{
bind
+=
",Z"
}
else
{
bind
+=
":Z"
}
}
result
=
append
(
result
,
bind
)
}
return
...
...
@@ -766,7 +782,8 @@ func (dm *DockerManager) runContainer(
dm
.
recorder
.
Eventf
(
ref
,
"Created"
,
"Created with docker id %v"
,
util
.
ShortenString
(
dockerContainer
.
ID
,
12
))
}
binds
:=
makeMountBindings
(
opts
.
Mounts
)
podHasSELinuxLabel
:=
pod
.
Spec
.
SecurityContext
!=
nil
&&
pod
.
Spec
.
SecurityContext
.
SELinuxOptions
!=
nil
binds
:=
makeMountBindings
(
opts
.
Mounts
,
podHasSELinuxLabel
)
// 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
...
...
pkg/kubelet/kubelet.go
View file @
c8a17837
...
...
@@ -29,6 +29,7 @@ import (
"net/http"
"os"
"path"
"path/filepath"
"sort"
"strings"
"sync"
...
...
@@ -62,6 +63,7 @@ import (
kubeletutil
"k8s.io/kubernetes/pkg/kubelet/util"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/securitycontext"
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/bandwidth"
...
...
@@ -73,6 +75,7 @@ import (
nodeutil
"k8s.io/kubernetes/pkg/util/node"
"k8s.io/kubernetes/pkg/util/oom"
"k8s.io/kubernetes/pkg/util/procfs"
"k8s.io/kubernetes/pkg/util/selinux"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/version"
"k8s.io/kubernetes/pkg/volume"
...
...
@@ -975,6 +978,47 @@ func (kl *Kubelet) syncNodeStatus() {
}
}
// 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
}
chconRunner
:=
selinux
.
NewChconRunner
()
// 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
_
,
volume
:=
range
volumes
{
if
volume
.
Builder
.
SupportsSELinux
()
&&
!
volume
.
Builder
.
IsReadOnly
()
{
// Relabel the volume and its content to match the 'Level' of the pod
err
:=
filepath
.
Walk
(
volume
.
Builder
.
GetPath
(),
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
error
{
if
err
!=
nil
{
return
err
}
return
chconRunner
.
SetContext
(
path
,
volumeContext
)
})
if
err
!=
nil
{
return
err
}
volume
.
SELinuxLabeled
=
true
}
}
return
nil
}
func
makeMounts
(
pod
*
api
.
Pod
,
podDir
string
,
container
*
api
.
Container
,
podVolumes
kubecontainer
.
VolumeMap
)
([]
kubecontainer
.
Mount
,
error
)
{
// Kubernetes only mounts on /etc/hosts if :
// - container does not use hostNetwork and
...
...
@@ -991,11 +1035,21 @@ func makeMounts(pod *api.Pod, podDir string, container *api.Container, podVolume
glog
.
Warningf
(
"Mount cannot be satisified for container %q, because the volume is missing: %q"
,
container
.
Name
,
mount
)
continue
}
relabelVolume
:=
false
// If the volume supports SELinux and it has not been
// relabeled already and it is not a read-only volume,
// relabel it and mark it as labeled
if
vol
.
Builder
.
SupportsSELinux
()
&&
!
vol
.
SELinuxLabeled
&&
!
vol
.
Builder
.
IsReadOnly
()
{
vol
.
SELinuxLabeled
=
true
relabelVolume
=
true
}
mounts
=
append
(
mounts
,
kubecontainer
.
Mount
{
Name
:
mount
.
Name
,
ContainerPath
:
mount
.
MountPath
,
HostPath
:
vol
.
GetPath
(),
ReadOnly
:
mount
.
ReadOnly
,
Name
:
mount
.
Name
,
ContainerPath
:
mount
.
MountPath
,
HostPath
:
vol
.
Builder
.
GetPath
(),
ReadOnly
:
mount
.
ReadOnly
,
SELinuxRelabel
:
relabelVolume
,
})
}
if
mountEtcHostsFile
{
...
...
@@ -1080,6 +1134,16 @@ func (kl *Kubelet) GenerateRunContainerOptions(pod *api.Pod, container *api.Cont
}
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
,
vol
)
if
err
!=
nil
{
return
nil
,
err
}
}
opts
.
Mounts
,
err
=
makeMounts
(
pod
,
kl
.
getPodDir
(
pod
.
UID
),
container
,
vol
)
if
err
!=
nil
{
return
nil
,
err
...
...
pkg/kubelet/kubelet_test.go
View file @
c8a17837
...
...
@@ -510,6 +510,26 @@ func (f *stubVolume) GetPath() string {
return
f
.
path
}
func
(
f
*
stubVolume
)
IsReadOnly
()
bool
{
return
false
}
func
(
f
*
stubVolume
)
SetUp
()
error
{
return
nil
}
func
(
f
*
stubVolume
)
SetUpAt
(
dir
string
)
error
{
return
nil
}
func
(
f
*
stubVolume
)
SupportsSELinux
()
bool
{
return
false
}
func
(
f
*
stubVolume
)
SupportsOwnershipManagement
()
bool
{
return
false
}
func
TestMakeVolumeMounts
(
t
*
testing
.
T
)
{
container
:=
api
.
Container
{
VolumeMounts
:
[]
api
.
VolumeMount
{
...
...
@@ -537,9 +557,9 @@ func TestMakeVolumeMounts(t *testing.T) {
}
podVolumes
:=
kubecontainer
.
VolumeMap
{
"disk"
:
&
stubVolume
{
"/mnt/disk"
},
"disk4"
:
&
stubVolume
{
"/mnt/host"
},
"disk5"
:
&
stubVolume
{
"/var/lib/kubelet/podID/volumes/empty/disk5"
},
"disk"
:
kubecontainer
.
VolumeInfo
{
Builder
:
&
stubVolume
{
"/mnt/disk"
}
},
"disk4"
:
kubecontainer
.
VolumeInfo
{
Builder
:
&
stubVolume
{
"/mnt/host"
}
},
"disk5"
:
kubecontainer
.
VolumeInfo
{
Builder
:
&
stubVolume
{
"/var/lib/kubelet/podID/volumes/empty/disk5"
}
},
}
pod
:=
api
.
Pod
{
...
...
@@ -558,24 +578,28 @@ func TestMakeVolumeMounts(t *testing.T) {
"/etc/hosts"
,
"/mnt/disk"
,
false
,
false
,
},
{
"disk"
,
"/mnt/path3"
,
"/mnt/disk"
,
true
,
false
,
},
{
"disk4"
,
"/mnt/path4"
,
"/mnt/host"
,
false
,
false
,
},
{
"disk5"
,
"/mnt/path5"
,
"/var/lib/kubelet/podID/volumes/empty/disk5"
,
false
,
false
,
},
}
if
!
reflect
.
DeepEqual
(
mounts
,
expectedMounts
)
{
...
...
pkg/kubelet/rkt/rkt.go
View file @
c8a17837
...
...
@@ -488,7 +488,7 @@ func (r *Runtime) makePodManifest(pod *api.Pod, pullSecrets []api.Secret) (*appc
manifest
.
Volumes
=
append
(
manifest
.
Volumes
,
appctypes
.
Volume
{
Name
:
*
volName
,
Kind
:
"host"
,
Source
:
volume
.
GetPath
(),
Source
:
volume
.
Builder
.
GetPath
(),
})
}
...
...
pkg/kubelet/root_context_linux.go
View file @
c8a17837
...
...
@@ -22,7 +22,7 @@ import (
"github.com/docker/libcontainer/selinux"
)
// getRootContext gets the SELinux context of the kubelet rootDir
// getRoot
Dir
Context gets the SELinux context of the kubelet rootDir
// or returns an error.
func
(
kl
*
Kubelet
)
getRootDirContext
()
(
string
,
error
)
{
// If SELinux is not enabled, return an empty string
...
...
pkg/kubelet/volumes.go
View file @
c8a17837
...
...
@@ -146,7 +146,7 @@ func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (kubecontainer.VolumeMap,
return
nil
,
err
}
}
podVolumes
[
volSpec
.
Name
]
=
builder
podVolumes
[
volSpec
.
Name
]
=
kubecontainer
.
VolumeInfo
{
Builder
:
builder
}
}
return
podVolumes
,
nil
}
...
...
pkg/util/selinux/doc.go
0 → 100644
View file @
c8a17837
/*
Copyright 2015 The Kubernetes Authors All rights reserved.
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 selinux contains selinux utility functions.
package
selinux
pkg/
volume/empty_dir/chcon_runner
.go
→
pkg/
util/selinux/selinux
.go
View file @
c8a17837
...
...
@@ -14,14 +14,14 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
empty_dir
package
selinux
// chconRunner knows how to chcon a directory.
type
c
hconRunner
interface
{
type
C
hconRunner
interface
{
SetContext
(
dir
,
context
string
)
error
}
// newChconRunner returns a new chconRunner.
func
newChconRunner
()
c
hconRunner
{
func
NewChconRunner
()
C
hconRunner
{
return
&
realChconRunner
{}
}
pkg/
volume/empty_dir/chcon_runner
_linux.go
→
pkg/
util/selinux/selinux
_linux.go
View file @
c8a17837
...
...
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
empty_dir
package
selinux
import
(
"github.com/docker/libcontainer/selinux"
...
...
pkg/
volume/empty_dir/chcon_runner
_unsupported.go
→
pkg/
util/selinux/selinux
_unsupported.go
View file @
c8a17837
...
...
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package
empty_dir
package
selinux
type
realChconRunner
struct
{}
...
...
pkg/volume/aws_ebs/aws_ebs.go
View file @
c8a17837
...
...
@@ -250,6 +250,10 @@ func (b *awsElasticBlockStoreBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
awsElasticBlockStoreBuilder
)
SupportsSELinux
()
bool
{
return
true
}
func
makeGlobalPDPath
(
host
volume
.
VolumeHost
,
volumeID
string
)
string
{
// Clean up the URI to be more fs-friendly
name
:=
volumeID
...
...
pkg/volume/cephfs/cephfs.go
View file @
c8a17837
...
...
@@ -187,6 +187,10 @@ func (cephfsVolume *cephfsBuilder) IsReadOnly() bool {
return
cephfsVolume
.
readonly
}
func
(
cephfsVolume
*
cephfsBuilder
)
SupportsSELinux
()
bool
{
return
false
}
type
cephfsCleaner
struct
{
*
cephfs
}
...
...
pkg/volume/cinder/cinder.go
View file @
c8a17837
...
...
@@ -225,6 +225,10 @@ func (b *cinderVolumeBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
cinderVolumeBuilder
)
SupportsSELinux
()
bool
{
return
true
}
func
makeGlobalPDName
(
host
volume
.
VolumeHost
,
devName
string
)
string
{
return
path
.
Join
(
host
.
GetPluginDir
(
cinderVolumePluginName
),
"mounts"
,
devName
)
}
...
...
pkg/volume/downwardapi/downwardapi.go
View file @
c8a17837
...
...
@@ -157,6 +157,10 @@ func (d *downwardAPIVolume) IsReadOnly() bool {
return
true
}
func
(
d
*
downwardAPIVolume
)
SupportsSELinux
()
bool
{
return
true
}
// collectData collects requested downwardAPI in data map.
// Map's key is the requested name of file to dump
// Map's value is the (sorted) content of the field to be dumped in the file.
...
...
pkg/volume/empty_dir/empty_dir.go
View file @
c8a17837
...
...
@@ -70,10 +70,10 @@ func (plugin *emptyDirPlugin) CanSupport(spec *volume.Spec) bool {
}
func
(
plugin
*
emptyDirPlugin
)
NewBuilder
(
spec
*
volume
.
Spec
,
pod
*
api
.
Pod
,
opts
volume
.
VolumeOptions
)
(
volume
.
Builder
,
error
)
{
return
plugin
.
newBuilderInternal
(
spec
,
pod
,
plugin
.
host
.
GetMounter
(),
&
realMountDetector
{
plugin
.
host
.
GetMounter
()},
opts
,
newChconRunner
()
)
return
plugin
.
newBuilderInternal
(
spec
,
pod
,
plugin
.
host
.
GetMounter
(),
&
realMountDetector
{
plugin
.
host
.
GetMounter
()},
opts
)
}
func
(
plugin
*
emptyDirPlugin
)
newBuilderInternal
(
spec
*
volume
.
Spec
,
pod
*
api
.
Pod
,
mounter
mount
.
Interface
,
mountDetector
mountDetector
,
opts
volume
.
VolumeOptions
,
chconRunner
chconRunner
)
(
volume
.
Builder
,
error
)
{
func
(
plugin
*
emptyDirPlugin
)
newBuilderInternal
(
spec
*
volume
.
Spec
,
pod
*
api
.
Pod
,
mounter
mount
.
Interface
,
mountDetector
mountDetector
,
opts
volume
.
VolumeOptions
)
(
volume
.
Builder
,
error
)
{
medium
:=
api
.
StorageMediumDefault
if
spec
.
Volume
.
EmptyDir
!=
nil
{
// Support a non-specified source as EmptyDir.
medium
=
spec
.
Volume
.
EmptyDir
.
Medium
...
...
@@ -86,7 +86,6 @@ func (plugin *emptyDirPlugin) newBuilderInternal(spec *volume.Spec, pod *api.Pod
mountDetector
:
mountDetector
,
plugin
:
plugin
,
rootContext
:
opts
.
RootContext
,
chconRunner
:
chconRunner
,
},
nil
}
...
...
@@ -134,7 +133,6 @@ type emptyDir struct {
mountDetector
mountDetector
plugin
*
emptyDirPlugin
rootContext
string
chconRunner
chconRunner
}
func
(
_
*
emptyDir
)
SupportsOwnershipManagement
()
bool
{
...
...
@@ -175,7 +173,7 @@ func (ed *emptyDir) SetUpAt(dir string) error {
switch
ed
.
medium
{
case
api
.
StorageMediumDefault
:
err
=
ed
.
setupDir
(
dir
,
securityContext
)
err
=
ed
.
setupDir
(
dir
)
case
api
.
StorageMediumMemory
:
err
=
ed
.
setupTmpfs
(
dir
,
securityContext
)
default
:
...
...
@@ -193,13 +191,17 @@ func (ed *emptyDir) IsReadOnly() bool {
return
false
}
func
(
ed
*
emptyDir
)
SupportsSELinux
()
bool
{
return
true
}
// setupTmpfs creates a tmpfs mount at the specified directory with the
// specified SELinux context.
func
(
ed
*
emptyDir
)
setupTmpfs
(
dir
string
,
selinuxContext
string
)
error
{
if
ed
.
mounter
==
nil
{
return
fmt
.
Errorf
(
"memory storage requested, but mounter is nil"
)
}
if
err
:=
ed
.
setupDir
(
dir
,
selinuxContext
);
err
!=
nil
{
if
err
:=
ed
.
setupDir
(
dir
);
err
!=
nil
{
return
err
}
// Make SetUp idempotent.
...
...
@@ -228,7 +230,7 @@ func (ed *emptyDir) setupTmpfs(dir string, selinuxContext string) error {
// setupDir creates the directory with the specified SELinux context and
// the default permissions specified by the perm constant.
func
(
ed
*
emptyDir
)
setupDir
(
dir
,
selinuxContext
string
)
error
{
func
(
ed
*
emptyDir
)
setupDir
(
dir
string
)
error
{
// Create the directory if it doesn't already exist.
if
err
:=
os
.
MkdirAll
(
dir
,
perm
);
err
!=
nil
{
return
err
...
...
@@ -262,12 +264,6 @@ func (ed *emptyDir) setupDir(dir, selinuxContext string) error {
}
}
// Set the context on the directory, if appropriate
if
selinuxContext
!=
""
{
glog
.
V
(
3
)
.
Infof
(
"Setting SELinux context for %v to %v"
,
dir
,
selinuxContext
)
return
ed
.
chconRunner
.
SetContext
(
dir
,
selinuxContext
)
}
return
nil
}
...
...
pkg/volume/empty_dir/empty_dir_test.go
View file @
c8a17837
...
...
@@ -69,30 +69,10 @@ func (fake *fakeMountDetector) GetMountMedium(path string) (storageMedium, bool,
return
fake
.
medium
,
fake
.
isMount
,
nil
}
type
fakeChconRequest
struct
{
dir
string
context
string
}
type
fakeChconRunner
struct
{
requests
[]
fakeChconRequest
}
func
newFakeChconRunner
()
*
fakeChconRunner
{
return
&
fakeChconRunner
{}
}
func
(
f
*
fakeChconRunner
)
SetContext
(
dir
,
context
string
)
error
{
f
.
requests
=
append
(
f
.
requests
,
fakeChconRequest
{
dir
,
context
})
return
nil
}
func
TestPluginEmptyRootContext
(
t
*
testing
.
T
)
{
doTestPlugin
(
t
,
pluginTestConfig
{
medium
:
api
.
StorageMediumDefault
,
rootContext
:
""
,
expectedChcons
:
0
,
expectedSetupMounts
:
0
,
expectedTeardownMounts
:
0
})
}
...
...
@@ -106,7 +86,6 @@ func TestPluginRootContextSet(t *testing.T) {
medium
:
api
.
StorageMediumDefault
,
rootContext
:
"user:role:type:range"
,
expectedSELinuxContext
:
"user:role:type:range"
,
expectedChcons
:
1
,
expectedSetupMounts
:
0
,
expectedTeardownMounts
:
0
})
}
...
...
@@ -120,7 +99,6 @@ func TestPluginTmpfs(t *testing.T) {
medium
:
api
.
StorageMediumMemory
,
rootContext
:
"user:role:type:range"
,
expectedSELinuxContext
:
"user:role:type:range"
,
expectedChcons
:
1
,
expectedSetupMounts
:
1
,
shouldBeMountedBeforeTeardown
:
true
,
expectedTeardownMounts
:
1
})
...
...
@@ -132,7 +110,6 @@ type pluginTestConfig struct {
SELinuxOptions
*
api
.
SELinuxOptions
idempotent
bool
expectedSELinuxContext
string
expectedChcons
int
expectedSetupMounts
int
shouldBeMountedBeforeTeardown
bool
expectedTeardownMounts
int
...
...
@@ -160,7 +137,6 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) {
mounter
=
mount
.
FakeMounter
{}
mountDetector
=
fakeMountDetector
{}
pod
=
&
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
UID
:
types
.
UID
(
"poduid"
)}}
fakeChconRnr
=
&
fakeChconRunner
{}
)
// Set up the SELinux options on the pod
...
...
@@ -194,8 +170,7 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) {
pod
,
&
mounter
,
&
mountDetector
,
volume
.
VolumeOptions
{
RootContext
:
config
.
rootContext
},
fakeChconRnr
)
volume
.
VolumeOptions
{
RootContext
:
config
.
rootContext
})
if
err
!=
nil
{
t
.
Errorf
(
"Failed to make a new Builder: %v"
,
err
)
}
...
...
@@ -231,19 +206,6 @@ func doTestPlugin(t *testing.T, config pluginTestConfig) {
t
.
Errorf
(
"Volume directory was created unexpectedly"
)
}
// Check the number of chcons during setup
if
e
,
a
:=
config
.
expectedChcons
,
len
(
fakeChconRnr
.
requests
);
e
!=
a
{
t
.
Errorf
(
"Expected %v chcon calls, got %v"
,
e
,
a
)
}
if
config
.
expectedChcons
==
1
{
if
e
,
a
:=
config
.
expectedSELinuxContext
,
fakeChconRnr
.
requests
[
0
]
.
context
;
e
!=
a
{
t
.
Errorf
(
"Unexpected chcon context argument; expected: %v, got: %v"
,
e
,
a
)
}
if
e
,
a
:=
volPath
,
fakeChconRnr
.
requests
[
0
]
.
dir
;
e
!=
a
{
t
.
Errorf
(
"Unexpected chcon path argument: expected: %v, got: %v"
,
e
,
a
)
}
}
// Check the number of mounts performed during setup
if
e
,
a
:=
config
.
expectedSetupMounts
,
len
(
mounter
.
Log
);
e
!=
a
{
t
.
Errorf
(
"Expected %v mounter calls during setup, got %v"
,
e
,
a
)
...
...
pkg/volume/fc/fc.go
View file @
c8a17837
...
...
@@ -191,6 +191,10 @@ func (b *fcDiskBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
fcDiskBuilder
)
SupportsSELinux
()
bool
{
return
true
}
// Unmounts the bind mount, and detaches the disk only if the disk
// resource was the last reference to that disk on the kubelet.
func
(
c
*
fcDiskCleaner
)
TearDown
()
error
{
...
...
pkg/volume/flocker/plugin.go
View file @
c8a17837
...
...
@@ -205,6 +205,10 @@ func (b flockerBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
flockerBuilder
)
SupportsSELinux
()
bool
{
return
false
}
// updateDatasetPrimary will update the primary in Flocker and wait for it to
// be ready. If it never gets to ready state it will timeout and error.
func
(
b
flockerBuilder
)
updateDatasetPrimary
(
datasetID
,
primaryUUID
string
)
error
{
...
...
pkg/volume/gce_pd/gce_pd.go
View file @
c8a17837
...
...
@@ -238,6 +238,10 @@ func (b *gcePersistentDiskBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
gcePersistentDiskBuilder
)
SupportsSELinux
()
bool
{
return
true
}
func
makeGlobalPDName
(
host
volume
.
VolumeHost
,
devName
string
)
string
{
return
path
.
Join
(
host
.
GetPluginDir
(
gcePersistentDiskPluginName
),
"mounts"
,
devName
)
}
...
...
pkg/volume/git_repo/git_repo.go
View file @
c8a17837
...
...
@@ -122,6 +122,10 @@ func (b *gitRepoVolumeBuilder) IsReadOnly() bool {
return
false
}
func
(
b
*
gitRepoVolumeBuilder
)
SupportsSELinux
()
bool
{
return
true
}
// This is the spec for the volume that this plugin wraps.
var
wrappedVolumeSpec
=
&
volume
.
Spec
{
Volume
:
&
api
.
Volume
{
VolumeSource
:
api
.
VolumeSource
{
EmptyDir
:
&
api
.
EmptyDirVolumeSource
{}}},
...
...
pkg/volume/glusterfs/glusterfs.go
View file @
c8a17837
...
...
@@ -189,6 +189,10 @@ func (b *glusterfsBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
glusterfsBuilder
)
SupportsSELinux
()
bool
{
return
false
}
func
(
glusterfsVolume
*
glusterfs
)
GetPath
()
string
{
name
:=
glusterfsPluginName
return
glusterfsVolume
.
plugin
.
host
.
GetPodVolumeDir
(
glusterfsVolume
.
pod
.
UID
,
util
.
EscapeQualifiedNameForDisk
(
name
),
glusterfsVolume
.
volName
)
...
...
pkg/volume/host_path/host_path.go
View file @
c8a17837
...
...
@@ -185,6 +185,10 @@ func (b *hostPathBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
hostPathBuilder
)
SupportsSELinux
()
bool
{
return
false
}
func
(
b
*
hostPathBuilder
)
GetPath
()
string
{
return
b
.
path
}
...
...
pkg/volume/iscsi/iscsi.go
View file @
c8a17837
...
...
@@ -185,6 +185,10 @@ func (b *iscsiDiskBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
iscsiDiskBuilder
)
SupportsSELinux
()
bool
{
return
true
}
// Unmounts the bind mount, and detaches the disk only if the disk
// resource was the last reference to that disk on the kubelet.
func
(
c
*
iscsiDiskCleaner
)
TearDown
()
error
{
...
...
pkg/volume/nfs/nfs.go
View file @
c8a17837
...
...
@@ -226,6 +226,10 @@ func (b *nfsBuilder) IsReadOnly() bool {
return
b
.
readOnly
}
func
(
b
*
nfsBuilder
)
SupportsSELinux
()
bool
{
return
false
}
//
//func (c *nfsCleaner) GetPath() string {
// name := nfsPluginName
...
...
pkg/volume/rbd/rbd.go
View file @
c8a17837
...
...
@@ -219,6 +219,10 @@ func (b *rbd) IsReadOnly() bool {
return
b
.
ReadOnly
}
func
(
b
*
rbd
)
SupportsSELinux
()
bool
{
return
true
}
// Unmounts the bind mount, and detaches the disk only if the disk
// resource was the last reference to that disk on the kubelet.
func
(
c
*
rbdCleaner
)
TearDown
()
error
{
...
...
pkg/volume/secret/secret.go
View file @
c8a17837
...
...
@@ -176,6 +176,10 @@ func (sv *secretVolume) IsReadOnly() bool {
return
false
}
func
(
sv
*
secretVolume
)
SupportsSELinux
()
bool
{
return
true
}
func
totalSecretBytes
(
secret
*
api
.
Secret
)
int
{
totalSize
:=
0
for
_
,
bytes
:=
range
secret
.
Data
{
...
...
pkg/volume/testing.go
View file @
c8a17837
...
...
@@ -172,6 +172,10 @@ func (fv *FakeVolume) IsReadOnly() bool {
return
false
}
func
(
fv
*
FakeVolume
)
SupportsSELinux
()
bool
{
return
false
}
func
(
fv
*
FakeVolume
)
GetPath
()
string
{
return
path
.
Join
(
fv
.
Plugin
.
Host
.
GetPodVolumeDir
(
fv
.
PodUID
,
util
.
EscapeQualifiedNameForDisk
(
fv
.
Plugin
.
PluginName
),
fv
.
VolName
))
}
...
...
pkg/volume/volume.go
View file @
c8a17837
...
...
@@ -53,6 +53,10 @@ type Builder interface {
// 2. Set the setgid bit is set (new files created in the volume will be owned by FSGroup)
// 3. Logical OR the permission bits with rw-rw----
SupportsOwnershipManagement
()
bool
// SupportsSELinux reports whether the given builder supports
// SELinux and would like the kubelet to relabel the volume to
// match the pod to which it will be attached.
SupportsSELinux
()
bool
}
// Cleaner interface provides methods to cleanup/unmount the volumes.
...
...
test/e2e/security_context.go
View file @
c8a17837
...
...
@@ -29,9 +29,10 @@ import (
"k8s.io/kubernetes/pkg/util"
.
"github.com/onsi/ginkgo"
.
"github.com/onsi/gomega"
)
func
scTestPod
()
*
api
.
Pod
{
func
scTestPod
(
hostIPC
bool
,
hostPID
bool
)
*
api
.
Pod
{
podName
:=
"security-context-"
+
string
(
util
.
NewUUID
())
pod
:=
&
api
.
Pod
{
ObjectMeta
:
api
.
ObjectMeta
{
...
...
@@ -39,7 +40,10 @@ func scTestPod() *api.Pod {
Labels
:
map
[
string
]
string
{
"name"
:
podName
},
},
Spec
:
api
.
PodSpec
{
SecurityContext
:
&
api
.
PodSecurityContext
{},
SecurityContext
:
&
api
.
PodSecurityContext
{
HostIPC
:
hostIPC
,
HostPID
:
hostPID
,
},
Containers
:
[]
api
.
Container
{
{
Name
:
"test-container"
,
...
...
@@ -57,7 +61,7 @@ var _ = Describe("[Skipped] Security Context", func() {
framework
:=
NewFramework
(
"security-context"
)
It
(
"should support pod.Spec.SecurityContext.SupplementalGroups"
,
func
()
{
pod
:=
scTestPod
()
pod
:=
scTestPod
(
false
,
false
)
pod
.
Spec
.
Containers
[
0
]
.
Command
=
[]
string
{
"id"
,
"-G"
}
pod
.
Spec
.
SecurityContext
.
SupplementalGroups
=
[]
int64
{
1234
,
5678
}
groups
:=
[]
string
{
"1234"
,
"5678"
}
...
...
@@ -65,7 +69,7 @@ var _ = Describe("[Skipped] Security Context", func() {
})
It
(
"should support pod.Spec.SecurityContext.RunAsUser"
,
func
()
{
pod
:=
scTestPod
()
pod
:=
scTestPod
(
false
,
false
)
var
uid
int64
=
1001
pod
.
Spec
.
SecurityContext
.
RunAsUser
=
&
uid
pod
.
Spec
.
Containers
[
0
]
.
Command
=
[]
string
{
"sh"
,
"-c"
,
"id -u"
}
...
...
@@ -76,7 +80,7 @@ var _ = Describe("[Skipped] Security Context", func() {
})
It
(
"should support container.SecurityContext.RunAsUser"
,
func
()
{
pod
:=
scTestPod
()
pod
:=
scTestPod
(
false
,
false
)
var
uid
int64
=
1001
var
overrideUid
int64
=
1002
pod
.
Spec
.
SecurityContext
.
RunAsUser
=
&
uid
...
...
@@ -88,4 +92,112 @@ var _ = Describe("[Skipped] Security Context", func() {
fmt
.
Sprintf
(
"%v"
,
overrideUid
),
})
})
It
(
"should support volume SELinux relabeling"
,
func
()
{
testPodSELinuxLabeling
(
framework
,
false
,
false
)
})
It
(
"should support volume SELinux relabeling when using hostIPC"
,
func
()
{
testPodSELinuxLabeling
(
framework
,
true
,
false
)
})
It
(
"should support volume SELinux relabeling when using hostPID"
,
func
()
{
testPodSELinuxLabeling
(
framework
,
false
,
true
)
})
})
func
testPodSELinuxLabeling
(
framework
*
Framework
,
hostIPC
bool
,
hostPID
bool
)
{
// Write and read a file with an empty_dir volume
// with a pod with the MCS label s0:c0,c1
pod
:=
scTestPod
(
hostIPC
,
hostPID
)
volumeName
:=
"test-volume"
mountPath
:=
"/mounted_volume"
pod
.
Spec
.
Containers
[
0
]
.
VolumeMounts
=
[]
api
.
VolumeMount
{
{
Name
:
volumeName
,
MountPath
:
mountPath
,
},
}
pod
.
Spec
.
Volumes
=
[]
api
.
Volume
{
{
Name
:
volumeName
,
VolumeSource
:
api
.
VolumeSource
{
EmptyDir
:
&
api
.
EmptyDirVolumeSource
{
Medium
:
api
.
StorageMediumDefault
,
},
},
},
}
pod
.
Spec
.
SecurityContext
.
SELinuxOptions
=
&
api
.
SELinuxOptions
{
Level
:
"s0:c0,c1"
,
}
pod
.
Spec
.
Containers
[
0
]
.
Command
=
[]
string
{
"sleep"
,
"6000"
}
client
:=
framework
.
Client
.
Pods
(
framework
.
Namespace
.
Name
)
_
,
err
:=
client
.
Create
(
pod
)
expectNoError
(
err
,
"Error creating pod %v"
,
pod
)
defer
client
.
Delete
(
pod
.
Name
,
nil
)
expectNoError
(
waitForPodRunningInNamespace
(
framework
.
Client
,
pod
.
Name
,
framework
.
Namespace
.
Name
))
testContent
:=
"hello"
testFilePath
:=
mountPath
+
"/TEST"
err
=
framework
.
WriteFileViaContainer
(
pod
.
Name
,
pod
.
Spec
.
Containers
[
0
]
.
Name
,
testFilePath
,
testContent
)
Expect
(
err
)
.
To
(
BeNil
())
content
,
err
:=
framework
.
ReadFileViaContainer
(
pod
.
Name
,
pod
.
Spec
.
Containers
[
0
]
.
Name
,
testFilePath
)
Expect
(
err
)
.
To
(
BeNil
())
Expect
(
content
)
.
To
(
ContainSubstring
(
testContent
))
foundPod
,
err
:=
framework
.
Client
.
Pods
(
framework
.
Namespace
.
Name
)
.
Get
(
pod
.
Name
)
Expect
(
err
)
.
NotTo
(
HaveOccurred
())
// Confirm that the file can be accessed from a second
// pod using host_path with the same MCS label
volumeHostPath
:=
fmt
.
Sprintf
(
"/var/lib/kubelet/pods/%s/volumes/kubernetes.io~empty-dir/%s"
,
foundPod
.
UID
,
volumeName
)
By
(
"confirming a container with the same label can read the file"
)
pod
=
scTestPod
(
hostIPC
,
hostPID
)
pod
.
Spec
.
NodeName
=
foundPod
.
Spec
.
NodeName
volumeMounts
:=
[]
api
.
VolumeMount
{
{
Name
:
volumeName
,
MountPath
:
mountPath
,
},
}
volumes
:=
[]
api
.
Volume
{
{
Name
:
volumeName
,
VolumeSource
:
api
.
VolumeSource
{
HostPath
:
&
api
.
HostPathVolumeSource
{
Path
:
volumeHostPath
,
},
},
},
}
pod
.
Spec
.
Containers
[
0
]
.
VolumeMounts
=
volumeMounts
pod
.
Spec
.
Volumes
=
volumes
pod
.
Spec
.
Containers
[
0
]
.
Command
=
[]
string
{
"cat"
,
testFilePath
}
pod
.
Spec
.
SecurityContext
.
SELinuxOptions
=
&
api
.
SELinuxOptions
{
Level
:
"s0:c0,c1"
,
}
framework
.
TestContainerOutput
(
"Pod with same MCS label reading test file"
,
pod
,
0
,
[]
string
{
testContent
})
// Confirm that the same pod with a different MCS
// label cannot access the volume
pod
=
scTestPod
(
hostIPC
,
hostPID
)
pod
.
Spec
.
Volumes
=
volumes
pod
.
Spec
.
Containers
[
0
]
.
VolumeMounts
=
volumeMounts
pod
.
Spec
.
Containers
[
0
]
.
Command
=
[]
string
{
"sleep"
,
"6000"
}
pod
.
Spec
.
SecurityContext
.
SELinuxOptions
=
&
api
.
SELinuxOptions
{
Level
:
"s0:c2,c3"
,
}
_
,
err
=
client
.
Create
(
pod
)
expectNoError
(
err
,
"Error creating pod %v"
,
pod
)
defer
client
.
Delete
(
pod
.
Name
,
nil
)
err
=
framework
.
WaitForPodRunning
(
pod
.
Name
)
expectNoError
(
err
,
"Error waiting for pod to run %v"
,
pod
)
content
,
err
=
framework
.
ReadFileViaContainer
(
pod
.
Name
,
"test-container"
,
testFilePath
)
Expect
(
content
)
.
NotTo
(
ContainSubstring
(
testContent
))
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment