NeuVector Scanner in Java: Container Security Vulnerability Scanning

NeuVector is a container security platform that provides vulnerability scanning, runtime protection, and network security. This implementation demonstrates how to integrate NeuVector's scanning capabilities into Java applications.

NeuVector Scanner Overview

NeuVector provides:

  • Container image vulnerability scanning
  • Runtime security monitoring
  • Network policy enforcement
  • Compliance checking
  • CI/CD pipeline integration

Dependencies and Setup

Maven Configuration:

<dependencies>
<!-- HTTP Client -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<!-- Docker Java API -->
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.3.0</version>
</dependency>
<!-- Kubernetes Client -->
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>18.0.0</version>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>

Configuration Management

NeuVectorConfig.java:

@Configuration
@ConfigurationProperties(prefix = "neuvector")
@Data
public class NeuVectorConfig {
private ScannerConfig scanner = new ScannerConfig();
private ControllerConfig controller = new ControllerConfig();
private RegistryConfig registry = new RegistryConfig();
private SecurityConfig security = new SecurityConfig();
@Data
public static class ScannerConfig {
private String url = "https://neuvector-scanner:8080";
private String username;
private String password;
private int timeout = 30000;
private int maxRetries = 3;
private boolean sslVerify = true;
private String caCertPath;
}
@Data
public static class ControllerConfig {
private String url = "https://neuvector-controller:8443";
private String username;
private String password;
private String apiVersion = "v1";
}
@Data
public static class RegistryConfig {
private String url;
private String username;
private String password;
private String registryType = "docker";
private boolean scanLayers = true;
private List<String> excludedRepositories = new ArrayList<>();
}
@Data
public static class SecurityConfig {
private String jwtSecret;
private String encryptionKey;
private boolean enableTLS = true;
private List<String> allowedCidrs = Arrays.asList("0.0.0.0/0");
}
public String getScannerAuthHeader() {
String auth = username + ":" + password;
return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
}
public String getControllerAuthHeader() {
String auth = controller.getUsername() + ":" + controller.getPassword();
return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes());
}
}

NeuVector API Client

NeuVectorApiClient.java:

