syncable_cli/analyzer/kubelint/templates/
unsafeprocmount.rs1use crate::analyzer::kubelint::context::Object;
4use crate::analyzer::kubelint::extract;
5use crate::analyzer::kubelint::templates::{CheckFunc, ParameterDesc, Template, TemplateError};
6use crate::analyzer::kubelint::types::{Diagnostic, ObjectKindsDesc};
7
8pub struct UnsafeProcMountTemplate;
10
11impl Template for UnsafeProcMountTemplate {
12 fn key(&self) -> &str {
13 "unsafe-proc-mount"
14 }
15
16 fn human_name(&self) -> &str {
17 "Unsafe Proc Mount"
18 }
19
20 fn description(&self) -> &str {
21 "Detects containers with unsafe /proc mount (procMount: Unmasked)"
22 }
23
24 fn supported_object_kinds(&self) -> ObjectKindsDesc {
25 ObjectKindsDesc::default()
26 }
27
28 fn parameters(&self) -> Vec<ParameterDesc> {
29 Vec::new()
30 }
31
32 fn instantiate(
33 &self,
34 _params: &serde_yaml::Value,
35 ) -> Result<Box<dyn CheckFunc>, TemplateError> {
36 Ok(Box::new(UnsafeProcMountCheck))
37 }
38}
39
40struct UnsafeProcMountCheck;
41
42impl CheckFunc for UnsafeProcMountCheck {
43 fn check(&self, object: &Object) -> Vec<Diagnostic> {
44 let mut diagnostics = Vec::new();
45
46 if let Some(pod_spec) = extract::pod_spec::extract_pod_spec(&object.k8s_object) {
47 for container in extract::container::all_containers(pod_spec) {
48 if let Some(sc) = &container.security_context
49 && let Some(proc_mount) = &sc.proc_mount
50 && proc_mount == "Unmasked"
51 {
52 diagnostics.push(Diagnostic {
53 message: format!(
54 "Container '{}' has unsafe /proc mount (procMount: Unmasked)",
55 container.name
56 ),
57 remediation: Some(
58 "Use the Default procMount type unless Unmasked is absolutely required. \
59 Unmasked proc mount exposes sensitive kernel information."
60 .to_string(),
61 ),
62 });
63 }
64 }
65 }
66
67 diagnostics
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::analyzer::kubelint::parser::yaml::parse_yaml;
75
76 #[test]
77 fn test_unsafe_proc_mount_detected() {
78 let yaml = r#"
79apiVersion: apps/v1
80kind: Deployment
81metadata:
82 name: unsafe-procmount
83spec:
84 template:
85 spec:
86 containers:
87 - name: nginx
88 image: nginx:1.21.0
89 securityContext:
90 procMount: Unmasked
91"#;
92 let objects = parse_yaml(yaml).unwrap();
93 let check = UnsafeProcMountCheck;
94 let diagnostics = check.check(&objects[0]);
95 assert_eq!(diagnostics.len(), 1);
96 assert!(diagnostics[0].message.contains("Unmasked"));
97 }
98
99 #[test]
100 fn test_default_proc_mount_ok() {
101 let yaml = r#"
102apiVersion: apps/v1
103kind: Deployment
104metadata:
105 name: safe-procmount
106spec:
107 template:
108 spec:
109 containers:
110 - name: nginx
111 image: nginx:1.21.0
112 securityContext:
113 procMount: Default
114"#;
115 let objects = parse_yaml(yaml).unwrap();
116 let check = UnsafeProcMountCheck;
117 let diagnostics = check.check(&objects[0]);
118 assert!(diagnostics.is_empty());
119 }
120
121 #[test]
122 fn test_no_proc_mount_ok() {
123 let yaml = r#"
124apiVersion: apps/v1
125kind: Deployment
126metadata:
127 name: no-procmount
128spec:
129 template:
130 spec:
131 containers:
132 - name: nginx
133 image: nginx:1.21.0
134"#;
135 let objects = parse_yaml(yaml).unwrap();
136 let check = UnsafeProcMountCheck;
137 let diagnostics = check.check(&objects[0]);
138 assert!(diagnostics.is_empty());
139 }
140}