1
16
17
18
19 package main
20
21 import (
22 "flag"
23 "fmt"
24 "net"
25 "os/exec"
26 "regexp"
27 "strings"
28
29 "errors"
30 "os"
31 )
32
33 const success = "\033[0;32mSUCCESS\033[0m"
34 const failed = "\033[0;31mFAILED\033[0m"
35 const notConfigured = "\033[0;34mNOT CONFIGURED\033[0m"
36 const skipped = "\033[0;34mSKIPPED\033[0m"
37
38 var checkFlag = flag.String(
39 "check", "all", "what to check for conformance. One or more of all,container-runtime,daemons,dns,firewall,kernel")
40
41 func init() {
42
43
44 flag.Set("logtostderr", "false")
45 }
46
47
48 func main() {
49 flag.Parse()
50 o := strings.Split(*checkFlag, ",")
51 errs := check(o...)
52 if len(errs) > 0 {
53 os.Exit(1)
54 } else {
55 os.Exit(0)
56 }
57 }
58
59
60 func check(options ...string) []error {
61 errs := []error{}
62 for _, c := range options {
63 switch c {
64 case "all":
65 errs = appendNotNil(errs, kernel())
66 errs = appendNotNil(errs, daemons())
67 errs = appendNotNil(errs, firewall())
68 errs = appendNotNil(errs, dns())
69 case "daemons":
70 errs = appendNotNil(errs, daemons())
71 case "dns":
72 errs = appendNotNil(errs, dns())
73 case "firewall":
74 errs = appendNotNil(errs, firewall())
75 case "kernel":
76 errs = appendNotNil(errs, kernel())
77 default:
78 fmt.Printf("Unrecognized option %s\n", c)
79 errs = append(errs, fmt.Errorf("Unrecognized option %s", c))
80 }
81 }
82 return errs
83 }
84
85 const kubeletClusterDNSRegexStr = `\/kubelet.*--cluster-dns=(\S+) `
86 const kubeletClusterDomainRegexStr = `\/kubelet.*--cluster-domain=(\S+)`
87
88
89 func dns() error {
90 dnsRegex, err := regexp.Compile(kubeletClusterDNSRegexStr)
91 if err != nil {
92
93 panic(err)
94 }
95 domainRegex, err := regexp.Compile(kubeletClusterDomainRegexStr)
96 if err != nil {
97
98 panic(err)
99 }
100
101 h, err := net.LookupHost("kubernetes.default")
102 if err == nil {
103 return printSuccess("Dns Check (Optional): %s", success)
104 }
105 if len(h) > 0 {
106 return printSuccess("Dns Check (Optional): %s", success)
107 }
108
109 kubecmd, err := exec.Command("ps", "aux").CombinedOutput()
110 if err != nil {
111
112 panic(err)
113 }
114
115
116 dns := dnsRegex.FindStringSubmatch(string(kubecmd))
117 if len(dns) < 2 {
118 return printSuccess(
119 "Dns Check (Optional): %s No hosts resolve to kubernetes.default. kubelet will need to set "+
120 "--cluster-dns and --cluster-domain when run", notConfigured)
121 }
122
123
124 domain := domainRegex.FindStringSubmatch(string(kubecmd))
125 if len(domain) < 2 {
126 return printSuccess(
127 "Dns Check (Optional): %s No hosts resolve to kubernetes.default. kubelet will need to set "+
128 "--cluster-dns and --cluster-domain when run", notConfigured)
129 }
130
131
132 nsArgs := []string{"-q=a", fmt.Sprintf("kubernetes.default.%s", domain[1]), dns[1]}
133 if err = exec.Command("nslookup", nsArgs...).Run(); err != nil {
134
135 return printError(
136 "Dns Check (Optional): %s No hosts resolve to kubernetes.default kubelet found, but cannot resolve "+
137 "kubernetes.default using nslookup %s error: %v", failed, strings.Join(nsArgs, " "), err)
138 }
139
140
141 return printSuccess("Dns Check (Optional): %s", success)
142 }
143
144 const cmdlineCGroupMemory = `cgroup_enable=memory`
145
146
147 func kernel() error {
148 cmdline, err := os.ReadFile("/proc/cmdline")
149 if err != nil {
150 return printError("Kernel Command Line Check %s: Could not check /proc/cmdline", failed)
151 }
152 if !strings.Contains(string(cmdline), cmdlineCGroupMemory) {
153 return printError("Kernel Command Line Check %s: cgroup_enable=memory not enabled in /proc/cmdline", failed)
154 }
155 return printSuccess("Kernel Command Line %s", success)
156 }
157
158 const iptablesInputRegexStr = `Chain INPUT \(policy DROP\)`
159 const iptablesForwardRegexStr = `Chain FORWARD \(policy DROP\)`
160
161
162 func firewall() error {
163 out, err := exec.Command("iptables", "-L", "INPUT").CombinedOutput()
164 if err != nil {
165 return printSuccess("Firewall IPTables Check %s: Could not run iptables", skipped)
166 }
167 inputRegex, err := regexp.Compile(iptablesInputRegexStr)
168 if err != nil {
169
170 panic(err)
171 }
172 if inputRegex.Match(out) {
173 return printError("Firewall IPTables Check %s: Found INPUT rule matching %s", failed, iptablesInputRegexStr)
174 }
175
176
177 out, err = exec.Command("iptables", "-L", "FORWARD").CombinedOutput()
178 if err != nil {
179 return printSuccess("Firewall IPTables Check %s: Could not run iptables", skipped)
180 }
181 forwardRegex, err := regexp.Compile(iptablesForwardRegexStr)
182 if err != nil {
183
184 panic(err)
185 }
186 if forwardRegex.Match(out) {
187 return printError("Firewall IPTables Check %s: Found FORWARD rule matching %s", failed, iptablesInputRegexStr)
188 }
189
190 return printSuccess("Firewall IPTables Check %s", success)
191 }
192
193
194 func daemons() error {
195 if exec.Command("pgrep", "-f", "kubelet").Run() != nil {
196 return printError("Daemon Check %s: kubelet process not found", failed)
197 }
198
199 if exec.Command("pgrep", "-f", "kube-proxy").Run() != nil {
200 return printError("Daemon Check %s: kube-proxy process not found", failed)
201 }
202
203 return printSuccess("Daemon Check %s", success)
204 }
205
206
207
208 func printError(s string, args ...interface{}) error {
209 es := fmt.Sprintf(s, args...)
210 fmt.Println(es)
211 return errors.New(es)
212 }
213
214
215 func printSuccess(s string, args ...interface{}) error {
216 fmt.Println(fmt.Sprintf(s, args...))
217 return nil
218 }
219
220
221 func appendNotNil(errs []error, err error) []error {
222 if err != nil {
223 return append(errs, err)
224 }
225 return errs
226 }
227
View as plain text