@Service
@Slf4j
public class NeuVectorApiClient {
private final NeuVectorConfig config;
private final RestTemplate restTemplate;
private final ObjectMapper objectMapper;
public NeuVectorApiClient(NeuVectorConfig config) {
this.config = config;
this.restTemplate = createRestTemplate();
this.objectMapper = new ObjectMapper();
}
public ScanResult scanImage(ScanRequest request) {
try {
String url = config.getScanner().getUrl() + "/scan";
HttpHeaders headers = createScannerHeaders();
HttpEntity<ScanRequest> entity = new HttpEntity<>(request, headers);
ResponseEntity<ScanResponse> response = restTemplate.exchange(
url, HttpMethod.POST, entity, ScanResponse.class);
return processScanResponse(response.getBody());
} catch (Exception e) {
throw new NeuVectorException("Image scan failed: " + e.getMessage(), e);
}
}
public ScanStatus getScanStatus(String scanId) {
try {
String url = config.getScanner().getUrl() + "/scan/" + scanId + "/status";
HttpHeaders headers = createScannerHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<ScanStatus> response = restTemplate.exchange(
url, HttpMethod.GET, entity, ScanStatus.class);
return response.getBody();
} catch (Exception e) {
throw new NeuVectorException("Failed to get scan status: " + e.getMessage(), e);
}
}
public List<Vulnerability> getVulnerabilities(String imageId) {
try {
String url = config.getController().getUrl() + "/" + 
config.getController().getApiVersion() + "/scan/image/" + imageId;
HttpHeaders headers = createControllerHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<VulnerabilityResponse> response = restTemplate.exchange(
url, HttpMethod.GET, entity, VulnerabilityResponse.class);
return response.getBody().getVulnerabilities();
} catch (Exception e) {
throw new NeuVectorException("Failed to get vulnerabilities: " + e.getMessage(), e);
}
}
public ComplianceReport getComplianceReport(String namespace) {
try {
String url = config.getController().getUrl() + "/" + 
config.getController().getApiVersion() + "/compliance/" + namespace;
HttpHeaders headers = createControllerHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<ComplianceReport> response = restTemplate.exchange(
url, HttpMethod.GET, entity, ComplianceReport.class);
return response.getBody();
} catch (Exception e) {
throw new NeuVectorException("Failed to get compliance report: " + e.getMessage(), e);
}
}
public List<SecurityEvent> getSecurityEvents(String namespace, Duration timeRange) {
try {
Instant endTime = Instant.now();
Instant startTime = endTime.minus(timeRange);
String url = config.getController().getUrl() + "/" + 
config.getController().getApiVersion() + "/events/security" +
"?start=" + startTime.getEpochSecond() +
"&end=" + endTime.getEpochSecond() +
"&namespace=" + namespace;
HttpHeaders headers = createControllerHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<SecurityEventResponse> response = restTemplate.exchange(
url, HttpMethod.GET, entity, SecurityEventResponse.class);
return response.getBody().getEvents();
} catch (Exception e) {
throw new NeuVectorException("Failed to get security events: " + e.getMessage(), e);
}
}
public boolean createNetworkPolicy(NetworkPolicy policy) {
try {
String url = config.getController().getUrl() + "/" + 
config.getController().getApiVersion() + "/policy/network";
HttpHeaders headers = createControllerHeaders();
HttpEntity<NetworkPolicy> entity = new HttpEntity<>(policy, headers);
ResponseEntity<Void> response = restTemplate.exchange(
url, HttpMethod.POST, entity, Void.class);
return response.getStatusCode().is2xxSuccessful();
} catch (Exception e) {
throw new NeuVectorException("Failed to create network policy: " + e.getMessage(), e);
}
}
private HttpHeaders createScannerHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", config.getScannerAuthHeader());
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
private HttpHeaders createControllerHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", config.getControllerAuthHeader());
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
private RestTemplate createRestTemplate() {
RestTemplate template = new RestTemplate();
// Configure SSL
if (!config.getScanner().isSslVerify() && config.getScanner().getCaCertPath() != null) {
template.setRequestFactory(createSslFactory());
}
// Configure timeout
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(config.getScanner().getTimeout());
factory.setReadTimeout(config.getScanner().getTimeout());
template.setRequestFactory(factory);
return template;
}
private ClientHttpRequestFactory createSslFactory() {
try {
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(new File(config.getScanner().getCaCertPath()), 
(chain, authType) -> true)
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
sslContext, NoopHostnameVerifier.INSTANCE);
HttpClientConnectionManager connectionManager = 
PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(socketFactory)
.build();
HttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.build();
return new HttpComponentsClientHttpRequestFactory(httpClient);
} catch (Exception e) {
throw new NeuVectorException("SSL configuration failed", e);
}
}
private ScanResult processScanResponse(ScanResponse response) {
return ScanResult.builder()
.scanId(response.getScanId())
.status(response.getStatus())
.vulnerabilities(response.getVulnerabilities())
.summary(createSummary(response.getVulnerabilities()))
.scanDate(Instant.now())
.build();
}
private VulnerabilitySummary createSummary(List<Vulnerability> vulnerabilities) {
Map<String, Long> severityCount = vulnerabilities.stream()
.collect(Collectors.groupingBy(Vulnerability::getSeverity, Collectors.counting()));
return VulnerabilitySummary.builder()
.total(vulnerabilities.size())
.critical(severityCount.getOrDefault("Critical", 0L))
.high(severityCount.getOrDefault("High", 0L))
.medium(severityCount.getOrDefault("Medium", 0L))
.low(severityCount.getOrDefault("Low", 0L))
.build();
}
}

Data Models

ScanRequest.java:

@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ScanRequest {
private String image;
private String registry;
private String username;
private String password;
private String tag;
private ScanConfig scanConfig;
private Boolean scanLayers;
private Map<String, String> labels;
@Data
@Builder
public static class ScanConfig {
private Boolean scanSecrets;
private Boolean scanMalware;
private Boolean scanSetuidSetgid;
private List<String> excludedPaths;
private Integer timeout;
}
}

ScanResult.java:

@Data
@Builder
public class ScanResult {
private String scanId;
private String status;
private List<Vulnerability> vulnerabilities;
private VulnerabilitySummary summary;
private Instant scanDate;
private String imageDigest;
private List<ComplianceIssue> complianceIssues;
private ScanMetadata metadata;
public boolean hasCriticalVulnerabilities() {
return summary != null && summary.getCritical() > 0;
}
public boolean hasHighVulnerabilities() {
return summary != null && summary.getHigh() > 0;
}
public boolean isCompliant() {
return complianceIssues == null || complianceIssues.isEmpty();
}
}

Vulnerability.java:

@Data
@Builder
@JsonIgnoreProperties(ignoreUnknown = true)
public class Vulnerability {
private String name;
private String severity;
private String packageName;
private String packageVersion;
private String fixedVersion;
private String description;
private String link;
private List<String> cves;
private Double score;
private Vector vector;
private List<String> layers;
private Instant publishedDate;
private Instant discoveredDate;
@Data
@Builder
public static class Vector {
private String attackVector;
private String attackComplexity;
private String privilegesRequired;
private String userInteraction;
private String scope;
private String confidentialityImpact;
private String integrityImpact;
private String availabilityImpact;
}
}

ComplianceIssue.java:

