diff --git a/cmd/kubelet/app/options/options.go b/cmd/kubelet/app/options/options.go index bf5ef3ad17d..cbb36fce0e5 100644 --- a/cmd/kubelet/app/options/options.go +++ b/cmd/kubelet/app/options/options.go @@ -387,7 +387,7 @@ func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) { // EXPERIMENTAL FLAGS fs.StringVar(&f.ExperimentalMounterPath, "experimental-mounter-path", f.ExperimentalMounterPath, "[Experimental] Path of mounter binary. Leave empty to use the default mount.") - fs.StringSliceVar(&f.AllowedUnsafeSysctls, "experimental-allowed-unsafe-sysctls", f.AllowedUnsafeSysctls, "Comma-separated whitelist of unsafe sysctls or unsafe sysctl patterns (ending in *). Use these at your own risk.") + fs.StringSliceVar(&f.AllowedUnsafeSysctls, "experimental-allowed-unsafe-sysctls", f.AllowedUnsafeSysctls, "Comma-separated whitelist of unsafe sysctls or unsafe sysctl patterns (ending in *). Use these at your own risk. Presently, you must also enable the Sysctls feature gate for this flag to take effect. Sysctls feature gate is enabled by default.") fs.BoolVar(&f.ExperimentalKernelMemcgNotification, "experimental-kernel-memcg-notification", f.ExperimentalKernelMemcgNotification, "If enabled, the kubelet will integrate with the kernel memcg notification to determine if memory eviction thresholds are crossed rather than polling.") fs.StringVar(&f.RemoteRuntimeEndpoint, "container-runtime-endpoint", f.RemoteRuntimeEndpoint, "[Experimental] The endpoint of remote runtime service. Currently unix socket is supported on Linux, and tcp is supported on windows. Examples:'unix:///var/run/dockershim.sock', 'tcp://localhost:3735'") fs.StringVar(&f.RemoteImageEndpoint, "image-service-endpoint", f.RemoteImageEndpoint, "[Experimental] The endpoint of remote image service. If not specified, it will be the same with container-runtime-endpoint by default. Currently unix socket is supported on Linux, and tcp is supported on windows. Examples:'unix:///var/run/dockershim.sock', 'tcp://localhost:3735'") diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 495e27264ba..7050c604e5c 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -3397,7 +3397,11 @@ func ValidatePodSecurityContext(securityContext *core.PodSecurityContext, spec * } if len(securityContext.Sysctls) != 0 { - allErrs = append(allErrs, validateSysctls(securityContext.Sysctls, fldPath.Child("sysctls"))...) + if utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) { + allErrs = append(allErrs, validateSysctls(securityContext.Sysctls, fldPath.Child("sysctls"))...) + } else { + allErrs = append(allErrs, field.Forbidden(fldPath.Child("sysctls"), "Sysctls are disabled by Sysctls feature-gate")) + } } } diff --git a/pkg/apis/policy/validation/BUILD b/pkg/apis/policy/validation/BUILD index d4895156c42..14fcee1d6ef 100644 --- a/pkg/apis/policy/validation/BUILD +++ b/pkg/apis/policy/validation/BUILD @@ -15,12 +15,14 @@ go_library( "//pkg/apis/core/validation:go_default_library", "//pkg/apis/extensions/validation:go_default_library", "//pkg/apis/policy:go_default_library", + "//pkg/features:go_default_library", "//pkg/security/apparmor:go_default_library", "//pkg/security/podsecuritypolicy/seccomp:go_default_library", "//pkg/security/podsecuritypolicy/util:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/validation:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library", + "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", ], ) diff --git a/pkg/apis/policy/validation/validation.go b/pkg/apis/policy/validation/validation.go index 3ba54867208..aa898ad8fdd 100644 --- a/pkg/apis/policy/validation/validation.go +++ b/pkg/apis/policy/validation/validation.go @@ -30,9 +30,12 @@ import ( apivalidation "k8s.io/kubernetes/pkg/apis/core/validation" extensionsvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" "k8s.io/kubernetes/pkg/apis/policy" + "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/security/apparmor" "k8s.io/kubernetes/pkg/security/podsecuritypolicy/seccomp" psputil "k8s.io/kubernetes/pkg/security/podsecuritypolicy/util" + + utilfeature "k8s.io/apiserver/pkg/util/feature" ) func ValidatePodDisruptionBudget(pdb *policy.PodDisruptionBudget) field.ErrorList { @@ -345,6 +348,15 @@ func validatePodSecurityPolicySysctlListsDoNotOverlap(allowedSysctlsFldPath, for // validatePodSecurityPolicySysctls validates the sysctls fields of PodSecurityPolicy. func validatePodSecurityPolicySysctls(fldPath *field.Path, sysctls []string) field.ErrorList { allErrs := field.ErrorList{} + + if len(sysctls) == 0 { + return allErrs + } + + if !utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) { + return append(allErrs, field.Forbidden(fldPath, "Sysctls are disabled by Sysctls feature-gate")) + } + coversAll := false for i, s := range sysctls { if len(s) == 0 { diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 491c7c05861..7c671194d84 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -160,6 +160,12 @@ const ( // Enable pods to consume pre-allocated huge pages of varying page sizes HugePages utilfeature.Feature = "HugePages" + // owner: @sjenning + // alpha: v1.4 + // + // Enable pods to set sysctls on a pod + Sysctls utilfeature.Feature = "Sysctls" + // owner @brendandburns // alpha: v1.9 // @@ -352,6 +358,7 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS PersistentLocalVolumes: {Default: true, PreRelease: utilfeature.Beta}, LocalStorageCapacityIsolation: {Default: true, PreRelease: utilfeature.Beta}, HugePages: {Default: true, PreRelease: utilfeature.Beta}, + Sysctls: {Default: true, PreRelease: utilfeature.Alpha}, DebugContainers: {Default: false, PreRelease: utilfeature.Alpha}, PodShareProcessNamespace: {Default: false, PreRelease: utilfeature.Alpha}, PodPriority: {Default: true, PreRelease: utilfeature.Beta}, diff --git a/pkg/kubelet/kubelet.go b/pkg/kubelet/kubelet.go index b448a00839a..a2690e3eb89 100644 --- a/pkg/kubelet/kubelet.go +++ b/pkg/kubelet/kubelet.go @@ -833,21 +833,23 @@ func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration, klet.evictionManager = evictionManager klet.admitHandlers.AddPodAdmitHandler(evictionAdmitHandler) - // add sysctl admission - runtimeSupport, err := sysctl.NewRuntimeAdmitHandler(klet.containerRuntime) - if err != nil { - return nil, err - } + if utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) { + // add sysctl admission + runtimeSupport, err := sysctl.NewRuntimeAdmitHandler(klet.containerRuntime) + if err != nil { + return nil, err + } - // Safe, whitelisted sysctls can always be used as unsafe sysctls in the spec. - // Hence, we concatenate those two lists. - safeAndUnsafeSysctls := append(sysctlwhitelist.SafeSysctlWhitelist(), allowedUnsafeSysctls...) - sysctlsWhitelist, err := sysctl.NewWhitelist(safeAndUnsafeSysctls) - if err != nil { - return nil, err + // Safe, whitelisted sysctls can always be used as unsafe sysctls in the spec. + // Hence, we concatenate those two lists. + safeAndUnsafeSysctls := append(sysctlwhitelist.SafeSysctlWhitelist(), allowedUnsafeSysctls...) + sysctlsWhitelist, err := sysctl.NewWhitelist(safeAndUnsafeSysctls) + if err != nil { + return nil, err + } + klet.admitHandlers.AddPodAdmitHandler(runtimeSupport) + klet.admitHandlers.AddPodAdmitHandler(sysctlsWhitelist) } - klet.admitHandlers.AddPodAdmitHandler(runtimeSupport) - klet.admitHandlers.AddPodAdmitHandler(sysctlsWhitelist) // enable active deadline handler activeDeadlineHandler, err := newActiveDeadlineHandler(klet.statusManager, kubeDeps.Recorder, klet.clock) diff --git a/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go b/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go index 1579b768372..33d0881f11e 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go @@ -25,6 +25,8 @@ import ( "github.com/golang/glog" "k8s.io/api/core/v1" kubetypes "k8s.io/apimachinery/pkg/types" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/kubernetes/pkg/features" runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2" kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" "k8s.io/kubernetes/pkg/kubelet/types" @@ -135,9 +137,11 @@ func (m *kubeGenericRuntimeManager) generatePodSandboxLinuxConfig(pod *v1.Pod) ( } sysctls := make(map[string]string) - if pod.Spec.SecurityContext != nil { - for _, c := range pod.Spec.SecurityContext.Sysctls { - sysctls[c.Name] = c.Value + if utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) { + if pod.Spec.SecurityContext != nil { + for _, c := range pod.Spec.SecurityContext.Sysctls { + sysctls[c.Name] = c.Value + } } }