syncable_cli/analyzer/kubelint/checks/
builtin.rs

1//! Built-in checks for kube-linter.
2//!
3//! This module registers all 63 built-in checks that come with kube-linter.
4
5use crate::analyzer::kubelint::config::{CheckScope, CheckSpec};
6
7/// Get all built-in check specifications.
8pub fn builtin_checks() -> Vec<CheckSpec> {
9    vec![
10        // Security checks
11        CheckSpec::new(
12            "privileged-container",
13            "Indicates when deployments have containers running in privileged mode.",
14            "Do not run your container as privileged unless it is required.",
15            "privileged",
16        )
17        .with_scope(CheckScope::new(&["DeploymentLike"])),
18        CheckSpec::new(
19            "privilege-escalation",
20            "Alert on containers of deployments that allow privilege escalation.",
21            "Ensure containers do not allow privilege escalation by setting allowPrivilegeEscalation to false.",
22            "privilege-escalation",
23        )
24        .with_scope(CheckScope::new(&["DeploymentLike"])),
25        CheckSpec::new(
26            "run-as-non-root",
27            "Indicates when containers are not set to runAsNonRoot.",
28            "Set runAsNonRoot to true in your container's securityContext.",
29            "run-as-non-root",
30        )
31        .with_scope(CheckScope::new(&["DeploymentLike"])),
32        CheckSpec::new(
33            "read-only-root-fs",
34            "Indicates when containers are running with a read-write root filesystem.",
35            "Set readOnlyRootFilesystem to true in your container's securityContext.",
36            "read-only-root-fs",
37        )
38        .with_scope(CheckScope::new(&["DeploymentLike"])),
39        CheckSpec::new(
40            "drop-net-raw-capability",
41            "Indicates when containers do not drop NET_RAW capability.",
42            "NET_RAW capability allows a container to craft arbitrary network packets. Drop this capability.",
43            "drop-net-raw-capability",
44        )
45        .with_scope(CheckScope::new(&["DeploymentLike"])),
46        CheckSpec::new(
47            "hostnetwork",
48            "Indicates when deployments use the host's network namespace.",
49            "Ensure deployments do not share the host's network namespace.",
50            "host-network",
51        )
52        .with_scope(CheckScope::new(&["DeploymentLike"])),
53        CheckSpec::new(
54            "hostpid",
55            "Indicates when deployments share the host's process namespace.",
56            "Ensure deployments do not share the host's process namespace.",
57            "host-pid",
58        )
59        .with_scope(CheckScope::new(&["DeploymentLike"])),
60        CheckSpec::new(
61            "hostipc",
62            "Indicates when deployments share the host's IPC namespace.",
63            "Ensure deployments do not share the host's IPC namespace.",
64            "host-ipc",
65        )
66        .with_scope(CheckScope::new(&["DeploymentLike"])),
67        CheckSpec::new(
68            "host-mounts",
69            "Indicates when deployments mount sensitive host directories.",
70            "Do not mount sensitive host paths unless absolutely necessary.",
71            "host-mounts",
72        )
73        .with_scope(CheckScope::new(&["DeploymentLike"])),
74        CheckSpec::new(
75            "writable-host-mount",
76            "Indicates when containers mount host directories as writable.",
77            "Mount host paths as read-only unless write access is required.",
78            "writable-host-mount",
79        )
80        .with_scope(CheckScope::new(&["DeploymentLike"])),
81        CheckSpec::new(
82            "docker-sock",
83            "Indicates when deployments mount the Docker socket.",
84            "Do not mount /var/run/docker.sock as it gives full control over Docker.",
85            "host-mounts",
86        )
87        .with_scope(CheckScope::new(&["DeploymentLike"])),
88        CheckSpec::new(
89            "unsafe-proc-mount",
90            "Indicates when containers have unsafe /proc mount.",
91            "Use the Default procMount type unless Unmasked is absolutely required.",
92            "unsafe-proc-mount",
93        )
94        .with_scope(CheckScope::new(&["DeploymentLike"])),
95        // Best practice checks
96        CheckSpec::new(
97            "latest-tag",
98            "Indicates when containers use images with the 'latest' tag.",
99            "Use specific image tags instead of 'latest' for reproducible deployments.",
100            "latest-tag",
101        )
102        .with_scope(CheckScope::new(&["DeploymentLike"])),
103        CheckSpec::new(
104            "no-liveness-probe",
105            "Indicates when containers do not have liveness probes configured.",
106            "Add a liveness probe to detect and recover from container failures.",
107            "liveness-probe",
108        )
109        .with_scope(CheckScope::new(&["DeploymentLike"])),
110        CheckSpec::new(
111            "no-readiness-probe",
112            "Indicates when containers do not have readiness probes configured.",
113            "Add a readiness probe to ensure traffic is only sent to healthy containers.",
114            "readiness-probe",
115        )
116        .with_scope(CheckScope::new(&["DeploymentLike"])),
117        CheckSpec::new(
118            "unset-cpu-requirements",
119            "Indicates when containers do not have CPU requirements set.",
120            "Set CPU requests and limits for better resource management.",
121            "cpu-requirements",
122        )
123        .with_scope(CheckScope::new(&["DeploymentLike"])),
124        CheckSpec::new(
125            "unset-memory-requirements",
126            "Indicates when containers do not have memory requirements set.",
127            "Set memory requests and limits for better resource management.",
128            "memory-requirements",
129        )
130        .with_scope(CheckScope::new(&["DeploymentLike"])),
131        CheckSpec::new(
132            "minimum-replicas",
133            "Indicates when deployments have fewer than the minimum recommended replicas.",
134            "Increase the number of replicas for better availability.",
135            "replicas",
136        )
137        .with_scope(CheckScope::new(&["Deployment", "StatefulSet"])),
138        CheckSpec::new(
139            "no-anti-affinity",
140            "Indicates when deployments do not have pod anti-affinity configured.",
141            "Use pod anti-affinity to spread pods across nodes for better availability.",
142            "anti-affinity",
143        )
144        .with_scope(CheckScope::new(&["Deployment", "StatefulSet"])),
145        CheckSpec::new(
146            "no-rolling-update-strategy",
147            "Indicates when deployments do not use a rolling update strategy.",
148            "Use RollingUpdate strategy for zero-downtime deployments.",
149            "rolling-update-strategy",
150        )
151        .with_scope(CheckScope::new(&["Deployment"])),
152        CheckSpec::new(
153            "default-service-account",
154            "Indicates when deployments use the default service account.",
155            "Create and use a dedicated service account for your workloads.",
156            "service-account",
157        )
158        .with_scope(CheckScope::new(&["DeploymentLike"])),
159        CheckSpec::new(
160            "deprecated-service-account",
161            "Indicates when the deprecated serviceAccount field is used.",
162            "Use serviceAccountName instead of the deprecated serviceAccount field.",
163            "deprecated-service-account-field",
164        )
165        .with_scope(CheckScope::new(&["DeploymentLike"])),
166        // RBAC checks
167        CheckSpec::new(
168            "access-to-secrets",
169            "Indicates when RBAC rules grant access to secrets.",
170            "Limit access to secrets to only those that need it.",
171            "access-to-secrets",
172        )
173        .with_scope(CheckScope::new(&["Role", "ClusterRole"])),
174        CheckSpec::new(
175            "access-to-create-pods",
176            "Indicates when RBAC rules grant create access to pods.",
177            "Limit the ability to create pods as it can be used for privilege escalation.",
178            "access-to-create-pods",
179        )
180        .with_scope(CheckScope::new(&["Role", "ClusterRole"])),
181        CheckSpec::new(
182            "cluster-admin-role-binding",
183            "Indicates when a ClusterRoleBinding grants cluster-admin.",
184            "Avoid granting cluster-admin to users or service accounts.",
185            "cluster-admin-role-binding",
186        )
187        .with_scope(CheckScope::new(&["ClusterRoleBinding"])),
188        CheckSpec::new(
189            "wildcard-in-rules",
190            "Indicates when RBAC rules use wildcards.",
191            "Avoid wildcards in RBAC rules; be specific about resources and verbs.",
192            "wildcard-in-rules",
193        )
194        .with_scope(CheckScope::new(&["Role", "ClusterRole"])),
195        // Validation checks
196        CheckSpec::new(
197            "dangling-service",
198            "Indicates when services have selectors that do not match any pods.",
199            "Ensure service selectors match labels on pods.",
200            "dangling-service",
201        )
202        .with_scope(CheckScope::new(&["Service"])),
203        CheckSpec::new(
204            "dangling-ingress",
205            "Indicates when ingresses reference non-existent services.",
206            "Ensure ingress backends reference existing services.",
207            "dangling-ingress",
208        )
209        .with_scope(CheckScope::new(&["Ingress"])),
210        CheckSpec::new(
211            "dangling-horizontalpodautoscaler",
212            "Indicates when HPAs target non-existent deployments.",
213            "Ensure HPA scaleTargetRef references an existing deployment.",
214            "dangling-hpa",
215        )
216        .with_scope(CheckScope::new(&["HorizontalPodAutoscaler"])),
217        CheckSpec::new(
218            "dangling-networkpolicy",
219            "Indicates when network policies have selectors that do not match any pods.",
220            "Ensure network policy pod selectors match labels on pods.",
221            "dangling-network-policy",
222        )
223        .with_scope(CheckScope::new(&["NetworkPolicy"])),
224        CheckSpec::new(
225            "mismatching-selector",
226            "Indicates when deployment selectors do not match pod template labels.",
227            "Ensure deployment selector matches pod template labels.",
228            "mismatching-selector",
229        )
230        .with_scope(CheckScope::new(&["Deployment", "StatefulSet", "DaemonSet"])),
231        CheckSpec::new(
232            "duplicate-env-var",
233            "Indicates when containers have duplicate environment variables.",
234            "Remove duplicate environment variables.",
235            "duplicate-env-var",
236        )
237        .with_scope(CheckScope::new(&["DeploymentLike"])),
238        CheckSpec::new(
239            "invalid-target-ports",
240            "Indicates when services have invalid target ports.",
241            "Ensure service target ports reference valid container ports.",
242            "target-port",
243        )
244        .with_scope(CheckScope::new(&["Service"])),
245        // Additional checks
246        CheckSpec::new(
247            "env-var-secret",
248            "Indicates when secrets are passed as environment variables.",
249            "Mount secrets as volumes instead of environment variables.",
250            "env-var-secret",
251        )
252        .with_scope(CheckScope::new(&["DeploymentLike"])),
253        CheckSpec::new(
254            "read-secret-from-env-var",
255            "Indicates when secrets are read from environment variables.",
256            "Consider mounting secrets as files instead.",
257            "read-secret-from-env-var",
258        )
259        .with_scope(CheckScope::new(&["DeploymentLike"])),
260        CheckSpec::new(
261            "ssh-port",
262            "Indicates when containers expose SSH port (22).",
263            "Avoid exposing SSH ports in containers.",
264            "ssh-port",
265        )
266        .with_scope(CheckScope::new(&["DeploymentLike"])),
267        CheckSpec::new(
268            "privileged-ports",
269            "Indicates when containers use privileged ports (< 1024).",
270            "Use non-privileged ports (>= 1024) when possible.",
271            "privileged-ports",
272        )
273        .with_scope(CheckScope::new(&["DeploymentLike"])),
274        CheckSpec::new(
275            "no-extensions-v1beta",
276            "Indicates when deprecated extensions/v1beta1 API is used.",
277            "Use apps/v1 API instead of extensions/v1beta1.",
278            "disallowed-gvk",
279        )
280        .with_scope(CheckScope::new(&["Any"])),
281        CheckSpec::new(
282            "hpa-minimum-replicas",
283            "Indicates when HPA minReplicas is set too low.",
284            "Set HPA minReplicas to at least 2 for high availability.",
285            "hpa-min-replicas",
286        )
287        .with_scope(CheckScope::new(&["HorizontalPodAutoscaler"])),
288        CheckSpec::new(
289            "liveness-port",
290            "Indicates when liveness probe ports do not match container ports.",
291            "Ensure liveness probe ports match defined container ports.",
292            "liveness-port",
293        )
294        .with_scope(CheckScope::new(&["DeploymentLike"])),
295        CheckSpec::new(
296            "readiness-port",
297            "Indicates when readiness probe ports do not match container ports.",
298            "Ensure readiness probe ports match defined container ports.",
299            "readiness-port",
300        )
301        .with_scope(CheckScope::new(&["DeploymentLike"])),
302        CheckSpec::new(
303            "startup-port",
304            "Indicates when startup probe ports do not match container ports.",
305            "Ensure startup probe ports match defined container ports.",
306            "startup-port",
307        )
308        .with_scope(CheckScope::new(&["DeploymentLike"])),
309        CheckSpec::new(
310            "non-existent-service-account",
311            "Indicates when pods reference non-existent service accounts.",
312            "Create the service account or use an existing one.",
313            "non-existent-service-account",
314        )
315        .with_scope(CheckScope::new(&["DeploymentLike"])),
316        CheckSpec::new(
317            "non-isolated-pod",
318            "Indicates when pods are not covered by any network policy.",
319            "Create network policies to isolate pod traffic.",
320            "non-isolated-pod",
321        )
322        .with_scope(CheckScope::new(&["DeploymentLike"])),
323        CheckSpec::new(
324            "pdb-max-unavailable",
325            "Indicates when PDB maxUnavailable is too permissive.",
326            "Set appropriate maxUnavailable for PodDisruptionBudgets.",
327            "pdb-max-unavailable",
328        )
329        .with_scope(CheckScope::new(&["PodDisruptionBudget"])),
330        CheckSpec::new(
331            "pdb-min-available",
332            "Indicates when PDB minAvailable is too permissive.",
333            "Set appropriate minAvailable for PodDisruptionBudgets.",
334            "pdb-min-available",
335        )
336        .with_scope(CheckScope::new(&["PodDisruptionBudget"])),
337        CheckSpec::new(
338            "required-annotation-email",
339            "Indicates when objects are missing required email annotation.",
340            "Add the required annotation to your resource.",
341            "required-annotation",
342        )
343        .with_scope(CheckScope::new(&["Any"])),
344        CheckSpec::new(
345            "required-label-owner",
346            "Indicates when objects are missing required owner label.",
347            "Add the required label to your resource.",
348            "required-label",
349        )
350        .with_scope(CheckScope::new(&["Any"])),
351        CheckSpec::new(
352            "no-node-affinity",
353            "Indicates when deployments do not have node affinity configured.",
354            "Consider using node affinity to control pod placement.",
355            "node-affinity",
356        )
357        .with_scope(CheckScope::new(&["DeploymentLike"])),
358        CheckSpec::new(
359            "restart-policy",
360            "Indicates when pods have inappropriate restart policies.",
361            "Use an appropriate restart policy for your workload type.",
362            "restart-policy",
363        )
364        .with_scope(CheckScope::new(&["Pod"])),
365        CheckSpec::new(
366            "scc-deny-privileged-container",
367            "Indicates when SecurityContextConstraints allow privileged containers.",
368            "Set allowPrivilegedContainer to false in SCC.",
369            "scc-deny-privileged",
370        )
371        .with_scope(CheckScope::new(&["SecurityContextConstraints"])),
372        CheckSpec::new(
373            "sysctls",
374            "Indicates when pods use unsafe sysctls.",
375            "Avoid using unsafe sysctls in pod specifications.",
376            "sysctls",
377        )
378        .with_scope(CheckScope::new(&["DeploymentLike"])),
379        CheckSpec::new(
380            "use-namespace",
381            "Indicates when objects are in the default namespace.",
382            "Deploy resources to a specific namespace, not default.",
383            "use-namespace",
384        )
385        .with_scope(CheckScope::new(&["Any"])),
386        CheckSpec::new(
387            "dangling-networkpolicypeer-podselector",
388            "Indicates when NetworkPolicy peer pod selectors don't match any pods.",
389            "Ensure NetworkPolicy peer selectors match existing pods.",
390            "dangling-network-policy-peer",
391        )
392        .with_scope(CheckScope::new(&["NetworkPolicy"])),
393        CheckSpec::new(
394            "dangling-servicemonitor",
395            "Indicates when ServiceMonitors have selectors that don't match any services.",
396            "Ensure ServiceMonitor selectors match existing services.",
397            "dangling-service-monitor",
398        )
399        .with_scope(CheckScope::new(&["ServiceMonitor"])),
400        CheckSpec::new(
401            "dnsconfig-options",
402            "Indicates when pods have missing recommended DNS config options.",
403            "Add recommended DNS config options for better reliability.",
404            "dnsconfig-options",
405        )
406        .with_scope(CheckScope::new(&["DeploymentLike"])),
407        CheckSpec::new(
408            "env-var-value-from",
409            "Indicates when env vars reference non-existent secrets or configmaps.",
410            "Ensure env var references point to existing resources.",
411            "env-var-value-from",
412        )
413        .with_scope(CheckScope::new(&["DeploymentLike"])),
414        CheckSpec::new(
415            "job-ttl-seconds-after-finished",
416            "Indicates when jobs don't have ttlSecondsAfterFinished set.",
417            "Set ttlSecondsAfterFinished to automatically clean up completed jobs.",
418            "job-ttl-seconds-after-finished",
419        )
420        .with_scope(CheckScope::new(&["Job"])),
421        CheckSpec::new(
422            "priority-class-name",
423            "Indicates when pods don't have a priorityClassName set.",
424            "Set a priorityClassName for important workloads.",
425            "priority-class-name",
426        )
427        .with_scope(CheckScope::new(&["DeploymentLike"])),
428        CheckSpec::new(
429            "service-type",
430            "Indicates when services use the LoadBalancer type.",
431            "Consider using ClusterIP or NodePort instead of LoadBalancer.",
432            "service-type",
433        )
434        .with_scope(CheckScope::new(&["Service"])),
435        CheckSpec::new(
436            "pdb-unhealthy-pod-eviction-policy",
437            "Indicates when PDB unhealthyPodEvictionPolicy is not configured.",
438            "Set unhealthyPodEvictionPolicy to control eviction behavior.",
439            "pdb-unhealthy-pod-eviction-policy",
440        )
441        .with_scope(CheckScope::new(&["PodDisruptionBudget"])),
442        // Note: schema-validation requires external schema files
443        // Note: sorted-keys is a style check
444    ]
445}
446
447#[cfg(test)]
448mod tests {
449    use super::*;
450
451    #[test]
452    fn test_builtin_checks_count() {
453        let checks = builtin_checks();
454        assert!(
455            checks.len() >= 60,
456            "Expected at least 60 builtin checks, got {}",
457            checks.len()
458        );
459    }
460
461    #[test]
462    fn test_builtin_checks_unique_names() {
463        let checks = builtin_checks();
464        let mut names: Vec<_> = checks.iter().map(|c| &c.name).collect();
465        let original_len = names.len();
466        names.sort();
467        names.dedup();
468        assert_eq!(names.len(), original_len, "Found duplicate check names");
469    }
470}