syncable_cli/analyzer/kubelint/templates/
privileged.rs

1//! Privileged container detection template.
2
3use 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
8/// Template for detecting privileged containers.
9pub struct PrivilegedTemplate;
10
11impl Template for PrivilegedTemplate {
12    fn key(&self) -> &str {
13        "privileged"
14    }
15
16    fn human_name(&self) -> &str {
17        "Privileged Container"
18    }
19
20    fn description(&self) -> &str {
21        "Detects containers running in privileged mode"
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(PrivilegedCheck))
37    }
38}
39
40struct PrivilegedCheck;
41
42impl CheckFunc for PrivilegedCheck {
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                    && sc.privileged == Some(true)
50                {
51                    diagnostics.push(Diagnostic {
52                            message: format!(
53                                "Container '{}' is running in privileged mode",
54                                container.name
55                            ),
56                            remediation: Some(
57                                "Do not run containers in privileged mode unless absolutely necessary. \
58                                 Set securityContext.privileged to false.".to_string()
59                            ),
60                        });
61                }
62            }
63        }
64
65        diagnostics
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use crate::analyzer::kubelint::parser::yaml::parse_yaml;
73
74    #[test]
75    fn test_privileged_container_detected() {
76        let yaml = r#"
77apiVersion: apps/v1
78kind: Deployment
79metadata:
80  name: privileged-deploy
81spec:
82  template:
83    spec:
84      containers:
85      - name: privileged-container
86        image: nginx
87        securityContext:
88          privileged: true
89"#;
90        let objects = parse_yaml(yaml).unwrap();
91        let check = PrivilegedCheck;
92        let diagnostics = check.check(&objects[0]);
93        assert_eq!(diagnostics.len(), 1);
94        assert!(diagnostics[0].message.contains("privileged mode"));
95    }
96
97    #[test]
98    fn test_non_privileged_container_ok() {
99        let yaml = r#"
100apiVersion: apps/v1
101kind: Deployment
102metadata:
103  name: safe-deploy
104spec:
105  template:
106    spec:
107      containers:
108      - name: safe-container
109        image: nginx
110        securityContext:
111          privileged: false
112"#;
113        let objects = parse_yaml(yaml).unwrap();
114        let check = PrivilegedCheck;
115        let diagnostics = check.check(&objects[0]);
116        assert!(diagnostics.is_empty());
117    }
118}