FSGroup implementation

pull/6/head
Paul Morie 2015-10-20 14:49:39 -04:00
parent f960b05fe1
commit 3cd12f5e05
48 changed files with 21626 additions and 20935 deletions

View File

@ -13188,18 +13188,11 @@
},
"v1.PodSecurityContext": {
"id": "v1.PodSecurityContext",
"description": "PodSecurityContext holds pod-level security attributes and common container settings.",
"description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
"properties": {
"supplementalGroups": {
"type": "array",
"items": {
"$ref": "integer"
},
"description": "SupplementalGroups can be used to specify a list of additional groups which the main container process will run as. This will be applied to all containers in the pod in addition to the primary group of the container."
},
"seLinuxOptions": {
"$ref": "v1.SELinuxOptions",
"description": "SELinuxOptions is the SELinux context to be applied to all containers If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container."
"description": "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container."
},
"runAsUser": {
"type": "integer",
@ -13209,6 +13202,18 @@
"runAsNonRoot": {
"type": "boolean",
"description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence."
},
"supplementalGroups": {
"type": "array",
"items": {
"$ref": "integer"
},
"description": "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container."
},
"fsGroup": {
"type": "integer",
"format": "int64",
"description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw "
}
}
},

View File

@ -3836,18 +3836,11 @@
},
"v1.PodSecurityContext": {
"id": "v1.PodSecurityContext",
"description": "PodSecurityContext holds pod-level security attributes and common container settings.",
"description": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
"properties": {
"supplementalGroups": {
"type": "array",
"items": {
"$ref": "integer"
},
"description": "SupplementalGroups can be used to specify a list of additional groups which the main container process will run as. This will be applied to all containers in the pod in addition to the primary group of the container."
},
"seLinuxOptions": {
"$ref": "v1.SELinuxOptions",
"description": "SELinuxOptions is the SELinux context to be applied to all containers If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container."
"description": "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container."
},
"runAsUser": {
"type": "integer",
@ -3857,6 +3850,18 @@
"runAsNonRoot": {
"type": "boolean",
"description": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence."
},
"supplementalGroups": {
"type": "array",
"items": {
"$ref": "integer"
},
"description": "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container."
},
"fsGroup": {
"type": "integer",
"format": "int64",
"description": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw "
}
}
},

View File

@ -52,6 +52,8 @@ import (
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/kubernetes/pkg/master/ports"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/chmod"
"k8s.io/kubernetes/pkg/util/chown"
"k8s.io/kubernetes/pkg/util/io"
"k8s.io/kubernetes/pkg/util/mount"
nodeutil "k8s.io/kubernetes/pkg/util/node"
@ -320,6 +322,9 @@ func (s *KubeletServer) UnsecuredKubeletConfig() (*KubeletConfig, error) {
writer = &io.NsenterWriter{}
}
chmodRunner := chmod.New()
chownRunner := chown.New()
tlsOptions, err := s.InitializeTLS()
if err != nil {
return nil, err
@ -393,6 +398,8 @@ func (s *KubeletServer) UnsecuredKubeletConfig() (*KubeletConfig, error) {
MaxPods: s.MaxPods,
MinimumGCAge: s.MinimumGCAge,
Mounter: mounter,
ChownRunner: chownRunner,
ChmodRunner: chmodRunner,
NetworkPluginName: s.NetworkPluginName,
NetworkPlugins: ProbeNetworkPlugins(s.NetworkPluginDir),
NodeStatusUpdateFrequency: s.NodeStatusUpdateFrequency,
@ -661,6 +668,8 @@ func SimpleKubelet(client *client.Client,
MaxPods: maxPods,
MinimumGCAge: minimumGCAge,
Mounter: mount.New(),
ChownRunner: chown.New(),
ChmodRunner: chmod.New(),
NodeStatusUpdateFrequency: nodeStatusUpdateFrequency,
OOMAdjuster: oom.NewFakeOOMAdjuster(),
OSInterface: osInterface,
@ -843,6 +852,8 @@ type KubeletConfig struct {
MaxPods int
MinimumGCAge time.Duration
Mounter mount.Interface
ChownRunner chown.Interface
ChmodRunner chmod.Interface
NetworkPluginName string
NetworkPlugins []network.NetworkPlugin
NodeName string
@ -938,6 +949,8 @@ func CreateAndInitKubelet(kc *KubeletConfig) (k KubeletBootstrap, pc *config.Pod
kc.RktStage1Image,
kc.Mounter,
kc.Writer,
kc.ChownRunner,
kc.ChmodRunner,
kc.DockerDaemonContainer,
kc.SystemContainer,
kc.ConfigureCBR0,

View File

@ -1864,7 +1864,7 @@ Both these may change in the future. Incoming requests are matched against the h
<div class="sect2">
<h3 id="_v1_podsecuritycontext">v1.PodSecurityContext</h3>
<div class="paragraph">
<p>PodSecurityContext holds pod-level security attributes and common container settings.</p>
<p>PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
@ -1885,15 +1885,8 @@ Both these may change in the future. Incoming requests are matched against the h
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">supplementalGroups</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">SupplementalGroups can be used to specify a list of additional groups which the main container process will run as. This will be applied to all containers in the pod in addition to the primary group of the container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#integer">[integer]</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">seLinuxOptions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">SELinuxOptions is the SELinux context to be applied to all containers If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_selinuxoptions">v1.SELinuxOptions</a></p></td>
<td class="tableblock halign-left valign-top"></td>
@ -1912,6 +1905,22 @@ Both these may change in the future. Incoming requests are matched against the h
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">supplementalGroups</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A list of groups applied to the first process run in each container, in addition to the container&#8217;s primary GID. If unspecified, no groups will be added to any container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#integer">[integer]</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fsGroup</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:<br>
<br>
1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR&#8217;d with rw-rw</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">integer (int64)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -4238,7 +4247,7 @@ Populated by the system when a graceful deletion is requested. Read-only. More i
</div>
<div id="footer">
<div id="footer-text">
Last updated 2015-10-22 10:21:28 UTC
Last updated 2015-10-22 20:40:01 UTC
</div>
</div>
</body>

View File

@ -4975,7 +4975,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
</div>
<div id="footer">
<div id="footer-text">
Last updated 2015-10-22 10:21:28 UTC
Last updated 2015-10-22 20:40:01 UTC
</div>
</div>
</body>

View File

@ -4846,7 +4846,7 @@ The resulting set of endpoints can be viewed as:<br>
<div class="sect2">
<h3 id="_v1_podsecuritycontext">v1.PodSecurityContext</h3>
<div class="paragraph">
<p>PodSecurityContext holds pod-level security attributes and common container settings.</p>
<p>PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.</p>
</div>
<table class="tableblock frame-all grid-all" style="width:100%; ">
<colgroup>
@ -4867,15 +4867,8 @@ The resulting set of endpoints can be viewed as:<br>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">supplementalGroups</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">SupplementalGroups can be used to specify a list of additional groups which the main container process will run as. This will be applied to all containers in the pod in addition to the primary group of the container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#integer">[integer]</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">seLinuxOptions</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">SELinuxOptions is the SELinux context to be applied to all containers If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_v1_selinuxoptions">v1.SELinuxOptions</a></p></td>
<td class="tableblock halign-left valign-top"></td>
@ -4894,6 +4887,22 @@ The resulting set of endpoints can be viewed as:<br>
<td class="tableblock halign-left valign-top"><p class="tableblock">boolean</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">supplementalGroups</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A list of groups applied to the first process run in each container, in addition to the container&#8217;s primary GID. If unspecified, no groups will be added to any container.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#integer">[integer]</a> array</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">fsGroup</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:<br>
<br>
1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR&#8217;d with rw-rw</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">false</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">integer (int64)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
@ -6857,7 +6866,7 @@ The resulting set of endpoints can be viewed as:<br>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2015-10-22 10:21:22 UTC
Last updated 2015-10-22 20:39:55 UTC
</div>
</div>
</body>

View File

@ -23144,7 +23144,7 @@ span.icon > [class^="icon-"], span.icon > [class*=" icon-"] { cursor: default; }
</div>
<div id="footer">
<div id="footer-text">
Last updated 2015-10-22 10:21:22 UTC
Last updated 2015-10-22 20:39:55 UTC
</div>
</div>
</body>

View File

@ -1486,14 +1486,6 @@ func deepCopy_api_PodSecurityContext(in PodSecurityContext, out *PodSecurityCont
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.SELinuxOptions != nil {
out.SELinuxOptions = new(SELinuxOptions)
if err := deepCopy_api_SELinuxOptions(*in.SELinuxOptions, out.SELinuxOptions, c); err != nil {
@ -1514,6 +1506,20 @@ func deepCopy_api_PodSecurityContext(in PodSecurityContext, out *PodSecurityCont
} else {
out.RunAsNonRoot = nil
}
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -998,8 +998,8 @@ type PodSpec struct {
}
// PodSecurityContext holds pod-level security attributes and common container settings.
// Some fields are also present in SecurityContext. Field values of SecurityContext take
// precedence over field values of PodSecurityContext.
// Some fields are also present in container.securityContext. Field values of
// container.securityContext take precedence over field values of PodSecurityContext.
type PodSecurityContext struct {
// Use the host's network namespace. If this option is set, the ports that will be
// used must be specified.
@ -1011,12 +1011,6 @@ type PodSecurityContext struct {
// Use the host's ipc namespace.
// Optional: Default to false.
HostIPC bool `json:"hostIPC,omitempty"`
// SupplementalGroups can be used to specify a list of
// additional groups which the main container process will run
// as. This will be applied to all containers in the pod in
// addition to the primary group of the container.
SupplementalGroups []int64 `json:"supplementalGroups,omitempty"`
// The SELinux context to be applied to all containers.
// If unspecified, the container runtime will allocate a random SELinux context for each
// container. May also be set in SecurityContext. If set in
@ -1036,6 +1030,20 @@ type PodSecurityContext struct {
// May also be set in SecurityContext. If set in both SecurityContext and
// PodSecurityContext, the value specified in SecurityContext takes precedence.
RunAsNonRoot *bool `json:"runAsNonRoot,omitempty"`
// A list of groups applied to the first process run in each container, in addition
// to the container's primary GID. If unspecified, no groups will be added to
// any container.
SupplementalGroups []int64 `json:"supplementalGroups,omitempty"`
// A special supplemental group that applies to all containers in a pod.
// Some volume types allow the Kubelet to change the ownership of that volume
// to be owned by the pod:
//
// 1. The owning GID will be the FSGroup
// 2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
// 3. The permission bits are OR'd with rw-rw----
//
// If unset, the Kubelet will not modify the ownership and permissions of any volume.
FSGroup *int64 `json:"fsGroup,omitempty"`
}
// PodStatus represents information about the status of a pod. Status may trail the actual

View File

@ -440,6 +440,12 @@ func convert_api_PodSecurityContext_To_v1_PodSecurityContext(in *api.PodSecurity
} else {
out.RunAsNonRoot = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}
@ -469,5 +475,11 @@ func convert_v1_PodSecurityContext_To_api_PodSecurityContext(in *PodSecurityCont
} else {
out.RunAsNonRoot = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}

View File

@ -1501,14 +1501,6 @@ func deepCopy_v1_PodProxyOptions(in PodProxyOptions, out *PodProxyOptions, c *co
}
func deepCopy_v1_PodSecurityContext(in PodSecurityContext, out *PodSecurityContext, c *conversion.Cloner) error {
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.SELinuxOptions != nil {
out.SELinuxOptions = new(SELinuxOptions)
if err := deepCopy_v1_SELinuxOptions(*in.SELinuxOptions, out.SELinuxOptions, c); err != nil {
@ -1529,6 +1521,20 @@ func deepCopy_v1_PodSecurityContext(in PodSecurityContext, out *PodSecurityConte
} else {
out.RunAsNonRoot = nil
}
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -1258,13 +1258,10 @@ type PodSpec struct {
}
// PodSecurityContext holds pod-level security attributes and common container settings.
// Some fields are also present in container.securityContext. Field values of
// container.securityContext take precedence over field values of PodSecurityContext.
type PodSecurityContext struct {
// SupplementalGroups can be used to specify a list of
// additional groups which the main container process will run
// as. This will be applied to all containers in the pod in
// addition to the primary group of the container.
SupplementalGroups []int64 `json:"supplementalGroups,omitempty"`
// SELinuxOptions is the SELinux context to be applied to all containers
// The SELinux context to be applied to all containers.
// If unspecified, the container runtime will allocate a random SELinux context for each
// container. May also be set in SecurityContext. If set in
// both SecurityContext and PodSecurityContext, the value specified in SecurityContext
@ -1283,6 +1280,20 @@ type PodSecurityContext struct {
// May also be set in SecurityContext. If set in both SecurityContext and
// PodSecurityContext, the value specified in SecurityContext takes precedence.
RunAsNonRoot *bool `json:"runAsNonRoot,omitempty"`
// A list of groups applied to the first process run in each container, in addition
// to the container's primary GID. If unspecified, no groups will be added to
// any container.
SupplementalGroups []int64 `json:"supplementalGroups,omitempty"`
// A special supplemental group that applies to all containers in a pod.
// Some volume types allow the Kubelet to change the ownership of that volume
// to be owned by the pod:
//
// 1. The owning GID will be the FSGroup
// 2. The setgid bit is set (new files created in the volume will be owned by FSGroup)
// 3. The permission bits are OR'd with rw-rw----
//
// If unset, the Kubelet will not modify the ownership and permissions of any volume.
FSGroup *int64 `json:"fsGroup,omitempty"`
}
// PodStatus represents information about the status of a pod. Status may trail the actual

View File

@ -975,11 +975,12 @@ func (PodProxyOptions) SwaggerDoc() map[string]string {
}
var map_PodSecurityContext = map[string]string{
"": "PodSecurityContext holds pod-level security attributes and common container settings.",
"supplementalGroups": "SupplementalGroups can be used to specify a list of additional groups which the main container process will run as. This will be applied to all containers in the pod in addition to the primary group of the container.",
"seLinuxOptions": "SELinuxOptions is the SELinux context to be applied to all containers If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.",
"": "PodSecurityContext holds pod-level security attributes and common container settings. Some fields are also present in container.securityContext. Field values of container.securityContext take precedence over field values of PodSecurityContext.",
"seLinuxOptions": "The SELinux context to be applied to all containers. If unspecified, the container runtime will allocate a random SELinux context for each container. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.",
"runAsUser": "The UID to run the entrypoint of the container process. Defaults to user specified in image metadata if unspecified. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence for that container.",
"runAsNonRoot": "Indicates that the container must run as a non-root user. If true, the Kubelet will validate the image at runtime to ensure that it does not run as UID 0 (root) and fail to start the container if it does. If unset or false, no such validation will be performed. May also be set in SecurityContext. If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence.",
"supplementalGroups": "A list of groups applied to the first process run in each container, in addition to the container's primary GID. If unspecified, no groups will be added to any container.",
"fsGroup": "A special supplemental group that applies to all containers in a pod. Some volume types allow the Kubelet to change the ownership of that volume to be owned by the pod:\n\n1. The owning GID will be the FSGroup 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) 3. The permission bits are OR'd with rw-rw ",
}
func (PodSecurityContext) SwaggerDoc() map[string]string {

View File

@ -464,14 +464,6 @@ func deepCopy_api_PodSecurityContext(in api.PodSecurityContext, out *api.PodSecu
out.HostNetwork = in.HostNetwork
out.HostPID = in.HostPID
out.HostIPC = in.HostIPC
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.SELinuxOptions != nil {
out.SELinuxOptions = new(api.SELinuxOptions)
if err := deepCopy_api_SELinuxOptions(*in.SELinuxOptions, out.SELinuxOptions, c); err != nil {
@ -492,6 +484,20 @@ func deepCopy_api_PodSecurityContext(in api.PodSecurityContext, out *api.PodSecu
} else {
out.RunAsNonRoot = nil
}
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}

View File

@ -353,6 +353,12 @@ func convert_api_PodSecurityContext_To_v1_PodSecurityContext(in *api.PodSecurity
} else {
out.RunAsNonRoot = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}
@ -382,5 +388,11 @@ func convert_v1_PodSecurityContext_To_api_PodSecurityContext(in *v1.PodSecurityC
} else {
out.RunAsNonRoot = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}

View File

@ -497,14 +497,6 @@ func deepCopy_v1_PersistentVolumeClaimVolumeSource(in v1.PersistentVolumeClaimVo
}
func deepCopy_v1_PodSecurityContext(in v1.PodSecurityContext, out *v1.PodSecurityContext, c *conversion.Cloner) error {
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.SELinuxOptions != nil {
out.SELinuxOptions = new(v1.SELinuxOptions)
if err := deepCopy_v1_SELinuxOptions(*in.SELinuxOptions, out.SELinuxOptions, c); err != nil {
@ -525,6 +517,20 @@ func deepCopy_v1_PodSecurityContext(in v1.PodSecurityContext, out *v1.PodSecurit
} else {
out.RunAsNonRoot = nil
}
if in.SupplementalGroups != nil {
out.SupplementalGroups = make([]int64, len(in.SupplementalGroups))
for i := range in.SupplementalGroups {
out.SupplementalGroups[i] = in.SupplementalGroups[i]
}
} else {
out.SupplementalGroups = nil
}
if in.FSGroup != nil {
out.FSGroup = new(int64)
*out.FSGroup = *in.FSGroup
} else {
out.FSGroup = nil
}
return nil
}

View File

@ -64,6 +64,8 @@ import (
"k8s.io/kubernetes/pkg/types"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/bandwidth"
"k8s.io/kubernetes/pkg/util/chmod"
"k8s.io/kubernetes/pkg/util/chown"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
kubeio "k8s.io/kubernetes/pkg/util/io"
"k8s.io/kubernetes/pkg/util/mount"
@ -174,6 +176,8 @@ func NewMainKubelet(
rktStage1Image string,
mounter mount.Interface,
writer kubeio.Writer,
chownRunner chown.Interface,
chmodRunner chmod.Interface,
dockerDaemonContainer string,
systemContainer string,
configureCBR0 bool,
@ -285,6 +289,8 @@ func NewMainKubelet(
oomWatcher: oomWatcher,
cgroupRoot: cgroupRoot,
mounter: mounter,
chmodRunner: chmodRunner,
chownRunner: chownRunner,
writer: writer,
configureCBR0: configureCBR0,
podCIDR: podCIDR,
@ -581,6 +587,10 @@ type Kubelet struct {
// Mounter to use for volumes.
mounter mount.Interface
// chown.Interface implementation to use
chownRunner chown.Interface
// chmod.Interface implementation to use
chmodRunner chmod.Interface
// Writer interface to use for volumes.
writer kubeio.Writer

View File

@ -114,6 +114,12 @@ func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (kubecontainer.VolumeMap,
podVolumes := make(kubecontainer.VolumeMap)
for i := range pod.Spec.Volumes {
volSpec := &pod.Spec.Volumes[i]
hasFSGroup := false
var fsGroup int64 = 0
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.FSGroup != nil {
hasFSGroup = true
fsGroup = *pod.Spec.SecurityContext.FSGroup
}
rootContext, err := kl.getRootDirContext()
if err != nil {
@ -134,6 +140,12 @@ func (kl *Kubelet) mountExternalVolumes(pod *api.Pod) (kubecontainer.VolumeMap,
if err != nil {
return nil, err
}
if hasFSGroup && builder.SupportsOwnershipManagement() && !builder.IsReadOnly() {
err := kl.manageVolumeOwnership(pod, internal, builder, fsGroup)
if err != nil {
return nil, err
}
}
podVolumes[volSpec.Name] = builder
}
return podVolumes, nil

View File

@ -0,0 +1,63 @@
// +build linux
/*
Copyright 2014 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 kubelet
import (
"os"
"path/filepath"
"syscall"
"github.com/golang/glog"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/volume"
)
// Bitmask to OR with current ownership of volumes that allow ownership management by the Kubelet
const managedOwnershipBitmask = os.FileMode(0660)
// manageVolumeOwnership modifies the given volume to be owned by fsGroup.
func (kl *Kubelet) manageVolumeOwnership(pod *api.Pod, volSpec *volume.Spec, builder volume.Builder, fsGroup int64) error {
return filepath.Walk(builder.GetPath(), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
stat, ok := info.Sys().(*syscall.Stat_t)
if !ok {
return nil
}
if stat == nil {
glog.Errorf("Got nil stat_t for path %v while managing ownership of volume %v for pod %s/%s", path, volSpec.Name, pod.Namespace, pod.Name)
return nil
}
err = kl.chownRunner.Chown(path, int(stat.Uid), int(fsGroup))
if err != nil {
glog.Errorf("Chown failed on %v: %v", path, err)
}
err = kl.chmodRunner.Chmod(path, info.Mode()|managedOwnershipBitmask|os.ModeSetgid)
if err != nil {
glog.Errorf("Chmod failed on %v: %v", path, err)
}
return nil
})
}

View File

@ -0,0 +1,28 @@
// +build !linux
/*
Copyright 2014 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 kubelet
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/volume"
)
func (_ *Kubelet) manageVolumeOwnership(pod *api.Pod, volSpec *volume.Spec, builder volume.Builder, fsGroup int64) error {
return nil
}

View File

@ -38,7 +38,7 @@ type SimpleSecurityContextProvider struct{}
// The security context provider can make changes to the Config with which
// the container is created.
func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, container *api.Container, config *docker.Config) {
effectiveSC := determineEffectiveSecurityContext(pod, container)
effectiveSC := DetermineEffectiveSecurityContext(pod, container)
if effectiveSC == nil {
return
}
@ -52,24 +52,28 @@ func (p SimpleSecurityContextProvider) ModifyContainerConfig(pod *api.Pod, conta
// security options, whether the container is privileged, volume binds, etc.
func (p SimpleSecurityContextProvider) ModifyHostConfig(pod *api.Pod, container *api.Container, hostConfig *docker.HostConfig) {
// Apply pod security context
if pod.Spec.SecurityContext != nil {
// We skip application of supplemental groups to the
if container.Name != leaky.PodInfraContainerName && pod.Spec.SecurityContext != nil {
// TODO: We skip application of supplemental groups to the
// infra container to work around a runc issue which
// requires containers to have the '/etc/group'. For
// more information see:
// https://github.com/opencontainers/runc/pull/313
// This can be removed once the fix makes it into the
// required version of docker.
if pod.Spec.SecurityContext.SupplementalGroups != nil && container.Name != leaky.PodInfraContainerName {
if pod.Spec.SecurityContext.SupplementalGroups != nil {
hostConfig.GroupAdd = make([]string, len(pod.Spec.SecurityContext.SupplementalGroups))
for i, group := range pod.Spec.SecurityContext.SupplementalGroups {
hostConfig.GroupAdd[i] = strconv.Itoa(int(group))
}
}
if pod.Spec.SecurityContext.FSGroup != nil {
hostConfig.GroupAdd = append(hostConfig.GroupAdd, strconv.Itoa(int(*pod.Spec.SecurityContext.FSGroup)))
}
}
// Apply effective security context for container
effectiveSC := determineEffectiveSecurityContext(pod, container)
effectiveSC := DetermineEffectiveSecurityContext(pod, container)
if effectiveSC == nil {
return
}
@ -116,7 +120,7 @@ func makeCapabilites(capAdd []api.Capability, capDrop []api.Capability) ([]strin
return addCaps, dropCaps
}
func determineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext {
func DetermineEffectiveSecurityContext(pod *api.Pod, container *api.Container) *api.SecurityContext {
effectiveSc := securityContextFromPodSecurityContext(pod)
containerSc := container.SecurityContext

View File

@ -179,19 +179,35 @@ func TestModifyHostConfigPodSecurityContext(t *testing.T) {
supplementalGroupsSC.SupplementalGroups = []int64{2222}
supplementalGroupHC := fullValidHostConfig()
supplementalGroupHC.GroupAdd = []string{"2222"}
fsGroupHC := fullValidHostConfig()
fsGroupHC.GroupAdd = []string{"1234"}
bothHC := fullValidHostConfig()
bothHC.GroupAdd = []string{"2222", "1234"}
fsGroup := int64(1234)
testCases := map[string]struct {
securityContext *api.PodSecurityContext
expected *docker.HostConfig
}{
"nil Security Context": {
"nil": {
securityContext: nil,
expected: fullValidHostConfig(),
},
"Security Context with SupplementalGroup": {
"SupplementalGroup": {
securityContext: supplementalGroupsSC,
expected: supplementalGroupHC,
},
"FSGroup": {
securityContext: &api.PodSecurityContext{FSGroup: &fsGroup},
expected: fsGroupHC,
},
"FSGroup + SupplementalGroups": {
securityContext: &api.PodSecurityContext{
SupplementalGroups: []int64{2222},
FSGroup: &fsGroup,
},
expected: bothHC,
},
}
provider := NewSimpleSecurityContextProvider()

39
pkg/util/chmod/chmod.go Normal file
View File

@ -0,0 +1,39 @@
/*
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 chmod
import (
"os"
)
// Interface is something that knows how to run the chmod system call.
// It is non-recursive.
type Interface interface {
// Chmod changes the mode of the given file, implementing the same
// semantics as os.Chmod.
Chmod(path string, filemode os.FileMode) error
}
func New() Interface {
return &chmodRunner{}
}
type chmodRunner struct{}
func (_ *chmodRunner) Chmod(path string, mode os.FileMode) error {
return os.Chmod(path, mode)
}

19
pkg/util/chmod/doc.go Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2014 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 chown provides an interface and implementations
// for things that run run the chmod system call.
package chmod

39
pkg/util/chown/chown.go Normal file
View File

@ -0,0 +1,39 @@
/*
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 chown
import (
"os"
)
// Interface is something that knows how to run the chown system call.
// It is non-recursive.
type Interface interface {
// Chown changes the owning UID and GID of a file, implementing
// the exact same semantics as os.Chown.
Chown(path string, uid, gid int) error
}
func New() Interface {
return &chownRunner{}
}
type chownRunner struct{}
func (_ *chownRunner) Chown(path string, uid, gid int) error {
return os.Chown(path, uid, gid)
}

18
pkg/util/chown/doc.go Normal file
View File

@ -0,0 +1,18 @@
/*
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 chown provides utilities to chown a path
package chown

View File

@ -177,6 +177,10 @@ type awsElasticBlockStoreBuilder struct {
var _ volume.Builder = &awsElasticBlockStoreBuilder{}
func (_ *awsElasticBlockStoreBuilder) SupportsOwnershipManagement() bool {
return true
}
// SetUp attaches the disk and bind mounts to the volume path.
func (b *awsElasticBlockStoreBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())

View File

@ -151,6 +151,10 @@ type cephfsBuilder struct {
var _ volume.Builder = &cephfsBuilder{}
func (_ *cephfsBuilder) SupportsOwnershipManagement() bool {
return false
}
// SetUp attaches the disk and bind mounts to the volume path.
func (cephfsVolume *cephfsBuilder) SetUp() error {
return cephfsVolume.SetUpAt(cephfsVolume.GetPath())

View File

@ -153,6 +153,10 @@ func detachDiskLogError(cd *cinderVolume) {
}
}
func (_ *cinderVolumeBuilder) SupportsOwnershipManagement() bool {
return true
}
func (b *cinderVolumeBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())
}

View File

@ -107,6 +107,10 @@ type downwardAPIVolumeBuilder struct {
// downwardAPIVolumeBuilder implements volume.Builder interface
var _ volume.Builder = &downwardAPIVolumeBuilder{}
func (_ *downwardAPIVolumeBuilder) SupportsOwnershipManagement() bool {
return false
}
// SetUp puts in place the volume plugin.
// This function is not idempotent by design. We want the data to be refreshed periodically.
// The internal sync interval of kubelet will drive the refresh of data.

View File

@ -137,6 +137,10 @@ type emptyDir struct {
chconRunner chconRunner
}
func (_ *emptyDir) SupportsOwnershipManagement() bool {
return true
}
// SetUp creates new directory.
func (ed *emptyDir) SetUp() error {
return ed.SetUpAt(ed.GetPath())

View File

@ -164,6 +164,10 @@ type fcDiskBuilder struct {
var _ volume.Builder = &fcDiskBuilder{}
func (_ *fcDiskBuilder) SupportsOwnershipManagement() bool {
return true
}
func (b *fcDiskBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())
}

View File

@ -113,6 +113,10 @@ type flockerBuilder struct {
readOnly bool
}
func (_ *flockerBuilder) SupportsOwnershipManagement() bool {
return false
}
func (b flockerBuilder) GetPath() string {
return b.flocker.path
}

View File

@ -165,6 +165,10 @@ type gcePersistentDiskBuilder struct {
var _ volume.Builder = &gcePersistentDiskBuilder{}
func (_ *gcePersistentDiskBuilder) SupportsOwnershipManagement() bool {
return true
}
// SetUp attaches the disk and bind mounts to the volume path.
func (b *gcePersistentDiskBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())

View File

@ -109,6 +109,10 @@ type gitRepoVolumeBuilder struct {
var _ volume.Builder = &gitRepoVolumeBuilder{}
func (_ *gitRepoVolumeBuilder) SupportsOwnershipManagement() bool {
return true
}
// SetUp creates new directory and clones a git repo.
func (b *gitRepoVolumeBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())

View File

@ -135,6 +135,10 @@ type glusterfsBuilder struct {
var _ volume.Builder = &glusterfsBuilder{}
func (_ *glusterfsBuilder) SupportsOwnershipManagement() bool {
return false
}
// SetUp attaches the disk and bind mounts to the volume path.
func (b *glusterfsBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())

View File

@ -167,6 +167,10 @@ type hostPathBuilder struct {
var _ volume.Builder = &hostPathBuilder{}
func (_ *hostPathBuilder) SupportsOwnershipManagement() bool {
return false
}
// SetUp does nothing.
func (b *hostPathBuilder) SetUp() error {
return nil

View File

@ -158,6 +158,10 @@ type iscsiDiskBuilder struct {
var _ volume.Builder = &iscsiDiskBuilder{}
func (_ *iscsiDiskBuilder) SupportsOwnershipManagement() bool {
return true
}
func (b *iscsiDiskBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())
}

View File

@ -169,6 +169,10 @@ type nfsBuilder struct {
var _ volume.Builder = &nfsBuilder{}
func (_ *nfsBuilder) SupportsOwnershipManagement() bool {
return false
}
// SetUp attaches the disk and bind mounts to the volume path.
func (b *nfsBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())

View File

@ -192,6 +192,10 @@ type rbdBuilder struct {
var _ volume.Builder = &rbdBuilder{}
func (_ *rbdBuilder) SupportsOwnershipManagement() bool {
return true
}
func (b *rbdBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())
}

View File

@ -97,6 +97,10 @@ type secretVolumeBuilder struct {
var _ volume.Builder = &secretVolumeBuilder{}
func (_ *secretVolumeBuilder) SupportsOwnershipManagement() bool {
return true
}
func (b *secretVolumeBuilder) SetUp() error {
return b.SetUpAt(b.GetPath())
}

View File

@ -156,6 +156,10 @@ type FakeVolume struct {
Plugin *FakeVolumePlugin
}
func (_ *FakeVolume) SupportsOwnershipManagement() bool {
return false
}
func (fv *FakeVolume) SetUp() error {
return fv.SetUpAt(fv.GetPath())
}

View File

@ -45,6 +45,14 @@ type Builder interface {
// IsReadOnly is a flag that gives the builder's ReadOnly attribute.
// All persistent volumes have a private readOnly flag in their builders.
IsReadOnly() bool
// SupportsOwnershipManagement returns whether this builder wants
// ownership management for the volume. If this method returns true,
// the Kubelet will:
//
// 1. Make the volume owned by group FSGroup
// 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
}
// Cleaner interface provides methods to cleanup/unmount the volumes.

View File

@ -69,6 +69,10 @@ func (p *plugin) Admit(a admission.Attributes) (err error) {
}
}
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.FSGroup != nil {
return apierrors.NewForbidden(a.GetResource(), pod.Name, fmt.Errorf("SecurityContext.FSGroup is forbidden"))
}
for _, v := range pod.Spec.Containers {
if v.SecurityContext != nil {
if v.SecurityContext.SELinuxOptions != nil {

View File

@ -101,6 +101,8 @@ func TestPodSecurityContextAdmission(t *testing.T) {
},
}
fsGroup := int64(1001)
tests := []struct {
securityContext api.PodSecurityContext
errorExpected bool
@ -115,6 +117,12 @@ func TestPodSecurityContextAdmission(t *testing.T) {
},
errorExpected: true,
},
{
securityContext: api.PodSecurityContext{
FSGroup: &fsGroup,
},
errorExpected: true,
},
}
for _, test := range tests {
pod.Spec.SecurityContext = &test.securityContext

View File

@ -37,6 +37,23 @@ var _ = Describe("EmptyDir volumes", func() {
f := NewFramework("emptydir")
// TODO: Enable security context everywhere and remove skip for FSGroup
It("new files should be created with FSGroup ownership when container is root [Conformance] [Skipped]", func() {
doTestSetgidFSGroup(f, testImageRootUid, api.StorageMediumMemory)
})
It("new files should be created with FSGroup ownership when container is non-root [Conformance] [Skipped]", func() {
doTestSetgidFSGroup(f, testImageNonRootUid, api.StorageMediumMemory)
})
It("volume on default medium should have the correct mode using FSGroup [Conformance] [Skipped]", func() {
doTestVolumeModeFSGroup(f, testImageRootUid, api.StorageMediumDefault)
})
It("volume on tmpfs should have the correct mode using FSGroup [Conformance] [Skipped]", func() {
doTestVolumeModeFSGroup(f, testImageRootUid, api.StorageMediumMemory)
})
It("volume on tmpfs should have the correct mode [Conformance]", func() {
doTestVolumeMode(f, testImageRootUid, api.StorageMediumMemory)
})
@ -99,6 +116,91 @@ const (
volumeName = "test-volume"
)
func doTestSetgidFSGroup(f *Framework, image string, medium api.StorageMedium) {
var (
volumePath = "/test-volume"
filePath = path.Join(volumePath, "test-file")
source = &api.EmptyDirVolumeSource{Medium: medium}
pod = testPodWithVolume(testImageRootUid, volumePath, source)
)
pod.Spec.Containers[0].Args = []string{
fmt.Sprintf("--fs_type=%v", volumePath),
fmt.Sprintf("--new_file_0660=%v", filePath),
fmt.Sprintf("--file_perm=%v", filePath),
fmt.Sprintf("--file_owner=%v", filePath),
}
pod.Spec.SecurityContext = &api.PodSecurityContext{}
fsGroup := int64(123)
pod.Spec.SecurityContext.FSGroup = &fsGroup
msg := fmt.Sprintf("emptydir 0644 on %v", formatMedium(medium))
out := []string{
"perms of file \"/test-volume/test-file\": -rw-rw----",
"content of file \"/test-volume/test-file\": mount-tester new file",
"owner GID of \"/test-volume/test-file\": 123",
}
if medium == api.StorageMediumMemory {
out = append(out, "mount type of \"/test-volume\": tmpfs")
}
f.TestContainerOutput(msg, pod, 0, out)
}
func doTestVolumeModeFSGroup(f *Framework, image string, medium api.StorageMedium) {
var (
volumePath = "/test-volume"
source = &api.EmptyDirVolumeSource{Medium: medium}
pod = testPodWithVolume(testImageRootUid, volumePath, source)
)
pod.Spec.Containers[0].Args = []string{
fmt.Sprintf("--fs_type=%v", volumePath),
fmt.Sprintf("--file_perm=%v", volumePath),
}
fsGroup := int64(1001)
pod.Spec.SecurityContext = &api.PodSecurityContext{FSGroup: &fsGroup}
msg := fmt.Sprintf("emptydir volume type on %v", formatMedium(medium))
out := []string{
"perms of file \"/test-volume\": -rwxrwxrwx",
}
if medium == api.StorageMediumMemory {
out = append(out, "mount type of \"/test-volume\": tmpfs")
}
f.TestContainerOutput(msg, pod, 0, out)
}
func doTest0644FSGroup(f *Framework, image string, medium api.StorageMedium) {
var (
volumePath = "/test-volume"
filePath = path.Join(volumePath, "test-file")
source = &api.EmptyDirVolumeSource{Medium: medium}
pod = testPodWithVolume(image, volumePath, source)
)
pod.Spec.Containers[0].Args = []string{
fmt.Sprintf("--fs_type=%v", volumePath),
fmt.Sprintf("--new_file_0644=%v", filePath),
fmt.Sprintf("--file_perm=%v", filePath),
}
pod.Spec.SecurityContext = &api.PodSecurityContext{}
fsGroup := int64(123)
pod.Spec.SecurityContext.FSGroup = &fsGroup
msg := fmt.Sprintf("emptydir 0644 on %v", formatMedium(medium))
out := []string{
"perms of file \"/test-volume/test-file\": -rw-r--r--",
"content of file \"/test-volume/test-file\": mount-tester new file",
}
if medium == api.StorageMediumMemory {
out = append(out, "mount type of \"/test-volume\": tmpfs")
}
f.TestContainerOutput(msg, pod, 0, out)
}
func doTestVolumeMode(f *Framework, image string, medium api.StorageMedium) {
var (
volumePath = "/test-volume"