@Data
@Builder
public class ComplianceIssue {
private String id;
private String type;
private String level;
private String description;
private String standard;
private String message;
private List<String> affectedResources;
private Remediation remediation;
@Data
@Builder
public static class Remediation {
private String description;
private List<String> commands;
private List<String> resources;
}
}

Vulnerability Scanner Service

VulnerabilityScannerService.java:

@Service
@Slf4j
public class VulnerabilityScannerService {
private final NeuVectorApiClient apiClient;
private final DockerService dockerService;
private final KubernetesService kubernetesService;
public VulnerabilityScannerService(NeuVectorApiClient apiClient,
DockerService dockerService,
KubernetesService kubernetesService) {
this.apiClient = apiClient;
this.dockerService = dockerService;
this.kubernetesService = kubernetesService;
}
public ScanResult scanImage(String imageName) {
try {
log.info("Starting vulnerability scan for image: {}", imageName);
ScanRequest request = ScanRequest.builder()
.image(imageName)
.scanConfig(ScanRequest.ScanConfig.builder()
.scanSecrets(true)
.scanMalware(true)
.scanSetuidSetgid(true)
.build())
.build();
ScanResult result = apiClient.scanImage(request);
log.info("Scan completed for image: {} - {} vulnerabilities found", 
imageName, result.getSummary().getTotal());
return result;
} catch (Exception e) {
log.error("Vulnerability scan failed for image: {}", imageName, e);
throw new ScanException("Scan failed for image: " + imageName, e);
}
}
public ScanResult scanImageWithRetry(String imageName, int maxRetries) {
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
return scanImage(imageName);
} catch (Exception e) {
if (attempt == maxRetries) {
throw e;
}
log.warn("Scan attempt {} failed for image: {}, retrying...", attempt, imageName);
sleepExponentialBackoff(attempt);
}
}
throw new ScanException("All scan attempts failed for image: " + imageName);
}
public List<ScanResult> scanImages(List<String> images) {
return images.parallelStream()
.map(this::scanImage)
.collect(Collectors.toList());
}
public ScanReport scanNamespace(String namespace) {
try {
log.info("Starting comprehensive scan for namespace: {}", namespace);
// Get all pods in namespace
List<Pod> pods = kubernetesService.getPodsInNamespace(namespace);
// Extract unique images
Set<String> images = pods.stream()
.flatMap(pod -> pod.getContainers().stream())
.map(Container::getImage)
.collect(Collectors.toSet());
// Scan all images
List<ScanResult> scanResults = scanImages(new ArrayList<>(images));
// Get compliance report
ComplianceReport complianceReport = apiClient.getComplianceReport(namespace);
// Get security events
List<SecurityEvent> securityEvents = apiClient.getSecurityEvents(namespace, Duration.ofHours(24));
return ScanReport.builder()
.namespace(namespace)
.scanDate(Instant.now())
.scanResults(scanResults)
.complianceReport(complianceReport)
.securityEvents(securityEvents)
.summary(createNamespaceSummary(scanResults, complianceReport, securityEvents))
.build();
} catch (Exception e) {
throw new ScanException("Namespace scan failed: " + namespace, e);
}
}
public ComplianceCheckResult checkCompliance(String namespace, ComplianceStandard standard) {
try {
ComplianceReport report = apiClient.getComplianceReport(namespace);
List<ComplianceIssue> relevantIssues = report.getIssues().stream()
.filter(issue -> standard.getName().equals(issue.getStandard()))
.collect(Collectors.toList());
boolean compliant = relevantIssues.stream()
.noneMatch(issue -> "HIGH".equals(issue.getLevel()) || "CRITICAL".equals(issue.getLevel()));
return ComplianceCheckResult.builder()
.namespace(namespace)
.standard(standard)
.compliant(compliant)
.issues(relevantIssues)
.checkDate(Instant.now())
.build();
} catch (Exception e) {
throw new ComplianceException("Compliance check failed", e);
}
}
public VulnerabilityTrend analyzeVulnerabilityTrend(String image, Duration period) {
try {
Instant endDate = Instant.now();
Instant startDate = endDate.minus(period);
// This would typically query historical scan data
List<ScanResult> historicalScans = getHistoricalScans(image, startDate, endDate);
return VulnerabilityTrend.builder()
.image(image)
.period(period)
.trendData(calculateTrend(historicalScans))
.recommendations(generateRecommendations(historicalScans))
.build();
} catch (Exception e) {
throw new AnalysisException("Vulnerability trend analysis failed", e);
}
}
public boolean isImageApproved(String image, ApprovalPolicy policy) {
ScanResult scanResult = scanImage(image);
return evaluateApprovalPolicy(scanResult, policy);
}
public ImageRiskAssessment assessImageRisk(String image) {
ScanResult scanResult = scanImage(image);
double riskScore = calculateRiskScore(scanResult);
RiskLevel riskLevel = determineRiskLevel(riskScore);
return ImageRiskAssessment.builder()
.image(image)
.riskScore(riskScore)
.riskLevel(riskLevel)
.scanResult(scanResult)
.assessmentDate(Instant.now())
.recommendations(generateRiskRecommendations(scanResult, riskLevel))
.build();
}
private NamespaceScanSummary createNamespaceSummary(List<ScanResult> scanResults,
ComplianceReport complianceReport,
List<SecurityEvent> securityEvents) {
VulnerabilitySummary vulnSummary = scanResults.stream()
.map(ScanResult::getSummary)
.reduce(new VulnerabilitySummary(0, 0L, 0L, 0L, 0L),
(s1, s2) -> new VulnerabilitySummary(
s1.getTotal() + s2.getTotal(),
s1.getCritical() + s2.getCritical(),
s1.getHigh() + s2.getHigh(),
s1.getMedium() + s2.getMedium(),
s1.getLow() + s2.getLow()
));
return NamespaceScanSummary.builder()
.totalImages(scanResults.size())
.vulnerabilitySummary(vulnSummary)
.complianceIssues(complianceReport.getIssues().size())
.securityEvents(securityEvents.size())
.overallStatus(calculateOverallStatus(vulnSummary, complianceReport))
.build();
}
private String calculateOverallStatus(VulnerabilitySummary vulnSummary, ComplianceReport complianceReport) {
if (vulnSummary.getCritical() > 0) {
return "CRITICAL";
} else if (vulnSummary.getHigh() > 0) {
return "HIGH";
} else if (!complianceReport.getIssues().isEmpty()) {
return "WARNING";
} else {
return "PASS";
}
}
private boolean evaluateApprovalPolicy(ScanResult scanResult, ApprovalPolicy policy) {
if (policy.isBlockCritical() && scanResult.getSummary().getCritical() > 0) {
return false;
}
if (policy.isBlockHigh() && scanResult.getSummary().getHigh() > 0) {
return false;
}
if (policy.getMaxTotalVulnerabilities() > 0 && 
scanResult.getSummary().getTotal() > policy.getMaxTotalVulnerabilities()) {
return false;
}
return true;
}
private double calculateRiskScore(ScanResult scanResult) {
VulnerabilitySummary summary = scanResult.getSummary();
double score = summary.getCritical() * 10.0 +
summary.getHigh() * 5.0 +
summary.getMedium() * 2.0 +
summary.getLow() * 0.5;
return Math.min(score, 100.0);
}
private RiskLevel determineRiskLevel(double riskScore) {
if (riskScore >= 80) return RiskLevel.CRITICAL;
if (riskScore >= 60) return RiskLevel.HIGH;
if (riskScore >= 40) return RiskLevel.MEDIUM;
if (riskScore >= 20) return RiskLevel.LOW;
return RiskLevel.NONE;
}
private void sleepExponentialBackoff(int attempt) {
try {
long delay = Math.min(1000 * (long) Math.pow(2, attempt), 30000);
Thread.sleep(delay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ScanException("Scan interrupted", e);
}
}
}

