diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go index a140753fb61..9de322165ea 100644 --- a/pkg/apis/core/types.go +++ b/pkg/apis/core/types.go @@ -2976,6 +2976,7 @@ type PodSpec struct { // If the OS field is set to windows, following fields must be unset: // - spec.hostPID // - spec.hostIPC + // - spec.hostUsers // - spec.securityContext.seLinuxOptions // - spec.securityContext.seccompProfile // - spec.securityContext.fsGroup @@ -3078,6 +3079,18 @@ type PodSecurityContext struct { // +k8s:conversion-gen=false // +optional ShareProcessNamespace *bool + // Use the host's user namespace. + // Optional: Default to true. + // If set to true or not present, the pod will be run in the host user namespace, useful + // for when the pod needs a feature only available to the host user namespace, such as + // loading a kernel module with CAP_SYS_MODULE. + // When set to false, a new user namespace is created for the pod. Setting false is useful + // for mitigating container breakout vulnerabilities even allowing users to run their + // containers as root without actually having root privileges on the host. + // Note that this field cannot be set when spec.os.name is windows. + // +k8s:conversion-gen=false + // +optional + HostUsers *bool // 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 diff --git a/pkg/apis/core/v1/conversion.go b/pkg/apis/core/v1/conversion.go index d89ea26354b..7869f0389b9 100644 --- a/pkg/apis/core/v1/conversion.go +++ b/pkg/apis/core/v1/conversion.go @@ -303,6 +303,7 @@ func Convert_core_PodSpec_To_v1_PodSpec(in *core.PodSpec, out *v1.PodSpec, s con out.HostNetwork = in.SecurityContext.HostNetwork out.HostIPC = in.SecurityContext.HostIPC out.ShareProcessNamespace = in.SecurityContext.ShareProcessNamespace + out.HostUsers = in.SecurityContext.HostUsers } return nil @@ -358,6 +359,7 @@ func Convert_v1_PodSpec_To_core_PodSpec(in *v1.PodSpec, out *core.PodSpec, s con out.SecurityContext.HostPID = in.HostPID out.SecurityContext.HostIPC = in.HostIPC out.SecurityContext.ShareProcessNamespace = in.ShareProcessNamespace + out.SecurityContext.HostUsers = in.HostUsers return nil } diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index fd8a67b2313..f6a7e417fd9 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -3637,6 +3637,9 @@ func validateWindows(spec *core.PodSpec, fldPath *field.Path) field.ErrorList { if securityContext.SELinuxOptions != nil { allErrs = append(allErrs, field.Forbidden(fldPath.Child("securityContext").Child("seLinuxOptions"), "cannot be set for a windows pod")) } + if securityContext.HostUsers != nil { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostUsers"), "cannot be set for a windows pod")) + } if securityContext.HostPID { allErrs = append(allErrs, field.Forbidden(fldPath.Child("hostPID"), "cannot be set for a windows pod")) } diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index f643bd80954..a98e35d706c 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -3289,6 +3289,7 @@ type PodSpec struct { // If the OS field is set to windows, following fields must be unset: // - spec.hostPID // - spec.hostIPC + // - spec.hostUsers // - spec.securityContext.seLinuxOptions // - spec.securityContext.seccompProfile // - spec.securityContext.fsGroup @@ -3309,6 +3310,18 @@ type PodSpec struct { // - spec.containers[*].securityContext.runAsGroup // +optional OS *PodOS `json:"os,omitempty" protobuf:"bytes,36,opt,name=os"` + // Use the host's user namespace. + // Optional: Default to true. + // If set to true or not present, the pod will be run in the host user namespace, useful + // for when the pod needs a feature only available to the host user namespace, such as + // loading a kernel module with CAP_SYS_MODULE. + // When set to false, a new userns is created for the pod. Setting false is useful for + // mitigating container breakout vulnerabilities even allowing users to run their + // containers as root without actually having root privileges on the host. + // This field is alpha-level and is only honored by servers that enable the UserNamespacesSupport feature. + // +k8s:conversion-gen=false + // +optional + HostUsers *bool `json:"hostUsers,omitempty" protobuf:"bytes,37,opt,name=hostUsers"` } // OSName is the set of OS'es that can be used in OS. diff --git a/staging/src/k8s.io/client-go/applyconfigurations/core/v1/podspec.go b/staging/src/k8s.io/client-go/applyconfigurations/core/v1/podspec.go index 015859e9a38..d3d3e028445 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/core/v1/podspec.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/core/v1/podspec.go @@ -41,6 +41,7 @@ type PodSpecApplyConfiguration struct { HostNetwork *bool `json:"hostNetwork,omitempty"` HostPID *bool `json:"hostPID,omitempty"` HostIPC *bool `json:"hostIPC,omitempty"` + HostUsers *bool `json:"hostUsers,omitempty"` ShareProcessNamespace *bool `json:"shareProcessNamespace,omitempty"` SecurityContext *PodSecurityContextApplyConfiguration `json:"securityContext,omitempty"` ImagePullSecrets []LocalObjectReferenceApplyConfiguration `json:"imagePullSecrets,omitempty"` @@ -207,6 +208,14 @@ func (b *PodSpecApplyConfiguration) WithHostNetwork(value bool) *PodSpecApplyCon return b } +// WithHostUsers sets the HostUsers field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the HostUsers field is set to the value of the last call. +func (b *PodSpecApplyConfiguration) WithHostUsers(value *bool) *PodSpecApplyConfiguration { + b.HostUsers = value + return b +} + // WithHostPID sets the HostPID field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the HostPID field is set to the value of the last call. diff --git a/staging/src/k8s.io/pod-security-admission/policy/check_hostNamespaces.go b/staging/src/k8s.io/pod-security-admission/policy/check_hostNamespaces.go index a11e59f9c72..9092b64e92a 100644 --- a/staging/src/k8s.io/pod-security-admission/policy/check_hostNamespaces.go +++ b/staging/src/k8s.io/pod-security-admission/policy/check_hostNamespaces.go @@ -25,7 +25,7 @@ import ( ) /* -Sharing the host namespaces must be disallowed. +Sharing the host network, PID, and IPC namespaces must be disallowed. **Restricted Fields:** diff --git a/test/e2e/framework/pod/wait_test.go b/test/e2e/framework/pod/wait_test.go index 8c46f0fd8ac..5939fba6ab5 100644 --- a/test/e2e/framework/pod/wait_test.go +++ b/test/e2e/framework/pod/wait_test.go @@ -183,6 +183,7 @@ INFO: Unexpected error: wait for pod pending-pod running: TopologySpreadConstraints: nil, SetHostnameAsFQDN: nil, OS: nil, + HostUsers: nil, }, Status: { Phase: "",