syncable_cli/analyzer/kubelint/templates/
serviceaccount.rs

1//! Service account detection templates.
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 default service account usage.
9pub struct ServiceAccountTemplate;
10
11impl Template for ServiceAccountTemplate {
12    fn key(&self) -> &str {
13        "service-account"
14    }
15
16    fn human_name(&self) -> &str {
17        "Default Service Account"
18    }
19
20    fn description(&self) -> &str {
21        "Detects pods using the default service account"
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(DefaultServiceAccountCheck))
37    }
38}
39
40struct DefaultServiceAccountCheck;
41
42impl CheckFunc for DefaultServiceAccountCheck {
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            let service_account = pod_spec.service_account_name.as_deref();
48
49            // Check if using default service account or no service account specified
50            if service_account.is_none() || service_account == Some("default") {
51                diagnostics.push(Diagnostic {
52                    message: format!(
53                        "Object '{}' is using the default service account",
54                        object.name()
55                    ),
56                    remediation: Some(
57                        "Create and use a dedicated ServiceAccount with only necessary permissions."
58                            .to_string(),
59                    ),
60                });
61            }
62        }
63
64        diagnostics
65    }
66}
67
68/// Template for detecting deprecated serviceAccount field.
69pub struct DeprecatedServiceAccountFieldTemplate;
70
71impl Template for DeprecatedServiceAccountFieldTemplate {
72    fn key(&self) -> &str {
73        "deprecated-service-account-field"
74    }
75
76    fn human_name(&self) -> &str {
77        "Deprecated Service Account Field"
78    }
79
80    fn description(&self) -> &str {
81        "Detects use of the deprecated serviceAccount field instead of serviceAccountName"
82    }
83
84    fn supported_object_kinds(&self) -> ObjectKindsDesc {
85        ObjectKindsDesc::default()
86    }
87
88    fn parameters(&self) -> Vec<ParameterDesc> {
89        Vec::new()
90    }
91
92    fn instantiate(
93        &self,
94        _params: &serde_yaml::Value,
95    ) -> Result<Box<dyn CheckFunc>, TemplateError> {
96        // Note: This check is a placeholder - the current parser doesn't distinguish
97        // between serviceAccount and serviceAccountName fields
98        Ok(Box::new(DeprecatedServiceAccountFieldCheck))
99    }
100}
101
102struct DeprecatedServiceAccountFieldCheck;
103
104impl CheckFunc for DeprecatedServiceAccountFieldCheck {
105    fn check(&self, _object: &Object) -> Vec<Diagnostic> {
106        // Note: The current YAML parser unifies serviceAccount and serviceAccountName
107        // into service_account_name, so we can't detect the deprecated field usage.
108        // This would require raw YAML inspection to implement properly.
109        Vec::new()
110    }
111}