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
- Implement proper error handling and retry mechanisms
- Use secure authentication with TLS and API keys
- Cache scan results to improve performance
- Monitor API rate limits and implement backoff strategies
- Keep NeuVector components updated for latest vulnerability databases
- Integrate with CI/CD pipelines for automated security scanning
- 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.