Docker Integration Service

DockerService.java:

@Service
@Slf4j
public class DockerService {
private final DockerClient dockerClient;
public DockerService() {
this.dockerClient = createDockerClient();
}
public List<Image> getLocalImages() {
try {
return dockerClient.listImagesCmd().exec().stream()
.map(this::convertToImage)
.collect(Collectors.toList());
} catch (Exception e) {
throw new DockerException("Failed to list local images", e);
}
}
public ImageInfo inspectImage(String imageName) {
try {
InspectImageResponse response = dockerClient.inspectImageCmd(imageName).exec();
return convertToImageInfo(response);
} catch (Exception e) {
throw new DockerException("Failed to inspect image: " + imageName, e);
}
}
public void pullImage(String imageName) {
try {
dockerClient.pullImageCmd(imageName)
.exec(new PullImageResultCallback())
.awaitCompletion(300, TimeUnit.SECONDS);
} catch (Exception e) {
throw new DockerException("Failed to pull image: " + imageName, e);
}
}
public List<Container> getRunningContainers() {
try {
return dockerClient.listContainersCmd()
.withShowAll(false)
.exec().stream()
.map(this::convertToContainer)
.collect(Collectors.toList());
} catch (Exception e) {
throw new DockerException("Failed to list running containers", e);
}
}
public ImageHistory getImageHistory(String imageName) {
try {
List<ImageHistory> history = dockerClient.inspectImageCmd(imageName)
.exec()
.getRepoDigests();
return ImageHistory.builder()
.image(imageName)
.layers(extractLayers(history))
.build();
} catch (Exception e) {
throw new DockerException("Failed to get image history: " + imageName, e);
}
}
private DockerClient createDockerClient() {
return DockerClientBuilder.getInstance().build();
}
private Image convertToImage(com.github.dockerjava.api.model.Image dockerImage) {
return Image.builder()
.id(dockerImage.getId())
.repository(dockerImage.getRepoTags() != null ? 
dockerImage.getRepoTags()[0] : "unknown")
.size(dockerImage.getSize())
.created(dockerImage.getCreated())
.build();
}
private ImageInfo convertToImageInfo(InspectImageResponse response) {
return ImageInfo.builder()
.id(response.getId())
.architecture(response.getArch())
.os(response.getOs())
.created(response.getCreated())
.size(response.getSize())
.layers(response.getRootFS().getLayers())
.environment(response.getConfig().getEnv())
.labels(response.getConfig().getLabels())
.build();
}
private Container convertToContainer(com.github.dockerjava.api.model.Container dockerContainer) {
return Container.builder()
.id(dockerContainer.getId())
.name(dockerContainer.getNames()[0])
.image(dockerContainer.getImage())
.status(dockerContainer.getStatus())
.created(dockerContainer.getCreated())
.build();
}
private List<ImageLayer> extractLayers(List<ImageHistory> history) {
return history.stream()
.map(h -> ImageLayer.builder()
.digest(h.getId())
.created(h.getCreated())
.size(h.getSize())
.build())
.collect(Collectors.toList());
}
}

