mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 05:57:25 +00:00
Kubernetes API for Shared Process Namespace
This commit is contained in:
parent
2b530438f1
commit
2343600ccc
@ -244,6 +244,10 @@ func DropDisabledAlphaFields(podSpec *api.PodSpec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) && podSpec.SecurityContext != nil {
|
||||||
|
podSpec.SecurityContext.ShareProcessNamespace = nil
|
||||||
|
}
|
||||||
|
|
||||||
for i := range podSpec.Containers {
|
for i := range podSpec.Containers {
|
||||||
DropDisabledVolumeMountsAlphaFields(podSpec.Containers[i].VolumeMounts)
|
DropDisabledVolumeMountsAlphaFields(podSpec.Containers[i].VolumeMounts)
|
||||||
}
|
}
|
||||||
|
@ -2644,6 +2644,15 @@ type PodSecurityContext struct {
|
|||||||
// +k8s:conversion-gen=false
|
// +k8s:conversion-gen=false
|
||||||
// +optional
|
// +optional
|
||||||
HostIPC bool
|
HostIPC bool
|
||||||
|
// Share a single process namespace between all of the containers in a pod.
|
||||||
|
// When this is set containers will be able to view and signal processes from other containers
|
||||||
|
// in the same pod, and the first process in each container will not be assigned PID 1.
|
||||||
|
// HostPID and ShareProcessNamespace cannot both be set.
|
||||||
|
// Optional: Default to false.
|
||||||
|
// This field is alpha-level and is honored only by servers that enable the PodShareProcessNamespace feature.
|
||||||
|
// +k8s:conversion-gen=false
|
||||||
|
// +optional
|
||||||
|
ShareProcessNamespace *bool
|
||||||
// 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
|
// If unspecified, the container runtime will allocate a random SELinux context for each
|
||||||
// container. May also be set in SecurityContext. If set in
|
// container. May also be set in SecurityContext. If set in
|
||||||
|
@ -384,6 +384,7 @@ func Convert_core_PodSpec_To_v1_PodSpec(in *core.PodSpec, out *v1.PodSpec, s con
|
|||||||
out.HostPID = in.SecurityContext.HostPID
|
out.HostPID = in.SecurityContext.HostPID
|
||||||
out.HostNetwork = in.SecurityContext.HostNetwork
|
out.HostNetwork = in.SecurityContext.HostNetwork
|
||||||
out.HostIPC = in.SecurityContext.HostIPC
|
out.HostIPC = in.SecurityContext.HostIPC
|
||||||
|
out.ShareProcessNamespace = in.SecurityContext.ShareProcessNamespace
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -408,6 +409,7 @@ func Convert_v1_PodSpec_To_core_PodSpec(in *v1.PodSpec, out *core.PodSpec, s con
|
|||||||
out.SecurityContext.HostNetwork = in.HostNetwork
|
out.SecurityContext.HostNetwork = in.HostNetwork
|
||||||
out.SecurityContext.HostPID = in.HostPID
|
out.SecurityContext.HostPID = in.HostPID
|
||||||
out.SecurityContext.HostIPC = in.HostIPC
|
out.SecurityContext.HostIPC = in.HostIPC
|
||||||
|
out.SecurityContext.ShareProcessNamespace = in.ShareProcessNamespace
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -3264,6 +3264,13 @@ func ValidatePodSecurityContext(securityContext *core.PodSecurityContext, spec *
|
|||||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg))
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("supplementalGroups").Index(g), gid, msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if securityContext.ShareProcessNamespace != nil {
|
||||||
|
if !utilfeature.DefaultFeatureGate.Enabled(features.PodShareProcessNamespace) {
|
||||||
|
allErrs = append(allErrs, field.Forbidden(fldPath.Child("shareProcessNamespace"), "Process Namespace Sharing is disabled by PodShareProcessNamespace feature-gate"))
|
||||||
|
} else if securityContext.HostPID && *securityContext.ShareProcessNamespace {
|
||||||
|
allErrs = append(allErrs, field.Invalid(fldPath.Child("shareProcessNamespace"), *securityContext.ShareProcessNamespace, "ShareProcessNamespace and HostPID cannot both be enabled"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allErrs
|
return allErrs
|
||||||
|
@ -31,11 +31,13 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
|
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
_ "k8s.io/kubernetes/pkg/api/testapi"
|
_ "k8s.io/kubernetes/pkg/api/testapi"
|
||||||
"k8s.io/kubernetes/pkg/apis/core"
|
"k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/helper"
|
"k8s.io/kubernetes/pkg/apis/core/helper"
|
||||||
"k8s.io/kubernetes/pkg/capabilities"
|
"k8s.io/kubernetes/pkg/capabilities"
|
||||||
|
"k8s.io/kubernetes/pkg/features"
|
||||||
"k8s.io/kubernetes/pkg/security/apparmor"
|
"k8s.io/kubernetes/pkg/security/apparmor"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -5748,24 +5750,9 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
minGroupID := int64(0)
|
minGroupID := int64(0)
|
||||||
maxGroupID := int64(2147483647)
|
maxGroupID := int64(2147483647)
|
||||||
|
|
||||||
priorityEnabled := utilfeature.DefaultFeatureGate.Enabled("PodPriority")
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodPriority, true)()
|
||||||
defer func() {
|
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodShareProcessNamespace, true)()
|
||||||
var err error
|
|
||||||
// restoring the old value
|
|
||||||
if priorityEnabled {
|
|
||||||
err = utilfeature.DefaultFeatureGate.Set("PodPriority=true")
|
|
||||||
} else {
|
|
||||||
err = utilfeature.DefaultFeatureGate.Set("PodPriority=false")
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to restore feature gate for PodPriority: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
err := utilfeature.DefaultFeatureGate.Set("PodPriority=true")
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Failed to enable feature gate for PodPriority: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
successCases := []core.PodSpec{
|
successCases := []core.PodSpec{
|
||||||
{ // Populate basic fields, leave defaults for most.
|
{ // Populate basic fields, leave defaults for most.
|
||||||
Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}},
|
Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}},
|
||||||
@ -5890,6 +5877,15 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
DNSPolicy: core.DNSClusterFirst,
|
DNSPolicy: core.DNSClusterFirst,
|
||||||
PriorityClassName: "valid-name",
|
PriorityClassName: "valid-name",
|
||||||
},
|
},
|
||||||
|
{ // Populate ShareProcessNamespace
|
||||||
|
Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}},
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSClusterFirst,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
ShareProcessNamespace: &[]bool{true}[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i := range successCases {
|
for i := range successCases {
|
||||||
if errs := ValidatePodSpec(&successCases[i], field.NewPath("field")); len(errs) != 0 {
|
if errs := ValidatePodSpec(&successCases[i], field.NewPath("field")); len(errs) != 0 {
|
||||||
@ -6061,12 +6057,42 @@ func TestValidatePodSpec(t *testing.T) {
|
|||||||
DNSPolicy: core.DNSClusterFirst,
|
DNSPolicy: core.DNSClusterFirst,
|
||||||
PriorityClassName: "InvalidName",
|
PriorityClassName: "InvalidName",
|
||||||
},
|
},
|
||||||
|
"ShareProcessNamespace and HostPID both set": {
|
||||||
|
Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}},
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSClusterFirst,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
HostPID: true,
|
||||||
|
ShareProcessNamespace: &[]bool{true}[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for k, v := range failureCases {
|
for k, v := range failureCases {
|
||||||
if errs := ValidatePodSpec(&v, field.NewPath("field")); len(errs) == 0 {
|
if errs := ValidatePodSpec(&v, field.NewPath("field")); len(errs) == 0 {
|
||||||
t.Errorf("expected failure for %q", k)
|
t.Errorf("expected failure for %q", k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// original value will be restored by previous defer
|
||||||
|
utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodShareProcessNamespace, false)
|
||||||
|
|
||||||
|
featuregatedCases := map[string]core.PodSpec{
|
||||||
|
"set ShareProcessNamespace": {
|
||||||
|
Volumes: []core.Volume{{Name: "vol", VolumeSource: core.VolumeSource{EmptyDir: &core.EmptyDirVolumeSource{}}}},
|
||||||
|
Containers: []core.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
||||||
|
RestartPolicy: core.RestartPolicyAlways,
|
||||||
|
DNSPolicy: core.DNSClusterFirst,
|
||||||
|
SecurityContext: &core.PodSecurityContext{
|
||||||
|
ShareProcessNamespace: &[]bool{true}[0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for k, v := range featuregatedCases {
|
||||||
|
if errs := ValidatePodSpec(&v, field.NewPath("field")); len(errs) == 0 {
|
||||||
|
t.Errorf("expected failure due to gated feature: %q", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func extendPodSpecwithTolerations(in core.PodSpec, tolerations []core.Toleration) core.PodSpec {
|
func extendPodSpecwithTolerations(in core.PodSpec, tolerations []core.Toleration) core.PodSpec {
|
||||||
|
@ -2861,6 +2861,15 @@ type PodSpec struct {
|
|||||||
// +k8s:conversion-gen=false
|
// +k8s:conversion-gen=false
|
||||||
// +optional
|
// +optional
|
||||||
HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,13,opt,name=hostIPC"`
|
HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,13,opt,name=hostIPC"`
|
||||||
|
// Share a single process namespace between all of the containers in a pod.
|
||||||
|
// When this is set containers will be able to view and signal processes from other containers
|
||||||
|
// in the same pod, and the first process in each container will not be assigned PID 1.
|
||||||
|
// HostPID and ShareProcessNamespace cannot both be set.
|
||||||
|
// Optional: Default to false.
|
||||||
|
// This field is alpha-level and is honored only by servers that enable the PodShareProcessNamespace feature.
|
||||||
|
// +k8s:conversion-gen=false
|
||||||
|
// +optional
|
||||||
|
ShareProcessNamespace *bool `json:"shareProcessNamespace,omitempty" protobuf:"varint,27,opt,name=shareProcessNamespace"`
|
||||||
// SecurityContext holds pod-level security attributes and common container settings.
|
// SecurityContext holds pod-level security attributes and common container settings.
|
||||||
// Optional: Defaults to empty. See type description for default values of each field.
|
// Optional: Defaults to empty. See type description for default values of each field.
|
||||||
// +optional
|
// +optional
|
||||||
|
Loading…
Reference in New Issue
Block a user