...
1
16
17 package sysctl
18
19 import (
20 "fmt"
21 "strings"
22
23 utilsysctl "k8s.io/component-helpers/node/util/sysctl"
24 "k8s.io/kubernetes/pkg/apis/core/validation"
25 policyvalidation "k8s.io/kubernetes/pkg/apis/policy/validation"
26 "k8s.io/kubernetes/pkg/kubelet/lifecycle"
27 )
28
29 const (
30 ForbiddenReason = "SysctlForbidden"
31 )
32
33
34
35
36 type patternAllowlist struct {
37 sysctls map[string]utilsysctl.Namespace
38 prefixes map[string]utilsysctl.Namespace
39 }
40
41 var _ lifecycle.PodAdmitHandler = &patternAllowlist{}
42
43
44 func NewAllowlist(patterns []string) (*patternAllowlist, error) {
45 w := &patternAllowlist{
46 sysctls: map[string]utilsysctl.Namespace{},
47 prefixes: map[string]utilsysctl.Namespace{},
48 }
49
50 for _, s := range patterns {
51 if !policyvalidation.IsValidSysctlPattern(s) {
52 return nil, fmt.Errorf("sysctl %q must have at most %d characters and match regex %s",
53 s,
54 validation.SysctlMaxLength,
55 policyvalidation.SysctlContainSlashPatternFmt,
56 )
57 }
58 ns, sysctlOrPrefix, prefixed := utilsysctl.GetNamespace(s)
59 if ns == utilsysctl.UnknownNamespace {
60 return nil, fmt.Errorf("the sysctls %q are not known to be namespaced", sysctlOrPrefix)
61 }
62 if prefixed {
63 w.prefixes[sysctlOrPrefix] = ns
64 } else {
65 w.sysctls[sysctlOrPrefix] = ns
66 }
67 }
68 return w, nil
69 }
70
71
72
73
74
75
76
77
78 func (w *patternAllowlist) validateSysctl(sysctl string, hostNet, hostIPC bool) error {
79 sysctl = utilsysctl.NormalizeName(sysctl)
80 nsErrorFmt := "%q not allowed with host %s enabled"
81 if ns, found := w.sysctls[sysctl]; found {
82 if ns == utilsysctl.IPCNamespace && hostIPC {
83 return fmt.Errorf(nsErrorFmt, sysctl, ns)
84 }
85 if ns == utilsysctl.NetNamespace && hostNet {
86 return fmt.Errorf(nsErrorFmt, sysctl, ns)
87 }
88 return nil
89 }
90 for p, ns := range w.prefixes {
91 if strings.HasPrefix(sysctl, p) {
92 if ns == utilsysctl.IPCNamespace && hostIPC {
93 return fmt.Errorf(nsErrorFmt, sysctl, ns)
94 }
95 if ns == utilsysctl.NetNamespace && hostNet {
96 return fmt.Errorf(nsErrorFmt, sysctl, ns)
97 }
98 return nil
99 }
100 }
101 return fmt.Errorf("%q not allowlisted", sysctl)
102 }
103
104
105
106 func (w *patternAllowlist) Admit(attrs *lifecycle.PodAdmitAttributes) lifecycle.PodAdmitResult {
107 pod := attrs.Pod
108 if pod.Spec.SecurityContext == nil || len(pod.Spec.SecurityContext.Sysctls) == 0 {
109 return lifecycle.PodAdmitResult{
110 Admit: true,
111 }
112 }
113
114 for _, s := range pod.Spec.SecurityContext.Sysctls {
115 if err := w.validateSysctl(s.Name, pod.Spec.HostNetwork, pod.Spec.HostIPC); err != nil {
116 return lifecycle.PodAdmitResult{
117 Admit: false,
118 Reason: ForbiddenReason,
119 Message: fmt.Sprintf("forbidden sysctl: %v", err),
120 }
121 }
122 }
123
124 return lifecycle.PodAdmitResult{
125 Admit: true,
126 }
127 }
128
View as plain text