diff --git a/pkg/kubelet/sysctl/allowlist.go b/pkg/kubelet/sysctl/allowlist.go index 07daa528eac..c00449da4c8 100644 --- a/pkg/kubelet/sysctl/allowlist.go +++ b/pkg/kubelet/sysctl/allowlist.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + utilsysctl "k8s.io/component-helpers/node/util/sysctl" "k8s.io/kubernetes/pkg/apis/core/validation" policyvalidation "k8s.io/kubernetes/pkg/apis/policy/validation" "k8s.io/kubernetes/pkg/kubelet/lifecycle" @@ -33,8 +34,8 @@ const ( // checks validity via a sysctl and prefix map, rejecting those which are not known // to be namespaced. type patternAllowlist struct { - sysctls map[string]Namespace - prefixes map[string]Namespace + sysctls map[string]utilsysctl.Namespace + prefixes map[string]utilsysctl.Namespace } var _ lifecycle.PodAdmitHandler = &patternAllowlist{} @@ -42,8 +43,8 @@ var _ lifecycle.PodAdmitHandler = &patternAllowlist{} // NewAllowlist creates a new Allowlist from a list of sysctls and sysctl pattern (ending in *). func NewAllowlist(patterns []string) (*patternAllowlist, error) { w := &patternAllowlist{ - sysctls: map[string]Namespace{}, - prefixes: map[string]Namespace{}, + sysctls: map[string]utilsysctl.Namespace{}, + prefixes: map[string]utilsysctl.Namespace{}, } for _, s := range patterns { @@ -54,17 +55,17 @@ func NewAllowlist(patterns []string) (*patternAllowlist, error) { policyvalidation.SysctlContainSlashPatternFmt, ) } - s = convertSysctlVariableToDotsSeparator(s) + s = utilsysctl.ConvertSysctlVariableToDotsSeparator(s) if strings.HasSuffix(s, "*") { prefix := s[:len(s)-1] - ns := NamespacedBy(prefix) - if ns == unknownNamespace { + ns := utilsysctl.NamespacedBy(prefix) + if ns == utilsysctl.UnknownNamespace { return nil, fmt.Errorf("the sysctls %q are not known to be namespaced", s) } w.prefixes[prefix] = ns } else { - ns := NamespacedBy(s) - if ns == unknownNamespace { + ns := utilsysctl.NamespacedBy(s) + if ns == utilsysctl.UnknownNamespace { return nil, fmt.Errorf("the sysctl %q are not known to be namespaced", s) } w.sysctls[s] = ns @@ -81,23 +82,23 @@ func NewAllowlist(patterns []string) (*patternAllowlist, error) { // respective namespaces with the host. This check is only possible for sysctls on // the static default allowlist, not those on the custom allowlist provided by the admin. func (w *patternAllowlist) validateSysctl(sysctl string, hostNet, hostIPC bool) error { - sysctl = convertSysctlVariableToDotsSeparator(sysctl) + sysctl = utilsysctl.ConvertSysctlVariableToDotsSeparator(sysctl) nsErrorFmt := "%q not allowed with host %s enabled" if ns, found := w.sysctls[sysctl]; found { - if ns == ipcNamespace && hostIPC { + if ns == utilsysctl.IpcNamespace && hostIPC { return fmt.Errorf(nsErrorFmt, sysctl, ns) } - if ns == netNamespace && hostNet { + if ns == utilsysctl.NetNamespace && hostNet { return fmt.Errorf(nsErrorFmt, sysctl, ns) } return nil } for p, ns := range w.prefixes { if strings.HasPrefix(sysctl, p) { - if ns == ipcNamespace && hostIPC { + if ns == utilsysctl.IpcNamespace && hostIPC { return fmt.Errorf(nsErrorFmt, sysctl, ns) } - if ns == netNamespace && hostNet { + if ns == utilsysctl.NetNamespace && hostNet { return fmt.Errorf(nsErrorFmt, sysctl, ns) } return nil diff --git a/pkg/kubelet/sysctl/util.go b/pkg/kubelet/sysctl/util.go index 0013fb7f688..031cf80d6ea 100644 --- a/pkg/kubelet/sysctl/util.go +++ b/pkg/kubelet/sysctl/util.go @@ -17,39 +17,10 @@ limitations under the License. package sysctl import ( - "strings" - - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" + utilsysctl "k8s.io/component-helpers/node/util/sysctl" ) -// convertSysctlVariableToDotsSeparator can return sysctl variables in dots separator format. -// The '/' separator is also accepted in place of a '.'. -// Convert the sysctl variables to dots separator format for validation. -// More info: -// -// https://man7.org/linux/man-pages/man8/sysctl.8.html -// https://man7.org/linux/man-pages/man5/sysctl.d.5.html -func convertSysctlVariableToDotsSeparator(val string) string { - if val == "" { - return val - } - firstSepIndex := strings.IndexAny(val, "./") - if firstSepIndex == -1 || val[firstSepIndex] == '.' { - return val - } - - f := func(r rune) rune { - switch r { - case '.': - return '/' - case '/': - return '.' - } - return r - } - return strings.Map(f, val) -} - // ConvertPodSysctlsVariableToDotsSeparator converts sysctls variable in the Pod.Spec.SecurityContext.Sysctls slice into a dot as a separator // according to the linux sysctl conversion rules. // see https://man7.org/linux/man-pages/man5/sysctl.d.5.html for more details. @@ -58,7 +29,7 @@ func ConvertPodSysctlsVariableToDotsSeparator(securityContext *v1.PodSecurityCon return } for i, sysctl := range securityContext.Sysctls { - securityContext.Sysctls[i].Name = convertSysctlVariableToDotsSeparator(sysctl.Name) + securityContext.Sysctls[i].Name = utilsysctl.ConvertSysctlVariableToDotsSeparator(sysctl.Name) } return } diff --git a/pkg/kubelet/sysctl/util_test.go b/pkg/kubelet/sysctl/util_test.go index 15c6cd40f96..97534bd1398 100644 --- a/pkg/kubelet/sysctl/util_test.go +++ b/pkg/kubelet/sysctl/util_test.go @@ -24,29 +24,6 @@ import ( "github.com/stretchr/testify/assert" ) -// TestConvertSysctlVariableToDotsSeparator tests whether the sysctl variable -// can be correctly converted to a dot as a separator. -func TestConvertSysctlVariableToDotsSeparator(t *testing.T) { - type testCase struct { - in string - out string - } - valid := []testCase{ - {in: "kernel.shm_rmid_forced", out: "kernel.shm_rmid_forced"}, - {in: "kernel/shm_rmid_forced", out: "kernel.shm_rmid_forced"}, - {in: "net.ipv4.conf.eno2/100.rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"}, - {in: "net/ipv4/conf/eno2.100/rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"}, - {in: "net/ipv4/ip_local_port_range", out: "net.ipv4.ip_local_port_range"}, - {in: "kernel/msgmax", out: "kernel.msgmax"}, - {in: "kernel/sem", out: "kernel.sem"}, - } - - for _, test := range valid { - convertSysctlVal := convertSysctlVariableToDotsSeparator(test.in) - assert.Equalf(t, test.out, convertSysctlVal, "The sysctl variable was not converted correctly. got: %s, want: %s", convertSysctlVal, test.out) - } -} - // TestConvertPodSysctlsVariableToDotsSeparator tests whether the sysctls variable // can be correctly converted to a dot as a separator. func TestConvertPodSysctlsVariableToDotsSeparator(t *testing.T) { diff --git a/pkg/kubelet/sysctl/namespace.go b/staging/src/k8s.io/component-helpers/node/util/sysctl/namespace.go similarity index 79% rename from pkg/kubelet/sysctl/namespace.go rename to staging/src/k8s.io/component-helpers/node/util/sysctl/namespace.go index c1c93ed5f8b..591c0b8090b 100644 --- a/pkg/kubelet/sysctl/namespace.go +++ b/staging/src/k8s.io/component-helpers/node/util/sysctl/namespace.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors. +Copyright 2023 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -25,24 +25,24 @@ type Namespace string const ( // the Linux IPC namespace - ipcNamespace = Namespace("ipc") + IpcNamespace = Namespace("ipc") // the network namespace - netNamespace = Namespace("net") + NetNamespace = Namespace("net") // the zero value if no namespace is known - unknownNamespace = Namespace("") + UnknownNamespace = Namespace("") ) var namespaces = map[string]Namespace{ - "kernel.sem": ipcNamespace, + "kernel.sem": IpcNamespace, } var prefixNamespaces = map[string]Namespace{ - "kernel.shm": ipcNamespace, - "kernel.msg": ipcNamespace, - "fs.mqueue.": ipcNamespace, - "net.": netNamespace, + "kernel.shm": IpcNamespace, + "kernel.msg": IpcNamespace, + "fs.mqueue.": IpcNamespace, + "net.": NetNamespace, } // NamespacedBy returns the namespace of the Linux kernel for a sysctl, or @@ -56,5 +56,5 @@ func NamespacedBy(val string) Namespace { return ns } } - return unknownNamespace + return UnknownNamespace } diff --git a/pkg/kubelet/sysctl/namespace_test.go b/staging/src/k8s.io/component-helpers/node/util/sysctl/namespace_test.go similarity index 79% rename from pkg/kubelet/sysctl/namespace_test.go rename to staging/src/k8s.io/component-helpers/node/util/sysctl/namespace_test.go index 1db7f8460ec..821b1dfe620 100644 --- a/pkg/kubelet/sysctl/namespace_test.go +++ b/staging/src/k8s.io/component-helpers/node/util/sysctl/namespace_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors. +Copyright 2023 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -22,10 +22,10 @@ import ( func TestNamespacedBy(t *testing.T) { tests := map[string]Namespace{ - "kernel.shm_rmid_forced": ipcNamespace, - "net.a.b.c": netNamespace, - "fs.mqueue.a.b.c": ipcNamespace, - "foo": unknownNamespace, + "kernel.shm_rmid_forced": IpcNamespace, + "net.a.b.c": NetNamespace, + "fs.mqueue.a.b.c": IpcNamespace, + "foo": UnknownNamespace, } for sysctl, ns := range tests { diff --git a/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl.go b/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl.go index 4910aa22d35..8e6268fcb7e 100644 --- a/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl.go +++ b/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl.go @@ -98,3 +98,31 @@ func (*procSysctl) GetSysctl(sysctl string) (int, error) { func (*procSysctl) SetSysctl(sysctl string, newVal int) error { return os.WriteFile(path.Join(sysctlBase, sysctl), []byte(strconv.Itoa(newVal)), 0640) } + +// ConvertSysctlVariableToDotsSeparator can return sysctl variables in dots separator format. +// The '/' separator is also accepted in place of a '.'. +// Convert the sysctl variables to dots separator format for validation. +// More info: +// +// https://man7.org/linux/man-pages/man8/sysctl.8.html +// https://man7.org/linux/man-pages/man5/sysctl.d.5.html +func ConvertSysctlVariableToDotsSeparator(val string) string { + if val == "" { + return val + } + firstSepIndex := strings.IndexAny(val, "./") + if firstSepIndex == -1 || val[firstSepIndex] == '.' { + return val + } + + f := func(r rune) rune { + switch r { + case '.': + return '/' + case '/': + return '.' + } + return r + } + return strings.Map(f, val) +} diff --git a/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl_test.go b/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl_test.go new file mode 100644 index 00000000000..32e27cdf1f8 --- /dev/null +++ b/staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl_test.go @@ -0,0 +1,44 @@ +/* +Copyright 2023 The Kubernetes Authors. + +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 sysctl + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +// TestConvertSysctlVariableToDotsSeparator tests whether the sysctl variable +// can be correctly converted to a dot as a separator. +func TestConvertSysctlVariableToDotsSeparator(t *testing.T) { + type testCase struct { + in string + out string + } + valid := []testCase{ + {in: "kernel.shm_rmid_forced", out: "kernel.shm_rmid_forced"}, + {in: "kernel/shm_rmid_forced", out: "kernel.shm_rmid_forced"}, + {in: "net.ipv4.conf.eno2/100.rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"}, + {in: "net/ipv4/conf/eno2.100/rp_filter", out: "net.ipv4.conf.eno2/100.rp_filter"}, + {in: "net/ipv4/ip_local_port_range", out: "net.ipv4.ip_local_port_range"}, + {in: "kernel/msgmax", out: "kernel.msgmax"}, + {in: "kernel/sem", out: "kernel.sem"}, + } + + for _, test := range valid { + convertSysctlVal := ConvertSysctlVariableToDotsSeparator(test.in) + assert.Equalf(t, test.out, convertSysctlVal, "The sysctl variable was not converted correctly. got: %s, want: %s", convertSysctlVal, test.out) + } +}