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 if let Some(proc_mount) = &sc.proc_mount {
50 if proc_mount == "Unmasked" {
51 diagnostics.push(Diagnostic {
52 message: format!(
53 "Container '{}' has unsafe /proc mount (procMount: Unmasked)",
54 container.name
55 ),
56 remediation: Some(
57 "Use the Default procMount type unless Unmasked is absolutely required. \
58 Unmasked proc mount exposes sensitive kernel information."
59 .to_string(),
60 ),
61 });
62 }
63 }
64 }
65 }
66 }
67
68 diagnostics
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use crate::analyzer::kubelint::parser::yaml::parse_yaml;
76
77 #[test]
78 fn test_unsafe_proc_mount_detected() {
79 let yaml = r#"
80apiVersion: apps/v1
81kind: Deployment
82metadata:
83 name: unsafe-procmount
84spec:
85 template:
86 spec:
87 containers:
88 - name: nginx
89 image: nginx:1.21.0
90 securityContext:
91 procMount: Unmasked
92"#;
93 let objects = parse_yaml(yaml).unwrap();
94 let check = UnsafeProcMountCheck;
95 let diagnostics = check.check(&objects[0]);
96 assert_eq!(diagnostics.len(), 1);
97 assert!(diagnostics[0].message.contains("Unmasked"));
98 }
99
100 #[test]
101 fn test_default_proc_mount_ok() {
102 let yaml = r#"
103apiVersion: apps/v1
104kind: Deployment
105metadata:
106 name: safe-procmount
107spec:
108 template:
109 spec:
110 containers:
111 - name: nginx
112 image: nginx:1.21.0
113 securityContext:
114 procMount: Default
115"#;
116 let objects = parse_yaml(yaml).unwrap();
117 let check = UnsafeProcMountCheck;
118 let diagnostics = check.check(&objects[0]);
119 assert!(diagnostics.is_empty());
120 }
121
122 #[test]
123 fn test_no_proc_mount_ok() {
124 let yaml = r#"
125apiVersion: apps/v1
126kind: Deployment
127metadata:
128 name: no-procmount
129spec:
130 template:
131 spec:
132 containers:
133 - name: nginx
134 image: nginx:1.21.0
135"#;
136 let objects = parse_yaml(yaml).unwrap();
137 let check = UnsafeProcMountCheck;
138 let diagnostics = check.check(&objects[0]);
139 assert!(diagnostics.is_empty());
140 }
141}