Kubernetes Integration Service

KubernetesService.java:

@Service
@Slf4j
public class KubernetesService {
private final ApiClient apiClient;
private final CoreV1Api coreApi;
private final AppsV1Api appsApi;
public KubernetesService() {
this.apiClient = createApiClient();
this.coreApi = new CoreV1Api(apiClient);
this.appsApi = new AppsV1Api(apiClient);
}
public List<Pod> getPodsInNamespace(String namespace) {
try {
V1PodList podList = coreApi.listNamespacedPod(namespace)
.execute();
return podList.getItems().stream()
.map(this::convertToPod)
.collect(Collectors.toList());
} catch (ApiException e) {
throw new KubernetesException("Failed to get pods in namespace: " + namespace, e);
}
}
public List<Deployment> getDeploymentsInNamespace(String namespace) {
try {
V1DeploymentList deploymentList = appsApi.listNamespacedDeployment(namespace)
.execute();
return deploymentList.getItems().stream()
.map(this::convertToDeployment)
.collect(Collectors.toList());
} catch (ApiException e) {
throw new KubernetesException("Failed to get deployments in namespace: " + namespace, e);
}
}
public NamespaceInfo getNamespaceInfo(String namespace) {
try {
V1Namespace ns = coreApi.readNamespace(namespace).execute();
return NamespaceInfo.builder()
.name(namespace)
.labels(ns.getMetadata().getLabels())
.annotations(ns.getMetadata().getAnnotations())
.creationTimestamp(ns.getMetadata().getCreationTimestamp())
.status(ns.getStatus().getPhase())
.build();
} catch (ApiException e) {
throw new KubernetesException("Failed to get namespace info: " + namespace, e);
}
}
public boolean createNetworkPolicy(NetworkPolicy policy) {
try {
V1NetworkPolicy v1Policy = convertToV1NetworkPolicy(policy);
coreApi.createNamespacedNetworkPolicy(policy.getNamespace(), v1Policy)
.execute();
return true;
} catch (ApiException e) {
throw new KubernetesException("Failed to create network policy", e);
}
}
public ClusterSecurityReport getClusterSecurityReport() {
try {
List<Pod> allPods = getAllPods();
List<NamespaceInfo> namespaces = getAllNamespaces();
return ClusterSecurityReport.builder()
.totalPods(allPods.size())
.totalNamespaces(namespaces.size())
.namespaces(namespaces.stream()
.map(ns -> getNamespaceInfo(ns.getName()))
.collect(Collectors.toList()))
.generatedAt(Instant.now())
.build();
} catch (Exception e) {
throw new KubernetesException("Failed to generate cluster security report", e);
}
}
private ApiClient createApiClient() {
try {
// Try in-cluster config first, then fallback to kubeconfig
if (isRunningInCluster()) {
return Config.fromCluster();
} else {
return Config.defaultClient();
}
} catch (Exception e) {
throw new KubernetesException("Failed to create Kubernetes client", e);
}
}
private boolean isRunningInCluster() {
return Files.exists(Paths.get("/var/run/secrets/kubernetes.io/serviceaccount/token"));
}
private Pod convertToPod(V1Pod v1Pod) {
return Pod.builder()
.name(v1Pod.getMetadata().getName())
.namespace(v1Pod.getMetadata().getNamespace())
.containers(v1Pod.getSpec().getContainers().stream()
.map(this::convertToContainer)
.collect(Collectors.toList()))
.labels(v1Pod.getMetadata().getLabels())
.status(v1Pod.getStatus().getPhase())
.created(v1Pod.getMetadata().getCreationTimestamp())
.build();
}
private Container convertToContainer(V1Container v1Container) {
return Container.builder()
.name(v1Container.getName())
.image(v1Container.getImage())
.resources(v1Container.getResources())
.build();
}
private Deployment convertToDeployment(V1Deployment v1Deployment) {
return Deployment.builder()
.name(v1Deployment.getMetadata().getName())
.namespace(v1Deployment.getMetadata().getNamespace())
.replicas(v1Deployment.getSpec().getReplicas())
.containers(v1Deployment.getSpec().getTemplate().getSpec().getContainers().stream()
.map(this::convertToContainer)
.collect(Collectors.toList()))
.labels(v1Deployment.getMetadata().getLabels())
.build();
}
private V1NetworkPolicy convertToV1NetworkPolicy(NetworkPolicy policy) {
V1NetworkPolicy v1Policy = new V1NetworkPolicy();
V1ObjectMeta metadata = new V1ObjectMeta();
metadata.setName(policy.getName());
metadata.setNamespace(policy.getNamespace());
v1Policy.setMetadata(metadata);
V1NetworkPolicySpec spec = new V1NetworkPolicySpec();
spec.setPodSelector(new V1LabelSelector()
.matchLabels(policy.getPodSelector()));
// Convert policy rules
if (policy.getIngressRules() != null) {
spec.setIngress(policy.getIngressRules().stream()
.map(this::convertToV1NetworkPolicyIngressRule)
.collect(Collectors.toList()));
}
if (policy.getEgressRules() != null) {
spec.setEgress(policy.getEgressRules().stream()
.map(this::convertToV1NetworkPolicyEgressRule)
.collect(Collectors.toList()));
}
v1Policy.setSpec(spec);
return v1Policy;
}
private List<Pod> getAllPods() {
try {
V1PodList podList = coreApi.listPodForAllNamespaces().execute();
return podList.getItems().stream()
.map(this::convertToPod)
.collect(Collectors.toList());
} catch (ApiException e) {
throw new KubernetesException("Failed to get all pods", e);
}
}
private List<NamespaceInfo> getAllNamespaces() {
try {
V1NamespaceList namespaceList = coreApi.listNamespace().execute();
return namespaceList.getItems().stream()
.map(ns -> NamespaceInfo.builder()
.name(ns.getMetadata().getName())
.labels(ns.getMetadata().getLabels())
.build())
.collect(Collectors.toList());
} catch (ApiException e) {
throw new KubernetesException("Failed to get all namespaces", e);
}
}
}

Security Policy Manager

SecurityPolicyManager.java:

@Service
@Slf4j
public class SecurityPolicyManager {
private final NeuVectorApiClient apiClient;
private final KubernetesService kubernetesService;
public SecurityPolicyManager(NeuVectorApiClient apiClient,
KubernetesService kubernetesService) {
this.apiClient = apiClient;
this.kubernetesService = kubernetesService;
}
public PolicyValidationResult validateImagePolicy(String image, ImagePolicy policy) {
try {
ScanResult scanResult = apiClient.scanImage(ScanRequest.builder()
.image(image)
.build());
return PolicyValidationResult.builder()
.image(image)
.policy(policy)
.compliant(isCompliantWithPolicy(scanResult, policy))
.violations(findPolicyViolations(scanResult, policy))
.scanResult(scanResult)
.validatedAt(Instant.now())
.build();
} catch (Exception e) {
throw new PolicyException("Image policy validation failed", e);
}
}
public RuntimePolicy createRuntimePolicy(RuntimePolicy policy) {
try {
// Create NeuVector runtime policy
boolean success = apiClient.createRuntimePolicy(policy);
if (success) {
log.info("Runtime policy created: {}", policy.getName());
return policy;
} else {
throw new PolicyException("Failed to create runtime policy: " + policy.getName());
}
} catch (Exception e) {
throw new PolicyException("Runtime policy creation failed", e);
}
}
public NetworkPolicy createNetworkPolicy(NetworkPolicy policy) {
try {
// Create Kubernetes network policy
boolean success = kubernetesService.createNetworkPolicy(policy);
if (success) {
log.info("Network policy created: {}", policy.getName());
return policy;
} else {
throw new PolicyException("Failed to create network policy: " + policy.getName());
}
} catch (Exception e) {
throw new PolicyException("Network policy creation failed", e);
}
}
public ComplianceReport checkNamespaceCompliance(String namespace, ComplianceStandard standard) {
try {
return apiClient.getComplianceReport(namespace);
} catch (Exception e) {
throw new ComplianceException("Compliance check failed for namespace: " + namespace, e);
}
}
public List<SecurityEvent> monitorSecurityEvents(String namespace, Duration timeRange) {
try {
return apiClient.getSecurityEvents(namespace, timeRange);
} catch (Exception e) {
throw new MonitoringException("Security event monitoring failed", e);
}
}
public SecurityDashboard getSecurityDashboard(String namespace) {
try {
List<ScanResult> scanResults = scanNamespaceImages(namespace);
ComplianceReport complianceReport = apiClient.getComplianceReport(namespace);
List<SecurityEvent> securityEvents = apiClient.getSecurityEvents(namespace, Duration.ofHours(24));
return SecurityDashboard.builder()
.namespace(namespace)
.timestamp(Instant.now())
.vulnerabilitySummary(createVulnerabilitySummary(scanResults))
.complianceStatus(createComplianceStatus(complianceReport))
.securityEvents(securityEvents)
.riskScore(calculateRiskScore(scanResults, complianceReport, securityEvents))
.recommendations(generateRecommendations(scanResults, complianceReport, securityEvents))
.build();
} catch (Exception e) {
throw new DashboardException("Security dashboard generation failed", e);
}
}
private boolean isCompliantWithPolicy(ScanResult scanResult, ImagePolicy policy) {
VulnerabilitySummary summary = scanResult.getSummary();
if (policy.getMaxCriticalSeverity() > 0 && 
summary.getCritical() > policy.getMaxCriticalSeverity()) {
return false;
}
if (policy.getMaxHighSeverity() > 0 && 
summary.getHigh() > policy.getMaxHighSeverity()) {
return false;
}
if (policy.getMaxTotalVulnerabilities() > 0 && 
summary.getTotal() > policy.getMaxTotalVulnerabilities()) {
return false;
}
return true;
}
private List<PolicyViolation> findPolicyViolations(ScanResult scanResult, ImagePolicy policy) {
List<PolicyViolation> violations = new ArrayList<>();
VulnerabilitySummary summary = scanResult.getSummary();
if (policy.getMaxCriticalSeverity() > 0 && 
summary.getCritical() > policy.getMaxCriticalSeverity()) {
violations.add(PolicyViolation.builder()
.type("CRITICAL_VULNERABILITIES")
.message("Exceeded maximum critical vulnerabilities: " + summary.getCritical())
.severity("HIGH")
.build());
}
// Add other violation checks...
return violations;
}
private List<ScanResult> scanNamespaceImages(String namespace) {
List<Pod> pods = kubernetesService.getPodsInNamespace(namespace);
Set<String> images = pods.stream()
.flatMap(pod -> pod.getContainers().stream())
.map(Container::getImage)
.collect(Collectors.toSet());
VulnerabilityScannerService scanner = new VulnerabilityScannerService(
apiClient, new DockerService(), kubernetesService);
return scanner.scanImages(new ArrayList<>(images));
}
private VulnerabilitySummary createVulnerabilitySummary(List<ScanResult> scanResults) {
return scanResults.stream()
.map(ScanResult::getSummary)
.reduce(new VulnerabilitySummary(0, 0L, 0L, 0L, 0L),
(s1, s2) -> new VulnerabilitySummary(
s1.getTotal() + s2.getTotal(),
s1.getCritical() + s2.getCritical(),
s1.getHigh() + s2.getHigh(),
s1.getMedium() + s2.getMedium(),
s1.getLow() + s2.getLow()
));
}
private ComplianceStatus createComplianceStatus(ComplianceReport report) {
long criticalIssues = report.getIssues().stream()
.filter(issue -> "CRITICAL".equals(issue.getLevel()))
.count();
long highIssues = report.getIssues().stream()
.filter(issue -> "HIGH".equals(issue.getLevel()))
.count();
return ComplianceStatus.builder()
.totalIssues(report.getIssues().size())
.criticalIssues(criticalIssues)
.highIssues(highIssues)
.compliant(criticalIssues == 0 && highIssues == 0)
.build();
}
private double calculateRiskScore(List<ScanResult> scanResults, 
ComplianceReport complianceReport,
List<SecurityEvent> securityEvents) {
// Implement risk scoring logic
double vulnScore = scanResults.stream()
.mapToDouble(result -> result.getSummary().getCritical() * 10 + 
result.getSummary().getHigh() * 5)
.sum();
double complianceScore = complianceReport.getIssues().size() * 2;
double eventScore = securityEvents.size() * 3;
return Math.min((vulnScore + complianceScore + eventScore) / 100.0, 1.0) * 100;
}
private List<String> generateRecommendations(List<ScanResult> scanResults,
ComplianceReport complianceReport,
List<SecurityEvent> securityEvents) {
List<String> recommendations = new ArrayList<>();
// Generate recommendations based on scan results, compliance issues, and security events
if (scanResults.stream().anyMatch(ScanResult::hasCriticalVulnerabilities)) {
recommendations.add("Upgrade images with critical vulnerabilities immediately");
}
if (!complianceReport.getIssues().isEmpty()) {
recommendations.add("Address compliance issues to meet security standards");
}
if (!securityEvents.isEmpty()) {
recommendations.add("Investigate recent security events for potential threats");
}
return recommendations;
}
}

REST API Controller

NeuVectorController.java:

@RestController
@RequestMapping("/api/neuvector")
@Slf4j
public class NeuVectorController {
private final VulnerabilityScannerService scannerService;
private final SecurityPolicyManager policyManager;
private final NeuVectorApiClient apiClient;
public NeuVectorController(VulnerabilityScannerService scannerService,
SecurityPolicyManager policyManager,
NeuVectorApiClient apiClient) {
this.scannerService = scannerService;
this.policyManager = policyManager;
this.apiClient = apiClient;
}
@PostMapping("/scan/image")
public ResponseEntity<ScanResult> scanImage(@RequestBody ScanImageRequest request) {
try {
ScanResult result = scannerService.scanImage(request.getImageName());
return ResponseEntity.ok(result);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@PostMapping("/scan/namespace")
public ResponseEntity<ScanReport> scanNamespace(@RequestBody ScanNamespaceRequest request) {
try {
ScanReport report = scannerService.scanNamespace(request.getNamespace());
return ResponseEntity.ok(report);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@PostMapping("/policy/validate")
public ResponseEntity<PolicyValidationResult> validatePolicy(
@RequestBody PolicyValidationRequest request) {
try {
PolicyValidationResult result = policyManager.validateImagePolicy(
request.getImage(), request.getPolicy());
return ResponseEntity.ok(result);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(null);
}
}
@GetMapping("/dashboard/{namespace}")
public ResponseEntity<SecurityDashboard> getSecurityDashboard(
@PathVariable String namespace) {
try {
SecurityDashboard dashboard = policyManager.getSecurityDashboard(namespace);
return ResponseEntity.ok(dashboard);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@GetMapping("/compliance/{namespace}")
public ResponseEntity<ComplianceReport> getComplianceReport(
@PathVariable String namespace) {
try {
ComplianceReport report = apiClient.getComplianceReport(namespace);
return ResponseEntity.ok(report);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
@GetMapping("/events/{namespace}")
public ResponseEntity<List<SecurityEvent>> getSecurityEvents(
@PathVariable String namespace,
@RequestParam(defaultValue = "24h") String duration) {
try {
Duration timeRange = parseDuration(duration);
List<SecurityEvent> events = apiClient.getSecurityEvents(namespace, timeRange);
return ResponseEntity.ok(events);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Collections.emptyList());
}
}
@PostMapping("/risk/assessment")
public ResponseEntity<ImageRiskAssessment> assessImageRisk(
@RequestBody RiskAssessmentRequest request) {
try {
ImageRiskAssessment assessment = scannerService.assessImageRisk(request.getImage());
return ResponseEntity.ok(assessment);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(null);
}
}
// DTO classes
@Data
public static class ScanImageRequest {
private String imageName;
}
@Data
public static class ScanNamespaceRequest {
private String namespace;
}
@Data
public static class PolicyValidationRequest {
private String image;
private ImagePolicy policy;
}
@Data
public static class RiskAssessmentRequest {
private String image;
}
private Duration parseDuration(String duration) {
if (duration.endsWith("h")) {
long hours = Long.parseLong(duration.substring(0, duration.length() - 1));
return Duration.ofHours(hours);
} else if (duration.endsWith("d")) {
long days = Long.parseLong(duration.substring(0, duration.length() - 1));
return Duration.ofDays(days);
} else {
return Duration.ofHours(24);
}
}
}

Best Practices

  1. Implement proper error handling and retry mechanisms
  2. Use secure authentication with TLS and API keys
  3. Cache scan results to improve performance
  4. Monitor API rate limits and implement backoff strategies
  5. Keep NeuVector components updated for latest vulnerability databases
  6. Integrate with CI/CD pipelines for automated security scanning
  7. Set up alerts for critical vulnerabilities and compliance violations

Conclusion

NeuVector Scanner integration in Java provides:

  • Comprehensive vulnerability scanning for container images
  • Runtime security monitoring and policy enforcement
  • Compliance checking against security standards
  • Risk assessment and trend analysis
  • Kubernetes-native integration for cluster security
  • RESTful API for automation and integration

This implementation demonstrates how to build a robust container security scanning solution that can be integrated into development pipelines, runtime environments, and security operations workflows.

Leave a Reply

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


Macro Nepal Helper