mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 02:09:56 +00:00
move sysctl namespace and some funcs to component helpers util
Signed-off-by: Paco Xu <paco.xu@daocloud.io>
This commit is contained in:
parent
4321652d13
commit
11de9543ee
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
utilsysctl "k8s.io/component-helpers/node/util/sysctl"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
policyvalidation "k8s.io/kubernetes/pkg/apis/policy/validation"
|
policyvalidation "k8s.io/kubernetes/pkg/apis/policy/validation"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
|
"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
|
// checks validity via a sysctl and prefix map, rejecting those which are not known
|
||||||
// to be namespaced.
|
// to be namespaced.
|
||||||
type patternAllowlist struct {
|
type patternAllowlist struct {
|
||||||
sysctls map[string]Namespace
|
sysctls map[string]utilsysctl.Namespace
|
||||||
prefixes map[string]Namespace
|
prefixes map[string]utilsysctl.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ lifecycle.PodAdmitHandler = &patternAllowlist{}
|
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 *).
|
// NewAllowlist creates a new Allowlist from a list of sysctls and sysctl pattern (ending in *).
|
||||||
func NewAllowlist(patterns []string) (*patternAllowlist, error) {
|
func NewAllowlist(patterns []string) (*patternAllowlist, error) {
|
||||||
w := &patternAllowlist{
|
w := &patternAllowlist{
|
||||||
sysctls: map[string]Namespace{},
|
sysctls: map[string]utilsysctl.Namespace{},
|
||||||
prefixes: map[string]Namespace{},
|
prefixes: map[string]utilsysctl.Namespace{},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range patterns {
|
for _, s := range patterns {
|
||||||
@ -54,17 +55,17 @@ func NewAllowlist(patterns []string) (*patternAllowlist, error) {
|
|||||||
policyvalidation.SysctlContainSlashPatternFmt,
|
policyvalidation.SysctlContainSlashPatternFmt,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
s = convertSysctlVariableToDotsSeparator(s)
|
s = utilsysctl.ConvertSysctlVariableToDotsSeparator(s)
|
||||||
if strings.HasSuffix(s, "*") {
|
if strings.HasSuffix(s, "*") {
|
||||||
prefix := s[:len(s)-1]
|
prefix := s[:len(s)-1]
|
||||||
ns := NamespacedBy(prefix)
|
ns := utilsysctl.NamespacedBy(prefix)
|
||||||
if ns == unknownNamespace {
|
if ns == utilsysctl.UnknownNamespace {
|
||||||
return nil, fmt.Errorf("the sysctls %q are not known to be namespaced", s)
|
return nil, fmt.Errorf("the sysctls %q are not known to be namespaced", s)
|
||||||
}
|
}
|
||||||
w.prefixes[prefix] = ns
|
w.prefixes[prefix] = ns
|
||||||
} else {
|
} else {
|
||||||
ns := NamespacedBy(s)
|
ns := utilsysctl.NamespacedBy(s)
|
||||||
if ns == unknownNamespace {
|
if ns == utilsysctl.UnknownNamespace {
|
||||||
return nil, fmt.Errorf("the sysctl %q are not known to be namespaced", s)
|
return nil, fmt.Errorf("the sysctl %q are not known to be namespaced", s)
|
||||||
}
|
}
|
||||||
w.sysctls[s] = ns
|
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
|
// 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.
|
// the static default allowlist, not those on the custom allowlist provided by the admin.
|
||||||
func (w *patternAllowlist) validateSysctl(sysctl string, hostNet, hostIPC bool) error {
|
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"
|
nsErrorFmt := "%q not allowed with host %s enabled"
|
||||||
if ns, found := w.sysctls[sysctl]; found {
|
if ns, found := w.sysctls[sysctl]; found {
|
||||||
if ns == ipcNamespace && hostIPC {
|
if ns == utilsysctl.IpcNamespace && hostIPC {
|
||||||
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
||||||
}
|
}
|
||||||
if ns == netNamespace && hostNet {
|
if ns == utilsysctl.NetNamespace && hostNet {
|
||||||
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
for p, ns := range w.prefixes {
|
for p, ns := range w.prefixes {
|
||||||
if strings.HasPrefix(sysctl, p) {
|
if strings.HasPrefix(sysctl, p) {
|
||||||
if ns == ipcNamespace && hostIPC {
|
if ns == utilsysctl.IpcNamespace && hostIPC {
|
||||||
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
||||||
}
|
}
|
||||||
if ns == netNamespace && hostNet {
|
if ns == utilsysctl.NetNamespace && hostNet {
|
||||||
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
return fmt.Errorf(nsErrorFmt, sysctl, ns)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -17,39 +17,10 @@ limitations under the License.
|
|||||||
package sysctl
|
package sysctl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
utilsysctl "k8s.io/component-helpers/node/util/sysctl"
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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
|
// ConvertPodSysctlsVariableToDotsSeparator converts sysctls variable in the Pod.Spec.SecurityContext.Sysctls slice into a dot as a separator
|
||||||
// according to the linux sysctl conversion rules.
|
// according to the linux sysctl conversion rules.
|
||||||
// see https://man7.org/linux/man-pages/man5/sysctl.d.5.html for more details.
|
// 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
|
return
|
||||||
}
|
}
|
||||||
for i, sysctl := range securityContext.Sysctls {
|
for i, sysctl := range securityContext.Sysctls {
|
||||||
securityContext.Sysctls[i].Name = convertSysctlVariableToDotsSeparator(sysctl.Name)
|
securityContext.Sysctls[i].Name = utilsysctl.ConvertSysctlVariableToDotsSeparator(sysctl.Name)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -24,29 +24,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"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
|
// TestConvertPodSysctlsVariableToDotsSeparator tests whether the sysctls variable
|
||||||
// can be correctly converted to a dot as a separator.
|
// can be correctly converted to a dot as a separator.
|
||||||
func TestConvertPodSysctlsVariableToDotsSeparator(t *testing.T) {
|
func TestConvertPodSysctlsVariableToDotsSeparator(t *testing.T) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2016 The Kubernetes Authors.
|
Copyright 2023 The Kubernetes Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -25,24 +25,24 @@ type Namespace string
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// the Linux IPC namespace
|
// the Linux IPC namespace
|
||||||
ipcNamespace = Namespace("ipc")
|
IpcNamespace = Namespace("ipc")
|
||||||
|
|
||||||
// the network namespace
|
// the network namespace
|
||||||
netNamespace = Namespace("net")
|
NetNamespace = Namespace("net")
|
||||||
|
|
||||||
// the zero value if no namespace is known
|
// the zero value if no namespace is known
|
||||||
unknownNamespace = Namespace("")
|
UnknownNamespace = Namespace("")
|
||||||
)
|
)
|
||||||
|
|
||||||
var namespaces = map[string]Namespace{
|
var namespaces = map[string]Namespace{
|
||||||
"kernel.sem": ipcNamespace,
|
"kernel.sem": IpcNamespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
var prefixNamespaces = map[string]Namespace{
|
var prefixNamespaces = map[string]Namespace{
|
||||||
"kernel.shm": ipcNamespace,
|
"kernel.shm": IpcNamespace,
|
||||||
"kernel.msg": ipcNamespace,
|
"kernel.msg": IpcNamespace,
|
||||||
"fs.mqueue.": ipcNamespace,
|
"fs.mqueue.": IpcNamespace,
|
||||||
"net.": netNamespace,
|
"net.": NetNamespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamespacedBy returns the namespace of the Linux kernel for a sysctl, or
|
// NamespacedBy returns the namespace of the Linux kernel for a sysctl, or
|
||||||
@ -56,5 +56,5 @@ func NamespacedBy(val string) Namespace {
|
|||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return unknownNamespace
|
return UnknownNamespace
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2016 The Kubernetes Authors.
|
Copyright 2023 The Kubernetes Authors.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -22,10 +22,10 @@ import (
|
|||||||
|
|
||||||
func TestNamespacedBy(t *testing.T) {
|
func TestNamespacedBy(t *testing.T) {
|
||||||
tests := map[string]Namespace{
|
tests := map[string]Namespace{
|
||||||
"kernel.shm_rmid_forced": ipcNamespace,
|
"kernel.shm_rmid_forced": IpcNamespace,
|
||||||
"net.a.b.c": netNamespace,
|
"net.a.b.c": NetNamespace,
|
||||||
"fs.mqueue.a.b.c": ipcNamespace,
|
"fs.mqueue.a.b.c": IpcNamespace,
|
||||||
"foo": unknownNamespace,
|
"foo": UnknownNamespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
for sysctl, ns := range tests {
|
for sysctl, ns := range tests {
|
@ -98,3 +98,31 @@ func (*procSysctl) GetSysctl(sysctl string) (int, error) {
|
|||||||
func (*procSysctl) SetSysctl(sysctl string, newVal int) error {
|
func (*procSysctl) SetSysctl(sysctl string, newVal int) error {
|
||||||
return os.WriteFile(path.Join(sysctlBase, sysctl), []byte(strconv.Itoa(newVal)), 0640)
|
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)
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user