mirror of https://github.com/k3s-io/k3s
127 lines
3.5 KiB
Go
127 lines
3.5 KiB
Go
/*
|
|
Copyright 2016 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 (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
|
api "k8s.io/kubernetes/pkg/apis/core"
|
|
)
|
|
|
|
// SafeSysctlWhitelist returns the whitelist of safe sysctls and safe sysctl patterns (ending in *).
|
|
//
|
|
// A sysctl is called safe iff
|
|
// - it is namespaced in the container or the pod
|
|
// - it is isolated, i.e. has no influence on any other pod on the same node.
|
|
func SafeSysctlWhitelist() []string {
|
|
return []string{
|
|
"kernel.shm_rmid_forced",
|
|
"net.ipv4.ip_local_port_range",
|
|
"net.ipv4.tcp_syncookies",
|
|
}
|
|
}
|
|
|
|
// mustMatchPatterns implements the SysctlsStrategy interface
|
|
type mustMatchPatterns struct {
|
|
safeWhitelist []string
|
|
allowedUnsafeSysctls []string
|
|
forbiddenSysctls []string
|
|
}
|
|
|
|
var (
|
|
_ SysctlsStrategy = &mustMatchPatterns{}
|
|
|
|
defaultSysctlsPatterns = []string{"*"}
|
|
)
|
|
|
|
// NewMustMatchPatterns creates a new mustMatchPatterns strategy that will provide validation.
|
|
// Passing nil means the default pattern, passing an empty list means to disallow all sysctls.
|
|
func NewMustMatchPatterns(safeWhitelist, allowedUnsafeSysctls, forbiddenSysctls []string) SysctlsStrategy {
|
|
return &mustMatchPatterns{
|
|
safeWhitelist: safeWhitelist,
|
|
allowedUnsafeSysctls: allowedUnsafeSysctls,
|
|
forbiddenSysctls: forbiddenSysctls,
|
|
}
|
|
}
|
|
|
|
func (s *mustMatchPatterns) isForbidden(sysctlName string) bool {
|
|
// Is the sysctl forbidden?
|
|
for _, s := range s.forbiddenSysctls {
|
|
if strings.HasSuffix(s, "*") {
|
|
prefix := strings.TrimSuffix(s, "*")
|
|
if strings.HasPrefix(sysctlName, prefix) {
|
|
return true
|
|
}
|
|
} else if sysctlName == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (s *mustMatchPatterns) isSafe(sysctlName string) bool {
|
|
for _, ws := range s.safeWhitelist {
|
|
if sysctlName == ws {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (s *mustMatchPatterns) isAllowedUnsafe(sysctlName string) bool {
|
|
for _, s := range s.allowedUnsafeSysctls {
|
|
if strings.HasSuffix(s, "*") {
|
|
prefix := strings.TrimSuffix(s, "*")
|
|
if strings.HasPrefix(sysctlName, prefix) {
|
|
return true
|
|
}
|
|
} else if sysctlName == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Validate ensures that the specified values fall within the range of the strategy.
|
|
func (s *mustMatchPatterns) Validate(pod *api.Pod) field.ErrorList {
|
|
allErrs := field.ErrorList{}
|
|
|
|
var sysctls []api.Sysctl
|
|
if pod.Spec.SecurityContext != nil {
|
|
sysctls = pod.Spec.SecurityContext.Sysctls
|
|
}
|
|
|
|
fieldPath := field.NewPath("pod", "spec", "securityContext").Child("sysctls")
|
|
|
|
for i, sysctl := range sysctls {
|
|
switch {
|
|
case s.isForbidden(sysctl.Name):
|
|
allErrs = append(allErrs, field.ErrorList{field.Forbidden(fieldPath.Index(i), fmt.Sprintf("sysctl %q is not allowed", sysctl.Name))}...)
|
|
case s.isSafe(sysctl.Name):
|
|
continue
|
|
case s.isAllowedUnsafe(sysctl.Name):
|
|
continue
|
|
default:
|
|
allErrs = append(allErrs, field.ErrorList{field.Forbidden(fieldPath.Index(i), fmt.Sprintf("unsafe sysctl %q is not allowed", sysctl.Name))}...)
|
|
}
|
|
}
|
|
|
|
return allErrs
|
|
}
|