Commit 1d3c7ca7 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #38348 from euank/doc-our-privilege

Automatic merge from submit-queue (batch tested with PRs 38727, 38726, 38347, 38348) Add 'privileged' to sandbox to indicate if any container might be privileged in it, document privileged Right now, the privileged flag is this magic thing which does "whatever Docker does". This documents it to make it a little less magic. In addition, due to how rkt uses `systemd-nspawn` as an outer layer of isolation in creating the sandbox, it's helpful to know beforehand whether the pod will be privileged so additional security options can be applied earlier / applied at all. I suspect the same indication will be useful for userns since userns should also occur at the pod layer, but it's possible that will be a separate/additional field. cc @lucab @jonboulle @yujuhong @feiskyer @kubernetes/sig-node ```release-note NONE ```
parents 63cf217b bcd939cb
......@@ -168,6 +168,12 @@ message LinuxSandboxSecurityContext {
// List of groups applied to the first process run in the sandbox, in
// addition to the sandbox's primary GID.
repeated int64 supplemental_groups = 5;
// Indicates whether the sandbox will be asked to run a privileged
// container. If a privileged container is to be executed within it, this
// MUST be true.
// This allows a sandbox to take additional security precautions if no
// privileged containers are expected to be run.
optional bool privileged = 6;
}
// LinuxPodSandboxConfig holds platform-specific configurations for Linux
......@@ -446,6 +452,22 @@ message LinuxContainerSecurityContext {
// Capabilities to add or drop.
optional Capability capabilities = 1;
// If set, run container in privileged mode.
// Privileged mode is incompatible with the following options. If
// privileged is set, the following features MAY have no effect:
// 1. capabilities
// 2. selinux_options
// 4. seccomp
// 5. apparmor
//
// Privileged mode implies the following specific options are applied:
// 1. All capabilities are added.
// 2. Sensitive paths, such as kernel module paths within sysfs, are not masked.
// 3. Any sysfs and procfs mounts are mounted RW.
// 4. Apparmor confinement is not applied.
// 5. Seccomp restrictions are not applied.
// 6. The device cgroup does not restrict access to any devices.
// 7. All devices from the host's /dev are available within the container.
// 8. SELinux restrictions are not applied (e.g. label=disabled).
optional bool privileged = 2;
// Configurations for the container's namespaces.
// Only used if the container uses namespace for isolation.
......
......@@ -261,3 +261,15 @@ func GetContainerSpec(pod *v1.Pod, containerName string) *v1.Container {
}
return nil
}
// HasPrivilegedContainer returns true if any of the containers in the pod are privileged.
func HasPrivilegedContainer(pod *v1.Pod) bool {
for _, c := range pod.Spec.Containers {
if c.SecurityContext != nil &&
c.SecurityContext.Privileged != nil &&
*c.SecurityContext.Privileged {
return true
}
}
return false
}
......@@ -211,3 +211,44 @@ func TestShouldContainerBeRestarted(t *testing.T) {
}
}
}
func TestHasPrivilegedContainer(t *testing.T) {
newBoolPtr := func(b bool) *bool {
return &b
}
tests := map[string]struct {
securityContext *v1.SecurityContext
expected bool
}{
"nil security context": {
securityContext: nil,
expected: false,
},
"nil privileged": {
securityContext: &v1.SecurityContext{},
expected: false,
},
"false privileged": {
securityContext: &v1.SecurityContext{Privileged: newBoolPtr(false)},
expected: false,
},
"true privileged": {
securityContext: &v1.SecurityContext{Privileged: newBoolPtr(true)},
expected: true,
},
}
for k, v := range tests {
pod := &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{SecurityContext: v.securityContext},
},
},
}
actual := HasPrivilegedContainer(pod)
if actual != v.expected {
t.Errorf("%s expected %t but got %t", k, v.expected, actual)
}
}
}
......@@ -1436,25 +1436,13 @@ func (kl *Kubelet) cleanupOrphanedPodCgroups(
// or it will not have the correct capabilities in the namespace. This means that host user namespace
// is enabled per pod, not per container.
func (kl *Kubelet) enableHostUserNamespace(pod *v1.Pod) bool {
if hasPrivilegedContainer(pod) || hasHostNamespace(pod) ||
if kubecontainer.HasPrivilegedContainer(pod) || hasHostNamespace(pod) ||
hasHostVolume(pod) || hasNonNamespacedCapability(pod) || kl.hasHostMountPVC(pod) {
return true
}
return false
}
// hasPrivilegedContainer returns true if any of the containers in the pod are privileged.
func hasPrivilegedContainer(pod *v1.Pod) bool {
for _, c := range pod.Spec.Containers {
if c.SecurityContext != nil &&
c.SecurityContext.Privileged != nil &&
*c.SecurityContext.Privileged {
return true
}
}
return false
}
// hasNonNamespacedCapability returns true if MKNOD, SYS_TIME, or SYS_MODULE is requested for any container.
func hasNonNamespacedCapability(pod *v1.Pod) bool {
for _, c := range pod.Spec.Containers {
......
......@@ -1266,47 +1266,6 @@ func TestMakeDevices(t *testing.T) {
}
}
func TestHasPrivilegedContainer(t *testing.T) {
newBoolPtr := func(b bool) *bool {
return &b
}
tests := map[string]struct {
securityContext *v1.SecurityContext
expected bool
}{
"nil sc": {
securityContext: nil,
expected: false,
},
"nil privleged": {
securityContext: &v1.SecurityContext{},
expected: false,
},
"false privleged": {
securityContext: &v1.SecurityContext{Privileged: newBoolPtr(false)},
expected: false,
},
"true privleged": {
securityContext: &v1.SecurityContext{Privileged: newBoolPtr(true)},
expected: true,
},
}
for k, v := range tests {
pod := &v1.Pod{
Spec: v1.PodSpec{
Containers: []v1.Container{
{SecurityContext: v.securityContext},
},
},
}
actual := hasPrivilegedContainer(pod)
if actual != v.expected {
t.Errorf("%s expected %t but got %t", k, v.expected, actual)
}
}
}
func TestHasHostMountPVC(t *testing.T) {
tests := map[string]struct {
pvError error
......
......@@ -130,23 +130,21 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *v1.Pod, attemp
// generatePodSandboxLinuxConfig generates LinuxPodSandboxConfig from v1.Pod.
func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod, cgroupParent string) *runtimeapi.LinuxPodSandboxConfig {
if pod.Spec.SecurityContext == nil && cgroupParent == "" {
return nil
lc := &runtimeapi.LinuxPodSandboxConfig{
SecurityContext: &runtimeapi.LinuxSandboxSecurityContext{},
}
lc := &runtimeapi.LinuxPodSandboxConfig{}
if cgroupParent != "" {
lc.CgroupParent = &cgroupParent
}
if pod.Spec.SecurityContext != nil {
sc := pod.Spec.SecurityContext
lc.SecurityContext = &runtimeapi.LinuxSandboxSecurityContext{
NamespaceOptions: &runtimeapi.NamespaceOption{
HostNetwork: &pod.Spec.HostNetwork,
HostIpc: &pod.Spec.HostIPC,
HostPid: &pod.Spec.HostPID,
},
RunAsUser: sc.RunAsUser,
lc.SecurityContext.RunAsUser = sc.RunAsUser
lc.SecurityContext.NamespaceOptions = &runtimeapi.NamespaceOption{
HostNetwork: &pod.Spec.HostNetwork,
HostIpc: &pod.Spec.HostIPC,
HostPid: &pod.Spec.HostPID,
}
if sc.FSGroup != nil {
......@@ -168,6 +166,11 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod, c
}
}
if kubecontainer.HasPrivilegedContainer(pod) {
privileged := true
lc.SecurityContext.Privileged = &privileged
}
return lc
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment