google-site-verification: google61fe8ba583a51912.html
Kube-Score Analysis in Java: Complete Implementation Guide

kube-score is a tool that performs static code analysis of Kubernetes manifests to improve reliability and security. This guide provides a complete Java implementation for analyzing Kubernetes YAML files.


Kube-Score Overview

What is Kube-Score?

  • Static analysis tool for Kubernetes manifests
  • Checks for security, reliability, and best practices
  • Provides actionable recommendations
  • Supports various resource types (Deployments, Services, etc.)

Key Checks:

  • Container security context
  • Resource requests and limits
  • Pod disruption budgets
  • Network policies
  • Liveness/readiness probes

Dependencies and Setup

Maven Dependencies
<properties> <spring-boot.version>3.1.0</spring-boot.version> <snakeyaml.version>2.0</snakeyaml.version> <kubernetes-client.version>6.7.2</kubernetes-client.version> <jackson.version>2.15.2</jackson.version> </properties> <dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>${spring-boot.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> <version>${spring-boot.version}</version> </dependency> <!-- YAML Processing --> <dependency> <groupId>org.yaml</groupId> <artifactId>snakeyaml</artifactId> <version>${snakeyaml.version}</version> </dependency> <!-- Kubernetes Client --> <dependency> <groupId>io.kubernetes</groupId> <artifactId>client-java</artifactId> <version>${kubernetes-client.version}</version> </dependency> <!-- JSON Processing --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-yaml</artifactId> <version>${jackson.version}</version> </dependency> <!-- Utilities --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <!-- Testing --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>${spring-boot.version}</version> <scope>test</scope> </dependency> </dependencies>
Application Configuration
# application.yml app: kube-score: # Severity levels: CRITICAL, WARNING, INFO min-severity: WARNING # Enable/disable specific checks checks: container-security-context: true resource-requests-limits: true pod-disruption-budget: true network-policy: true liveness-readiness-probes: true topology-spread-constraints: true # Custom scoring weights scoring: critical: 10 warning: 5 info: 1 server: port: 8080 logging: level: com.example.kubescore: DEBUG

Core Models

1. Analysis Models
// KubeScoreRequest.java package com.example.kubescore.model; import lombok.Data; import org.springframework.web.multipart.MultipartFile; import jakarta.validation.constraints.NotNull; import java.util.Map; @Data public class KubeScoreRequest { @NotNull(message = "Kubernetes manifest is required") private MultipartFile manifest; private AnalysisOptions options = new AnalysisOptions(); @Data public static class AnalysisOptions { private Severity minSeverity = Severity.WARNING; private boolean enableAllChecks = true; private Map<String, Boolean> enabledChecks; private boolean ignoreTestPods = true; private String outputFormat = "json"; } } // KubeScoreResponse.java package com.example.kubescore.model; import lombok.Data; import lombok.Builder; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @Data @Builder public class KubeScoreResponse { private boolean success; private String message; private LocalDateTime timestamp; private AnalysisSummary summary; private List<CheckResult> results; private String rawOutput; @Data @Builder public static class AnalysisSummary { private int totalChecks; private int criticalIssues; private int warnings; private int infoIssues; private int passedChecks; private double score; private String grade; } } // CheckResult.java package com.example.kubescore.model; import lombok.Data; import lombok.Builder; @Data @Builder public class CheckResult { private String checkName; private String checkType; private Severity severity; private String message; private String resourceType; private String resourceName; private String namespace; private String comment; private List<String> suggestions; private String documentationUrl; public boolean isCritical() { return severity == Severity.CRITICAL; } public boolean isWarning() { return severity == Severity.WARNING; } public boolean isInfo() { return severity == Severity.INFO; } } // Severity.java package com.example.kubescore.model; public enum Severity { CRITICAL, WARNING, INFO, OK }
2. Kubernetes Resource Models
// KubernetesResource.java package com.example.kubescore.model; import lombok.Data; import java.util.Map; @Data public class KubernetesResource { private String apiVersion; private String kind; private Metadata metadata; private Map<String, Object> spec; @Data public static class Metadata { private String name; private String namespace; private Map<String, String> labels; private Map<String, String> annotations; } } // ContainerSpec.java package com.example.kubescore.model; import lombok.Data; import java.util.List; import java.util.Map; @Data public class ContainerSpec { private String name; private String image; private List<String> command; private List<String> args; private List<EnvVar> env; private List<VolumeMount> volumeMounts; private ResourceRequirements resources; private SecurityContext securityContext; private Probe livenessProbe; private Probe readinessProbe; private Probe startupProbe; @Data public static class EnvVar { private String name; private String value; private EnvVarSource valueFrom; } @Data public static class EnvVarSource { private ConfigMapKeySelector configMapKeyRef; private SecretKeySelector secretKeyRef; private FieldRef fieldRef; private ResourceFieldRef resourceFieldRef; } @Data public static class ConfigMapKeySelector { private String name; private String key; } @Data public static class SecretKeySelector { private String name; private String key; } @Data public static class FieldRef { private String fieldPath; } @Data public static class ResourceFieldRef { private String resource; } @Data public static class VolumeMount { private String name; private String mountPath; private boolean readOnly; } } // ResourceRequirements.java package com.example.kubescore.model; import lombok.Data; import java.util.Map; @Data public class ResourceRequirements { private Map<String, String> requests; private Map<String, String> limits; public boolean hasRequests() { return requests != null && !requests.isEmpty(); } public boolean hasLimits() { return limits != null && !limits.isEmpty(); } public boolean hasCpuRequests() { return hasRequests() && requests.containsKey("cpu"); } public boolean hasMemoryRequests() { return hasRequests() && requests.containsKey("memory"); } public boolean hasCpuLimits() { return hasLimits() && limits.containsKey("cpu"); } public boolean hasMemoryLimits() { return hasLimits() && limits.containsKey("memory"); } } // SecurityContext.java package com.example.kubescore.model; import lombok.Data; @Data public class SecurityContext { private Boolean runAsNonRoot; private Long runAsUser; private Long runAsGroup; private Boolean readOnlyRootFilesystem; private Boolean allowPrivilegeEscalation; private Capabilities capabilities; private SeLinuxOptions seLinuxOptions; private SeccompProfile seccompProfile; @Data public static class Capabilities { private java.util.List<String> add; private java.util.List<String> drop; } @Data public static class SeLinuxOptions { private String level; } @Data public static class SeccompProfile { private String type; } } // Probe.java package com.example.kubescore.model; import lombok.Data; @Data public class Probe { private ExecAction exec; private HttpGetAction httpGet; private TcpSocketAction tcpSocket; private int initialDelaySeconds; private int periodSeconds; private int timeoutSeconds; private int successThreshold; private int failureThreshold; @Data public static class ExecAction { private java.util.List<String> command; } @Data public static class HttpGetAction { private String path; private int port; private String scheme; private java.util.Map<String, String> httpHeaders; } @Data public static class TcpSocketAction { private int port; } }

Analysis Checks

1. Base Check Interface
// ResourceCheck.java package com.example.kubescore.checks; import com.example.kubescore.model.CheckResult; import com.example.kubescore.model.KubernetesResource; import java.util.List; public interface ResourceCheck { String getName(); String getDescription(); List<String> getSupportedResourceTypes(); List<CheckResult> check(KubernetesResource resource); boolean isEnabled(); }
2. Container Security Context Check
// ContainerSecurityContextCheck.java package com.example.kubescore.checks; import com.example.kubescore.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Map; @Slf4j @Component public class ContainerSecurityContextCheck implements ResourceCheck { @Override public String getName() { return "container-security-context"; } @Override public String getDescription() { return "Checks container security context settings"; } @Override public List<String> getSupportedResourceTypes() { return List.of("Deployment", "StatefulSet", "DaemonSet", "Pod", "ReplicaSet", "CronJob", "Job"); } @Override public List<CheckResult> check(KubernetesResource resource) { List<CheckResult> results = new ArrayList<>(); try { Map<String, Object> spec = resource.getSpec(); if (spec == null) return results; // Extract containers from different resource types List<Map<String, Object>> containers = extractContainers(resource); if (containers == null || containers.isEmpty()) return results; for (Map<String, Object> container : containers) { String containerName = (String) container.get("name"); checkContainerSecurityContext(resource, containerName, container, results); } } catch (Exception e) { log.error("Error checking security context for resource: {}", resource.getMetadata().getName(), e); } return results; } private void checkContainerSecurityContext(KubernetesResource resource, String containerName, Map<String, Object> container, List<CheckResult> results) { Map<String, Object> securityContext = (Map<String, Object>) container.get("securityContext"); String resourceName = resource.getMetadata().getName(); String resourceType = resource.getKind(); // Check if security context is set if (securityContext == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Security") .severity(Severity.CRITICAL) .message("Container is missing security context") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Add securityContext to container specification", "Set runAsNonRoot to true", "Set readOnlyRootFilesystem to true", "Drop all capabilities and add only required ones" )) .documentationUrl("https://kubernetes.io/docs/concepts/security/security-context/") .build()); return; } // Check runAsNonRoot Boolean runAsNonRoot = (Boolean) securityContext.get("runAsNonRoot"); if (runAsNonRoot == null || !runAsNonRoot) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Security") .severity(Severity.CRITICAL) .message("Container should run as non-root user") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Set runAsNonRoot to true in securityContext")) .build()); } // Check readOnlyRootFilesystem Boolean readOnlyRootFilesystem = (Boolean) securityContext.get("readOnlyRootFilesystem"); if (readOnlyRootFilesystem == null || !readOnlyRootFilesystem) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Security") .severity(Severity.WARNING) .message("Container should use read-only root filesystem") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Set readOnlyRootFilesystem to true in securityContext")) .build()); } // Check allowPrivilegeEscalation Boolean allowPrivilegeEscalation = (Boolean) securityContext.get("allowPrivilegeEscalation"); if (allowPrivilegeEscalation == null || allowPrivilegeEscalation) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Security") .severity(Severity.CRITICAL) .message("Container should not allow privilege escalation") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Set allowPrivilegeEscalation to false in securityContext")) .build()); } // Check capabilities Map<String, Object> capabilities = (Map<String, Object>) securityContext.get("capabilities"); if (capabilities != null) { List<String> addCapabilities = (List<String>) capabilities.get("add"); if (addCapabilities != null && !addCapabilities.isEmpty()) { if (addCapabilities.contains("ALL")) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Security") .severity(Severity.CRITICAL) .message("Container should not have ALL capabilities") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Drop ALL capabilities and add only required ones")) .build()); } // Check for dangerous capabilities List<String> dangerousCaps = List.of("SYS_ADMIN", "NET_ADMIN", "SYS_PTRACE", "SYS_MODULE"); for (String cap : dangerousCaps) { if (addCapabilities.contains(cap)) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Security") .severity(Severity.WARNING) .message("Container has dangerous capability: " + cap) .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Remove capability " + cap + " unless absolutely necessary")) .build()); } } } } } @SuppressWarnings("unchecked") private List<Map<String, Object>> extractContainers(KubernetesResource resource) { Map<String, Object> spec = resource.getSpec(); if (spec == null) return null; // Handle different resource types switch (resource.getKind()) { case "Pod": return (List<Map<String, Object>>) spec.get("containers"); case "Deployment": case "StatefulSet": case "DaemonSet": case "ReplicaSet": Map<String, Object> template = (Map<String, Object>) spec.get("template"); if (template != null) { Map<String, Object> podSpec = (Map<String, Object>) template.get("spec"); return podSpec != null ? (List<Map<String, Object>>) podSpec.get("containers") : null; } break; case "CronJob": Map<String, Object> jobTemplate = (Map<String, Object>) spec.get("jobTemplate"); if (jobTemplate != null) { Map<String, Object> jobSpec = (Map<String, Object>) jobTemplate.get("spec"); if (jobSpec != null) { Map<String, Object> podTemplate = (Map<String, Object>) jobSpec.get("template"); if (podTemplate != null) { Map<String, Object> podSpec = (Map<String, Object>) podTemplate.get("spec"); return podSpec != null ? (List<Map<String, Object>>) podSpec.get("containers") : null; } } } break; case "Job": Map<String, Object> jobSpec = (Map<String, Object>) spec.get("spec"); if (jobSpec != null) { Map<String, Object> podTemplate = (Map<String, Object>) jobSpec.get("template"); if (podTemplate != null) { Map<String, Object> podSpec = (Map<String, Object>) podTemplate.get("spec"); return podSpec != null ? (List<Map<String, Object>>) podSpec.get("containers") : null; } } break; } return null; } @Override public boolean isEnabled() { return true; } }
3. Resource Requests and Limits Check
// ResourceRequestsLimitsCheck.java package com.example.kubescore.checks; import com.example.kubescore.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Map; @Slf4j @Component public class ResourceRequestsLimitsCheck implements ResourceCheck { @Override public String getName() { return "resource-requests-limits"; } @Override public String getDescription() { return "Checks resource requests and limits configuration"; } @Override public List<String> getSupportedResourceTypes() { return List.of("Deployment", "StatefulSet", "DaemonSet", "Pod", "ReplicaSet", "CronJob", "Job"); } @Override public List<CheckResult> check(KubernetesResource resource) { List<CheckResult> results = new ArrayList<>(); try { List<Map<String, Object>> containers = extractContainers(resource); if (containers == null || containers.isEmpty()) return results; for (Map<String, Object> container : containers) { String containerName = (String) container.get("name"); checkContainerResources(resource, containerName, container, results); } } catch (Exception e) { log.error("Error checking resources for resource: {}", resource.getMetadata().getName(), e); } return results; } @SuppressWarnings("unchecked") private void checkContainerResources(KubernetesResource resource, String containerName, Map<String, Object> container, List<CheckResult> results) { Map<String, Object> resources = (Map<String, Object>) container.get("resources"); String resourceName = resource.getMetadata().getName(); String resourceType = resource.getKind(); if (resources == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.CRITICAL) .message("Container is missing resource requests and limits") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Add resource requests and limits to container specification", "Set CPU and memory requests based on application requirements", "Set CPU and memory limits to prevent resource exhaustion" )) .documentationUrl("https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/") .build()); return; } Map<String, String> requests = (Map<String, String>) resources.get("requests"); Map<String, String> limits = (Map<String, String>) resources.get("limits"); // Check requests if (requests == null || requests.isEmpty()) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.CRITICAL) .message("Container is missing resource requests") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Add CPU and memory requests to container specification")) .build()); } else { if (!requests.containsKey("cpu")) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container is missing CPU requests") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Add CPU requests to container specification")) .build()); } if (!requests.containsKey("memory")) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container is missing memory requests") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Add memory requests to container specification")) .build()); } } // Check limits if (limits == null || limits.isEmpty()) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container is missing resource limits") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Add CPU and memory limits to container specification")) .build()); } else { if (!limits.containsKey("cpu")) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container is missing CPU limits") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Add CPU limits to container specification")) .build()); } if (!limits.containsKey("memory")) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container is missing memory limits") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Add memory limits to container specification")) .build()); } } // Validate resource values if (requests != null) { validateResourceValues(resource, containerName, "requests", requests, results); } if (limits != null) { validateResourceValues(resource, containerName, "limits", limits, results); } } private void validateResourceValues(KubernetesResource resource, String containerName, String resourceType, Map<String, String> values, List<CheckResult> results) { String resourceName = resource.getMetadata().getName(); String kind = resource.getKind(); for (Map.Entry<String, String> entry : values.entrySet()) { String resourceNameKey = entry.getKey(); String value = entry.getValue(); if (value == null || value.trim().isEmpty()) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container has empty " + resourceNameKey + " " + resourceType) .resourceType(kind) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Set a valid value for " + resourceNameKey + " " + resourceType)) .build()); } // Validate CPU format if ("cpu".equals(resourceNameKey)) { if (!isValidCpuValue(value)) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container has invalid CPU " + resourceType + " value: " + value) .resourceType(kind) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Use valid CPU values: millicores (e.g., 100m, 500m) or cores (e.g., 0.5, 1, 2)" )) .build()); } } // Validate memory format if ("memory".equals(resourceNameKey)) { if (!isValidMemoryValue(value)) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Resources") .severity(Severity.WARNING) .message("Container has invalid memory " + resourceType + " value: " + value) .resourceType(kind) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Use valid memory values: KiB (e.g., 64Ki), MiB (e.g., 128Mi), GiB (e.g., 1Gi)" )) .build()); } } } } private boolean isValidCpuValue(String value) { if (value == null) return false; return value.matches("^[0-9]+m$") || // millicores: 100m, 500m value.matches("^[0-9]+(\\.[0-9]+)?$"); // cores: 0.5, 1, 2 } private boolean isValidMemoryValue(String value) { if (value == null) return false; return value.matches("^[0-9]+(\\.[0-9]+)?[KMGTPE]i?$") || // KiB, MiB, GiB, etc. value.matches("^[0-9]+(\\.[0-9]+)?[KMGTPE]?$"); // K, M, G, etc. } @SuppressWarnings("unchecked") private List<Map<String, Object>> extractContainers(KubernetesResource resource) { // Same implementation as in ContainerSecurityContextCheck Map<String, Object> spec = resource.getSpec(); if (spec == null) return null; switch (resource.getKind()) { case "Pod": return (List<Map<String, Object>>) spec.get("containers"); case "Deployment": case "StatefulSet": case "DaemonSet": case "ReplicaSet": Map<String, Object> template = (Map<String, Object>) spec.get("template"); if (template != null) { Map<String, Object> podSpec = (Map<String, Object>) template.get("spec"); return podSpec != null ? (List<Map<String, Object>>) podSpec.get("containers") : null; } break; // ... other resource types } return null; } @Override public boolean isEnabled() { return true; } }
4. Liveness and Readiness Probes Check
// ProbeCheck.java package com.example.kubescore.checks; import com.example.kubescore.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; import java.util.Map; @Slf4j @Component public class ProbeCheck implements ResourceCheck { @Override public String getName() { return "liveness-readiness-probes"; } @Override public String getDescription() { return "Checks liveness and readiness probes configuration"; } @Override public List<String> getSupportedResourceTypes() { return List.of("Deployment", "StatefulSet", "DaemonSet", "Pod", "ReplicaSet"); } @Override public List<CheckResult> check(KubernetesResource resource) { List<CheckResult> results = new ArrayList<>(); try { List<Map<String, Object>> containers = extractContainers(resource); if (containers == null || containers.isEmpty()) return results; for (Map<String, Object> container : containers) { String containerName = (String) container.get("name"); checkContainerProbes(resource, containerName, container, results); } } catch (Exception e) { log.error("Error checking probes for resource: {}", resource.getMetadata().getName(), e); } return results; } @SuppressWarnings("unchecked") private void checkContainerProbes(KubernetesResource resource, String containerName, Map<String, Object> container, List<CheckResult> results) { Map<String, Object> livenessProbe = (Map<String, Object>) container.get("livenessProbe"); Map<String, Object> readinessProbe = (Map<String, Object>) container.get("readinessProbe"); String resourceName = resource.getMetadata().getName(); String resourceType = resource.getKind(); // Check liveness probe if (livenessProbe == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.WARNING) .message("Container is missing liveness probe") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Add liveness probe to detect and restart unhealthy containers", "Use HTTP GET, TCP socket, or command execution for health checks" )) .documentationUrl("https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/") .build()); } else { validateProbeConfiguration(resource, containerName, "liveness", livenessProbe, results); } // Check readiness probe if (readinessProbe == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.WARNING) .message("Container is missing readiness probe") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Add readiness probe to control traffic to the container", "Use HTTP GET, TCP socket, or command execution for readiness checks" )) .build()); } else { validateProbeConfiguration(resource, containerName, "readiness", readinessProbe, results); } // Check for startup probe (optional but recommended for slow-starting containers) Map<String, Object> startupProbe = (Map<String, Object>) container.get("startupProbe"); if (startupProbe == null) { // Only suggest startup probe if the app has long initialization results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.INFO) .message("Consider adding startup probe for slow-starting containers") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Add startup probe for applications with long initialization times", "Startup probe prevents killing containers during startup" )) .build()); } } private void validateProbeConfiguration(KubernetesResource resource, String containerName, String probeType, Map<String, Object> probe, List<CheckResult> results) { String resourceName = resource.getMetadata().getName(); String resourceType = resource.getKind(); // Check probe type boolean hasHttpGet = probe.containsKey("httpGet"); boolean hasTcpSocket = probe.containsKey("tcpSocket"); boolean hasExec = probe.containsKey("exec"); if (!hasHttpGet && !hasTcpSocket && !hasExec) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.WARNING) .message(probeType + " probe is missing action configuration") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Configure HTTP GET, TCP socket, or command execution for the probe" )) .build()); } // Check initial delay Integer initialDelaySeconds = (Integer) probe.get("initialDelaySeconds"); if (initialDelaySeconds == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.INFO) .message(probeType + " probe is missing initial delay") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of( "Set initialDelaySeconds to account for application startup time" )) .build()); } // Check period seconds Integer periodSeconds = (Integer) probe.get("periodSeconds"); if (periodSeconds == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.INFO) .message(probeType + " probe is missing period configuration") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Set periodSeconds to configure probe frequency")) .build()); } else if (periodSeconds < 1) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.WARNING) .message(probeType + " probe has very short period: " + periodSeconds + "s") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Increase periodSeconds to reduce probe frequency")) .build()); } // Check timeout Integer timeoutSeconds = (Integer) probe.get("timeoutSeconds"); if (timeoutSeconds == null) { results.add(CheckResult.builder() .checkName(getName()) .checkType("Health") .severity(Severity.INFO) .message(probeType + " probe is missing timeout configuration") .resourceType(resourceType) .resourceName(resourceName) .comment("Container: " + containerName) .suggestions(List.of("Set timeoutSeconds for probe execution")) .build()); } } @SuppressWarnings("unchecked") private List<Map<String, Object>> extractContainers(KubernetesResource resource) { // Same implementation as previous checks Map<String, Object> spec = resource.getSpec(); if (spec == null) return null; switch (resource.getKind()) { case "Pod": return (List<Map<String, Object>>) spec.get("containers"); case "Deployment": case "StatefulSet": case "DaemonSet": case "ReplicaSet": Map<String, Object> template = (Map<String, Object>) spec.get("template"); if (template != null) { Map<String, Object> podSpec = (Map<String, Object>) template.get("spec"); return podSpec != null ? (List<Map<String, Object>>) podSpec.get("containers") : null; } break; } return null; } @Override public boolean isEnabled() { return true; } }

YAML Parser and Resource Extractor

// KubernetesManifestParser.java package com.example.kubescore.service; import com.example.kubescore.model.KubernetesResource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import java.util.Map; @Slf4j @Service public class KubernetesManifestParser { private final Yaml yaml; public KubernetesManifestParser() { this.yaml = new Yaml(new SafeConstructor()); } /** * Parse Kubernetes manifest from input stream */ public List<KubernetesResource> parseManifest(InputStream inputStream) { List<KubernetesResource> resources = new ArrayList<>(); try { Iterable<Object> documents = yaml.loadAll(inputStream); for (Object document : documents) { if (document instanceof Map) { @SuppressWarnings("unchecked") Map<String, Object> resourceMap = (Map<String, Object>) document; KubernetesResource resource = mapToKubernetesResource(resourceMap); if (resource != null) { resources.add(resource); } } } log.info("Parsed {} Kubernetes resources from manifest", resources.size()); } catch (Exception e) { log.error("Error parsing Kubernetes manifest", e); throw new ManifestParseException("Failed to parse Kubernetes manifest", e); } return resources; } /** * Convert YAML map to KubernetesResource object */ @SuppressWarnings("unchecked") private KubernetesResource mapToKubernetesResource(Map<String, Object> resourceMap) { KubernetesResource resource = new KubernetesResource(); try { // Set basic properties resource.setApiVersion((String) resourceMap.get("apiVersion")); resource.setKind((String) resourceMap.get("kind")); // Set metadata Map<String, Object> metadata = (Map<String, Object>) resourceMap.get("metadata"); if (metadata != null) { KubernetesResource.Metadata resourceMetadata = new KubernetesResource.Metadata(); resourceMetadata.setName((String) metadata.get("name")); resourceMetadata.setNamespace((String) metadata.get("namespace")); resourceMetadata.setLabels((Map<String, String>) metadata.get("labels")); resourceMetadata.setAnnotations((Map<String, String>) metadata.get("annotations")); resource.setMetadata(resourceMetadata); } // Set spec resource.setSpec((Map<String, Object>) resourceMap.get("spec")); // Validate required fields if (resource.getKind() == null || resource.getApiVersion() == null || resource.getMetadata() == null || resource.getMetadata().getName() == null) { log.warn("Skipping invalid Kubernetes resource: missing required fields"); return null; } return resource; } catch (Exception e) { log.warn("Error mapping Kubernetes resource", e); return null; } } /** * Validate Kubernetes resource kind */ public boolean isValidResourceKind(String kind) { if (kind == null) return false; List<String> supportedKinds = List.of( "Pod", "Deployment", "StatefulSet", "DaemonSet", "ReplicaSet", "Service", "ConfigMap", "Secret", "PersistentVolume", "PersistentVolumeClaim", "ServiceAccount", "Role", "RoleBinding", "ClusterRole", "ClusterRoleBinding", "Ingress", "NetworkPolicy", "PodDisruptionBudget", "CronJob", "Job", "HorizontalPodAutoscaler", "VerticalPodAutoscaler" ); return supportedKinds.contains(kind); } public static class ManifestParseException extends RuntimeException { public ManifestParseException(String message) { super(message); } public ManifestParseException(String message, Throwable cause) { super(message, cause); } } }

Main Analysis Service

// KubeScoreService.java package com.example.kubescore.service; import com.example.kubescore.checks.ResourceCheck; import com.example.kubescore.model.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.io.InputStream; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @Slf4j @Service public class KubeScoreService { private final KubernetesManifestParser manifestParser; private final List<ResourceCheck> resourceChecks; public KubeScoreService(KubernetesManifestParser manifestParser, List<ResourceCheck> resourceChecks) { this.manifestParser = manifestParser; this.resourceChecks = resourceChecks; } /** * Analyze Kubernetes manifest */ public KubeScoreResponse analyzeManifest(KubeScoreRequest request) { log.info("Starting kube-score analysis"); try (InputStream inputStream = request.getManifest().getInputStream()) { // Parse Kubernetes manifest List<KubernetesResource> resources = manifestParser.parseManifest(inputStream); if (resources.isEmpty()) { return KubeScoreResponse.builder() .success(false) .message("No valid Kubernetes resources found in manifest") .timestamp(LocalDateTime.now()) .build(); } // Perform analysis List<CheckResult> allResults = new ArrayList<>(); for (KubernetesResource resource : resources) { List<CheckResult> resourceResults = analyzeResource(resource, request.getOptions()); allResults.addAll(resourceResults); } // Filter by severity List<CheckResult> filteredResults = filterResultsBySeverity( allResults, request.getOptions().getMinSeverity() ); // Generate summary AnalysisSummary summary = generateSummary(filteredResults); log.info("Kube-score analysis completed: {} issues found", filteredResults.size()); return KubeScoreResponse.builder() .success(true) .message("Analysis completed successfully") .timestamp(LocalDateTime.now()) .summary(summary) .results(filteredResults) .build(); } catch (Exception e) { log.error("Kube-score analysis failed", e); return KubeScoreResponse.builder() .success(false) .message("Analysis failed: " + e.getMessage()) .timestamp(LocalDateTime.now()) .build(); } } /** * Analyze single Kubernetes resource */ private List<CheckResult> analyzeResource(KubernetesResource resource, KubeScoreRequest.AnalysisOptions options) { List<CheckResult> results = new ArrayList<>(); // Skip test pods if configured if (options.isIgnoreTestPods() && isTestPod(resource)) { log.debug("Skipping test pod: {}", resource.getMetadata().getName()); return results; } // Run all applicable checks for (ResourceCheck check : resourceChecks) { if (check.isEnabled() && isCheckApplicable(check, resource)) { try { List<CheckResult> checkResults = check.check(resource); results.addAll(checkResults); } catch (Exception e) { log.error("Check {} failed for resource {}", check.getName(), resource.getMetadata().getName(), e); } } } return results; } /** * Check if a check is applicable to the resource */ private boolean isCheckApplicable(ResourceCheck check, KubernetesResource resource) { return check.getSupportedResourceTypes().contains(resource.getKind()); } /** * Check if resource is a test pod */ private boolean isTestPod(KubernetesResource resource) { if (!"Pod".equals(resource.getKind())) { return false; } KubernetesResource.Metadata metadata = resource.getMetadata(); if (metadata == null) { return false; } String name = metadata.getName(); Map<String, String> labels = metadata.getLabels(); // Common test pod patterns if (name != null && (name.contains("test") || name.contains("debug"))) { return true; } if (labels != null) { return labels.keySet().stream() .anyMatch(key -> key.contains("test") || key.contains("debug")); } return false; } /** * Filter results by minimum severity */ private List<CheckResult> filterResultsBySeverity(List<CheckResult> results, Severity minSeverity) { return results.stream() .filter(result -> { switch (minSeverity) { case CRITICAL: return result.isCritical(); case WARNING: return result.isCritical() || result.isWarning(); case INFO: return true; // Include all default: return true; } }) .collect(Collectors.toList()); } /** * Generate analysis summary */ private AnalysisSummary generateSummary(List<CheckResult> results) { int critical = (int) results.stream().filter(CheckResult::isCritical).count(); int warnings = (int) results.stream().filter(CheckResult::isWarning).count(); int info = (int) results.stream().filter(CheckResult::isInfo).count(); int total = results.size(); // Calculate score (0-100) double score = calculateScore(results); String grade = calculateGrade(score); return AnalysisSummary.builder() .totalChecks(total) .criticalIssues(critical) .warnings(warnings) .infoIssues(info) .passedChecks(0) // This would require tracking passed checks .score(score) .grade(grade) .build(); } /** * Calculate overall score (0-100) */ private double calculateScore(List<CheckResult> results) { if (results.isEmpty()) { return 100.0; } // Weighted scoring based on severity double totalWeight = 0; double score = 100; for (CheckResult result : results) { double weight = getSeverityWeight(result.getSeverity()); totalWeight += weight; score -= weight; } // Ensure score doesn't go below 0 return Math.max(0, score); } private double getSeverityWeight(Severity severity) { switch (severity) { case CRITICAL: return 10.0; case WARNING: return 5.0; case INFO: return 1.0; default: return 0.0; } } private String calculateGrade(double score) { if (score >= 90) return "A"; if (score >= 80) return "B"; if (score >= 70) return "C"; if (score >= 60) return "D"; return "F"; } /** * Get analysis report in different formats */ public String generateReport(KubeScoreResponse response, String format) { switch (format.toLowerCase()) { case "json": return generateJsonReport(response); case "yaml": return generateYamlReport(response); case "html": return generateHtmlReport(response); case "text": default: return generateTextReport(response); } } private String generateTextReport(KubeScoreResponse response) { StringBuilder report = new StringBuilder(); AnalysisSummary summary = response.getSummary(); report.append("Kube-Score Analysis Report\n"); report.append("==========================\n\n"); report.append(String.format("Overall Score: %.1f/100 (%s)\n", summary.getScore(), summary.getGrade())); report.append(String.format("Critical Issues: %d\n", summary.getCriticalIssues())); report.append(String.format("Warnings: %d\n", summary.getWarnings())); report.append(String.format("Info Issues: %d\n\n", summary.getInfoIssues())); // Group by resource response.getResults().stream() .collect(Collectors.groupingBy(CheckResult::getResourceType)) .forEach((resourceType, results) -> { report.append(resourceType).append(":\n"); results.forEach(result -> { report.append(String.format(" [%s] %s: %s\n", result.getSeverity(), result.getResourceName(), result.getMessage())); }); report.append("\n"); }); return report.toString(); } private String generateJsonReport(KubeScoreResponse response) { // Use Jackson ObjectMapper for JSON serialization try { com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(response); } catch (Exception e) { log.error("Error generating JSON report", e); return "{\"error\": \"Failed to generate JSON report\"}"; } } private String generateYamlReport(KubeScoreResponse response) { // Use SnakeYAML for YAML serialization try { org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml(); return yaml.dump(response); } catch (Exception e) { log.error("Error generating YAML report", e); return "error: Failed to generate YAML report"; } } private String generateHtmlReport(KubeScoreResponse response) { // Simple HTML report generation StringBuilder html = new StringBuilder(); html.append(""" <!DOCTYPE html> <html> <head> <title>Kube-Score Analysis Report</title> <style> body { font-family: Arial, sans-serif; margin: 20px; } .critical { color: #d73a49; font-weight: bold; } .warning { color: #f66a0a; } .info { color: #0366d6; } .score { font-size: 24px; font-weight: bold; } .grade-A { color: #28a745; } .grade-B { color: #17a2b8; } .grade-C { color: #ffc107; } .grade-D { color: #fd7e14; } .grade-F { color: #dc3545; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #ddd; padding: 8px; text-align: left; } th { background-color: #f2f2f2; } </style> </head> <body> <h1>Kube-Score Analysis Report</h1> """); AnalysisSummary summary = response.getSummary(); html.append(String.format(""" <div class="score grade-%s">Overall Score: %.1f/100 (%s)</div> <p>Critical Issues: %d | Warnings: %d | Info Issues: %d</p> """, summary.getGrade(), summary.getScore(), summary.getGrade(), summary.getCriticalIssues(), summary.getWarnings(), summary.getInfoIssues())); html.append("<table><tr><th>Severity</th><th>Resource</th><th>Message</th><th>Suggestions</th></tr>"); for (CheckResult result : response.getResults()) { String severityClass = result.getSeverity().name().toLowerCase(); String suggestions = result.getSuggestions() != null ? String.join("<br>", result.getSuggestions()) : ""; html.append(String.format(""" <tr class="%s"> <td>%s</td> <td>%s/%s</td> <td>%s</td> <td>%s</td> </tr> """, severityClass, result.getSeverity(), result.getResourceType(), result.getResourceName(), result.getMessage(), suggestions)); } html.append("</table></body></html>"); return html.toString(); } }

REST Controller

// KubeScoreController.java package com.example.kubescore.controller; import com.example.kubescore.model.KubeScoreRequest; import com.example.kubescore.model.KubeScoreResponse; import com.example.kubescore.service.KubeScoreService; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.Map; @Slf4j @RestController @RequestMapping("/api/kube-score") public class KubeScoreController { private final KubeScoreService kubeScoreService; public KubeScoreController(KubeScoreService kubeScoreService) { this.kubeScoreService = kubeScoreService; } @PostMapping(value = "/analyze", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<KubeScoreResponse> analyzeManifest(@ModelAttribute KubeScoreRequest request) { log.info("Received kube-score analysis request"); try { KubeScoreResponse response = kubeScoreService.analyzeManifest(request); return ResponseEntity.ok(response); } catch (Exception e) { log.error("Analysis request failed", e); return ResponseEntity.badRequest().body( KubeScoreResponse.builder() .success(false) .message("Analysis failed: " + e.getMessage()) .build() ); } } @PostMapping(value = "/analyze/file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity<Map<String, Object>> analyzeManifestFile( @RequestParam("file") MultipartFile file, @RequestParam(value = "minSeverity", defaultValue = "WARNING") String minSeverity, @RequestParam(value = "outputFormat", defaultValue = "json") String outputFormat) { log.info("Received file analysis request: {}", file.getOriginalFilename()); try { KubeScoreRequest request = new KubeScoreRequest(); request.setManifest(file); request.getOptions().setMinSeverity( com.example.kubescore.model.Severity.valueOf(minSeverity.toUpperCase()) ); request.getOptions().setOutputFormat(outputFormat); KubeScoreResponse response = kubeScoreService.analyzeManifest(request); return ResponseEntity.ok(Map.of( "success", response.isSuccess(), "summary", response.getSummary(), "results", response.getResults(), "timestamp", response.getTimestamp() )); } catch (Exception e) { log.error("File analysis failed", e); return ResponseEntity.badRequest().body(Map.of( "success", false, "error", e.getMessage() )); } } @GetMapping("/report") public ResponseEntity<String> generateReport( @RequestParam String format, @RequestBody KubeScoreResponse analysisResult) { try { String report = kubeScoreService.generateReport(analysisResult, format); HttpHeaders headers = new HttpHeaders(); switch (format.toLowerCase()) { case "json": headers.setContentType(MediaType.APPLICATION_JSON); break; case "yaml": headers.setContentType(MediaType.parseMediaType("application/yaml")); break; case "html": headers.setContentType(MediaType.TEXT_HTML); break; default: headers.setContentType(MediaType.TEXT_PLAIN); } return ResponseEntity.ok() .headers(headers) .body(report); } catch (Exception e) { log.error("Report generation failed", e); return ResponseEntity.badRequest().body("Report generation failed: " + e.getMessage()); } } @GetMapping("/health") public ResponseEntity<Map<String, Object>> health() { return ResponseEntity.ok(Map.of( "status", "healthy", "service", "kube-score", "timestamp", java.time.LocalDateTime.now() )); } }

Testing

1. Unit Tests
// KubeScoreServiceTest.java package com.example.kubescore.service; import com.example.kubescore.model.KubeScoreRequest; import com.example.kubescore.model.KubeScoreResponse; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.web.multipart.MultipartFile; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) class KubeScoreServiceTest { @Mock private KubernetesManifestParser manifestParser; @Mock private MultipartFile multipartFile; @InjectMocks private KubeScoreService kubeScoreService; @Test void testAnalyzeManifest_Success() throws Exception { // Setup String yamlContent = """ apiVersion: apps/v1 kind: Deployment metadata: name: test-deployment spec: replicas: 1 template: spec: containers: - name: test-container image: nginx:latest """; InputStream inputStream = new ByteArrayInputStream(yamlContent.getBytes(StandardCharsets.UTF_8)); when(multipartFile.getInputStream()).thenReturn(inputStream); KubeScoreRequest request = new KubeScoreRequest(); request.setManifest(multipartFile); // Execute KubeScoreResponse response = kubeScoreService.analyzeManifest(request); // Verify assertNotNull(response); // Add more assertions based on your implementation } } // ContainerSecurityContextCheckTest.java package com.example.kubescore.checks; import com.example.kubescore.model.KubernetesResource; import com.example.kubescore.model.CheckResult; import org.junit.jupiter.api.Test; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; class ContainerSecurityContextCheckTest { private final ContainerSecurityContextCheck check = new ContainerSecurityContextCheck(); @Test void testCheck_NoSecurityContext() { // Setup KubernetesResource resource = new KubernetesResource(); resource.setKind("Deployment"); resource.setApiVersion("apps/v1"); KubernetesResource.Metadata metadata = new KubernetesResource.Metadata(); metadata.setName("test-deployment"); resource.setMetadata(metadata); Map<String, Object> spec = Map.of( "template", Map.of( "spec", Map.of( "containers", List.of( Map.of("name", "test-container", "image", "nginx:latest") ) ) ) ); resource.setSpec(spec); // Execute List<CheckResult> results = check.check(resource); // Verify assertFalse(results.isEmpty()); assertTrue(results.stream().anyMatch(r -> r.getMessage().contains("missing security context"))); } }
2. Integration Test
// KubeScoreIntegrationTest.java package com.example.kubescore.integration; import com.example.kubescore.controller.KubeScoreController; import com.example.kubescore.model.KubeScoreRequest; import com.example.kubescore.model.Severity; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.mock.web.MockMultipartFile; import org.springframework.test.context.ActiveProfiles; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest @ActiveProfiles("test") class KubeScoreIntegrationTest { @Autowired private KubeScoreController kubeScoreController; @Test void testFullAnalysisWorkflow() { // Setup String yamlContent = """ apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 """; MockMultipartFile file = new MockMultipartFile( "file", "test.yaml", "text/yaml", yamlContent.getBytes() ); // Execute var response = kubeScoreController.analyzeManifestFile(file, "WARNING", "json"); // Verify assertTrue(response.getStatusCode().is2xxSuccessful()); assertNotNull(response.getBody()); // Add more specific assertions } }

Production Considerations

1. Configuration
// KubeScoreConfig.java package com.example.kubescore.config; import com.example.kubescore.checks.ResourceCheck; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; @Configuration public class KubeScoreConfig { @Bean public List<ResourceCheck> resourceChecks(List<ResourceCheck> checks) { // All ResourceCheck implementations are automatically injected return checks; } }
2. Error Handling
// GlobalExceptionHandler.java package com.example.kubescore.controller; import com.example.kubescore.service.KubernetesManifestParser; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.multipart.MaxUploadSizeExceededException; import java.util.Map; @Slf4j @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(KubernetesManifestParser.ManifestParseException.class) public ResponseEntity<Map<String, Object>> handleManifestParseException( KubernetesManifestParser.ManifestParseException e) { log.error("Manifest parse error", e); return ResponseEntity.badRequest().body(Map.of( "error", "Manifest parse failed", "message", e.getMessage() )); } @ExceptionHandler(MaxUploadSizeExceededException.class) public ResponseEntity<Map<String, Object>> handleMaxSizeException(MaxUploadSizeExceededException e) { return ResponseEntity.badRequest().body(Map.of( "error", "File too large", "message", "Maximum upload size exceeded" )); } @ExceptionHandler(Exception.class) public ResponseEntity<Map<String, Object>> handleGenericException(Exception e) { log.error("Unexpected error", e); return ResponseEntity.internalServerError().body(Map.of( "error", "Internal server error", "message", "An unexpected error occurred" )); } }

Best Practices

  1. Performance:
  • Use streaming YAML parsing for large manifests
  • Implement caching for frequently analyzed manifests
  • Use parallel processing for multiple resources
  1. Extensibility:
  • Easy to add new checks via ResourceCheck interface
  • Configurable severity levels and weights
  • Plugin architecture for custom checks
  1. Security:
  • Validate YAML input to prevent YAML bombs
  • Limit file upload sizes
  • Sanitize output for different formats
  1. Usability:
  • Multiple output formats (JSON, YAML, HTML, Text)
  • Detailed suggestions for fixing issues
  • Clear severity levels and scoring

Conclusion

This kube-score implementation provides:

  • Comprehensive Kubernetes manifest analysis with multiple checks
  • Extensible architecture for adding new analysis rules
  • Multiple output formats for different use cases
  • Production-ready features including error handling and validation
  • REST API for easy integration with CI/CD pipelines

The solution can be extended with:

  • Custom check plugins
  • Integration with Kubernetes admission controllers
  • Historical analysis and trend reporting
  • Team-specific rule sets
  • Automated fix suggestions

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper