Anchore Engine in Java: Complete Integration Guide

Introduction to Anchore Engine

Anchore Engine is an open-source tool for analyzing container images for security vulnerabilities, compliance issues, and best practices. This guide covers Java integration with Anchore Engine for container security scanning in CI/CD pipelines and runtime environments.

Key Anchore Engine Features

  • Vulnerability Scanning - CVE detection in container images
  • Policy Compliance - Custom security policies enforcement
  • Image Analysis - Deep inspection of container contents
  • SBOM Generation - Software Bill of Materials
  • CI/CD Integration - Pipeline security gates
  • REST API - Comprehensive API for automation

Dependencies and Setup

Maven Configuration

<properties>
<anchore.client.version>1.0.0</anchore.client.version>
<okhttp.version>4.10.0</okhttp.version>
<jackson.version>2.15.2</jackson.version>
</properties>
<dependencies>
<!-- HTTP Client -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
</dependency>
<!-- JSON Processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<!-- Testing -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
<!-- Docker Java API -->
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java-core</artifactId>
<version>3.3.0</version>
</dependency>
</dependencies>

Core Anchore Engine Client

Anchore Client Implementation

package com.anchore.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class AnchoreClient {
private static final Logger logger = LoggerFactory.getLogger(AnchoreClient.class);
private final String baseUrl;
private final String username;
private final String password;
private final OkHttpClient httpClient;
private final ObjectMapper objectMapper;
public AnchoreClient(String baseUrl, String username, String password) {
this.baseUrl = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
this.username = username;
this.password = password;
this.objectMapper = new ObjectMapper();
this.httpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(300, TimeUnit.SECONDS) // Longer timeout for image analysis
.writeTimeout(30, TimeUnit.SECONDS)
.build();
}
/**
* Execute authenticated request to Anchore Engine
*/
private Response executeRequest(Request request) throws IOException {
Response response = httpClient.newCall(request).execute();
if (!response.isSuccessful()) {
String errorBody = response.body() != null ? response.body().string() : "No error body";
logger.error("Anchore API request failed: {} - {}", response.code(), errorBody);
throw new AnchoreException("API request failed: " + response.code() + " - " + errorBody);
}
return response;
}
/**
* Create authenticated request builder
*/
private Request.Builder createAuthenticatedRequest() {
String credential = Credentials.basic(username, password);
return new Request.Builder()
.addHeader("Authorization", credential)
.addHeader("Content-Type", "application/json");
}
/**
* Get system status
*/
public SystemStatus getSystemStatus() throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/system")
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), SystemStatus.class);
}
}
/**
* Add image for analysis
*/
public ImageAnalysisResponse addImage(String imageTag, boolean force) throws IOException {
String json = objectMapper.writeValueAsString(new ImageAnalysisRequest(imageTag, force));
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/images")
.post(RequestBody.create(json, MediaType.parse("application/json")))
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), ImageAnalysisResponse.class);
}
}
/**
* Get image analysis status
*/
public ImageAnalysisStatus getImageStatus(String imageDigest) throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/images/" + imageDigest)
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), ImageAnalysisStatus.class);
}
}
/**
* Wait for image analysis to complete
*/
public void waitForAnalysis(String imageDigest, long timeoutMs) 
throws IOException, InterruptedException {
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < timeoutMs) {
ImageAnalysisStatus status = getImageStatus(imageDigest);
if ("analyzed".equals(status.getAnalysisStatus())) {
logger.info("Image analysis completed for: {}", imageDigest);
return;
} else if ("analysis_failed".equals(status.getAnalysisStatus())) {
throw new AnchoreException("Image analysis failed for: " + imageDigest);
}
logger.info("Waiting for image analysis... Current status: {}", 
status.getAnalysisStatus());
Thread.sleep(5000); // Wait 5 seconds between checks
}
throw new AnchoreException("Image analysis timeout for: " + imageDigest);
}
/**
* Get vulnerability report for image
*/
public VulnerabilityReport getVulnerabilities(String imageDigest) throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/images/" + imageDigest + "/vuln/all")
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), VulnerabilityReport.class);
}
}
/**
* Get policy evaluation for image
*/
public PolicyEvaluation evaluatePolicy(String imageDigest, String tag) throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/images/" + imageDigest + "/check?tag=" + tag + "&detail=true")
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), PolicyEvaluation.class);
}
}
/**
* Get image content (SBOM)
*/
public ImageContent getImageContent(String imageDigest) throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/images/" + imageDigest + "/content")
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), ImageContent.class);
}
}
/**
* List all policies
*/
public PolicyList listPolicies() throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/policies")
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), PolicyList.class);
}
}
/**
* Get specific policy
*/
public Policy getPolicy(String policyId) throws IOException {
Request request = createAuthenticatedRequest()
.url(baseUrl + "v1/policies/" + policyId)
.get()
.build();
try (Response response = executeRequest(request)) {
return objectMapper.readValue(response.body().string(), Policy.class);
}
}
// Custom exception
public static class AnchoreException extends RuntimeException {
public AnchoreException(String message) {
super(message);
}
public AnchoreException(String message, Throwable cause) {
super(message, cause);
}
}
}

Data Models

Response Data Classes

package com.anchore.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import java.util.Map;
// System Status
@JsonIgnoreProperties(ignoreUnknown = true)
class SystemStatus {
private String service;
private String version;
private String dbVersion;
// Getters and setters
public String getService() { return service; }
public void setService(String service) { this.service = service; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getDbVersion() { return dbVersion; }
public void setDbVersion(String dbVersion) { this.dbVersion = dbVersion; }
}
// Image Analysis Request
class ImageAnalysisRequest {
@JsonProperty("tag")
private String imageTag;
@JsonProperty("force")
private boolean forceAnalysis;
public ImageAnalysisRequest(String imageTag, boolean forceAnalysis) {
this.imageTag = imageTag;
this.forceAnalysis = forceAnalysis;
}
// Getters and setters
public String getImageTag() { return imageTag; }
public void setImageTag(String imageTag) { this.imageTag = imageTag; }
public boolean isForceAnalysis() { return forceAnalysis; }
public void setForceAnalysis(boolean forceAnalysis) { this.forceAnalysis = forceAnalysis; }
}
// Image Analysis Response
@JsonIgnoreProperties(ignoreUnknown = true)
class ImageAnalysisResponse {
private String imageDigest;
private List<AnalysisStatus> analysisStatus;
// Getters and setters
public String getImageDigest() { return imageDigest; }
public void setImageDigest(String imageDigest) { this.imageDigest = imageDigest; }
public List<AnalysisStatus> getAnalysisStatus() { return analysisStatus; }
public void setAnalysisStatus(List<AnalysisStatus> analysisStatus) { 
this.analysisStatus = analysisStatus; 
}
}
// Analysis Status
@JsonIgnoreProperties(ignoreUnknown = true)
class AnalysisStatus {
private String status;
private String tag;
// Getters and setters
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getTag() { return tag; }
public void setTag(String tag) { this.tag = tag; }
}
// Image Analysis Status
@JsonIgnoreProperties(ignoreUnknown = true)
class ImageAnalysisStatus {
private String imageDigest;
private String analysisStatus;
private List<ImageDetail> imageDetail;
// Getters and setters
public String getImageDigest() { return imageDigest; }
public void setImageDigest(String imageDigest) { this.imageDigest = imageDigest; }
public String getAnalysisStatus() { return analysisStatus; }
public void setAnalysisStatus(String analysisStatus) { this.analysisStatus = analysisStatus; }
public List<ImageDetail> getImageDetail() { return imageDetail; }
public void setImageDetail(List<ImageDetail> imageDetail) { this.imageDetail = imageDetail; }
}
// Image Detail
@JsonIgnoreProperties(ignoreUnknown = true)
class ImageDetail {
private String tag;
private String digest;
private String createdAt;
private String lastUpdated;
// Getters and setters
public String getTag() { return tag; }
public void setTag(String tag) { this.tag = tag; }
public String getDigest() { return digest; }
public void setDigest(String digest) { this.digest = digest; }
public String getCreatedAt() { return createdAt; }
public void setCreatedAt(String createdAt) { this.createdAt = createdAt; }
public String getLastUpdated() { return lastUpdated; }
public void setLastUpdated(String lastUpdated) { this.lastUpdated = lastUpdated; }
}
// Vulnerability Report
@JsonIgnoreProperties(ignoreUnknown = true)
class VulnerabilityReport {
private String imageDigest;
private List<Vulnerability> vulnerabilities;
private VulnerabilitySummary vulnerabilitySummary;
// Getters and setters
public String getImageDigest() { return imageDigest; }
public void setImageDigest(String imageDigest) { this.imageDigest = imageDigest; }
public List<Vulnerability> getVulnerabilities() { return vulnerabilities; }
public void setVulnerabilities(List<Vulnerability> vulnerabilities) { 
this.vulnerabilities = vulnerabilities; 
}
public VulnerabilitySummary getVulnerabilitySummary() { return vulnerabilitySummary; }
public void setVulnerabilitySummary(VulnerabilitySummary vulnerabilitySummary) { 
this.vulnerabilitySummary = vulnerabilitySummary; 
}
}
// Vulnerability
@JsonIgnoreProperties(ignoreUnknown = true)
class Vulnerability {
private String vuln;
private String severity;
private String packageName;
private String packageVersion;
private String packageType;
private String fix;
private String url;
private List<String> cweIds;
// Getters and setters
public String getVuln() { return vuln; }
public void setVuln(String vuln) { this.vuln = vuln; }
public String getSeverity() { return severity; }
public void setSeverity(String severity) { this.severity = severity; }
public String getPackageName() { return packageName; }
public void setPackageName(String packageName) { this.packageName = packageName; }
public String getPackageVersion() { return packageVersion; }
public void setPackageVersion(String packageVersion) { this.packageVersion = packageVersion; }
public String getPackageType() { return packageType; }
public void setPackageType(String packageType) { this.packageType = packageType; }
public String getFix() { return fix; }
public void setFix(String fix) { this.fix = fix; }
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
public List<String> getCweIds() { return cweIds; }
public void setCweIds(List<String> cweIds) { this.cweIds = cweIds; }
}
// Vulnerability Summary
@JsonIgnoreProperties(ignoreUnknown = true)
class VulnerabilitySummary {
private int critical;
private int high;
private int medium;
private int low;
private int negligible;
private int unknown;
private int total;
// Getters and setters
public int getCritical() { return critical; }
public void setCritical(int critical) { this.critical = critical; }
public int getHigh() { return high; }
public void setHigh(int high) { this.high = high; }
public int getMedium() { return medium; }
public void setMedium(int medium) { this.medium = medium; }
public int getLow() { return low; }
public void setLow(int low) { this.low = low; }
public int getNegligible() { return negligible; }
public void setNegligible(int negligible) { this.negligible = negligible; }
public int getUnknown() { return unknown; }
public void setUnknown(int unknown) { this.unknown = unknown; }
public int getTotal() { return total; }
public void setTotal(int total) { this.total = total; }
}
// Policy Evaluation
@JsonIgnoreProperties(ignoreUnknown = true)
class PolicyEvaluation {
private String imageDigest;
private List<PolicyResult> policyResults;
// Getters and setters
public String getImageDigest() { return imageDigest; }
public void setImageDigest(String imageDigest) { this.imageDigest = imageDigest; }
public List<PolicyResult> getPolicyResults() { return policyResults; }
public void setPolicyResults(List<PolicyResult> policyResults) { 
this.policyResults = policyResults; 
}
}
// Policy Result
@JsonIgnoreProperties(ignoreUnknown = true)
class PolicyResult {
private String policyId;
private String status;
private String tag;
private List<PolicyGateResult> gateResults;
// Getters and setters
public String getPolicyId() { return policyId; }
public void setPolicyId(String policyId) { this.policyId = policyId; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getTag() { return tag; }
public void setTag(String tag) { this.tag = tag; }
public List<PolicyGateResult> getGateResults() { return gateResults; }
public void setGateResults(List<PolicyGateResult> gateResults) { 
this.gateResults = gateResults; 
}
}
// Policy Gate Result
@JsonIgnoreProperties(ignoreUnknown = true)
class PolicyGateResult {
private String gate;
private String trigger;
private String status;
private String detail;
// Getters and setters
public String getGate() { return gate; }
public void setGate(String gate) { this.gate = gate; }
public String getTrigger() { return trigger; }
public void setTrigger(String trigger) { this.trigger = trigger; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getDetail() { return detail; }
public void setDetail(String detail) { this.detail = detail; }
}
// Image Content (SBOM)
@JsonIgnoreProperties(ignoreUnknown = true)
class ImageContent {
private String imageDigest;
private List<ContentEntry> content;
// Getters and setters
public String getImageDigest() { return imageDigest; }
public void setImageDigest(String imageDigest) { this.imageDigest = imageDigest; }
public List<ContentEntry> getContent() { return content; }
public void setContent(List<ContentEntry> content) { this.content = content; }
}
// Content Entry
@JsonIgnoreProperties(ignoreUnknown = true)
class ContentEntry {
private String packageType;
private String packageName;
private String packageVersion;
private String license;
private String location;
// Getters and setters
public String getPackageType() { return packageType; }
public void setPackageType(String packageType) { this.packageType = packageType; }
public String getPackageName() { return packageName; }
public void setPackageName(String packageName) { this.packageName = packageName; }
public String getPackageVersion() { return packageVersion; }
public void setPackageVersion(String packageVersion) { this.packageVersion = packageVersion; }
public String getLicense() { return license; }
public void setLicense(String license) { this.license = license; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
}
// Policy List
@JsonIgnoreProperties(ignoreUnknown = true)
class PolicyList {
private List<Policy> policies;
// Getters and setters
public List<Policy> getPolicies() { return policies; }
public void setPolicies(List<Policy> policies) { this.policies = policies; }
}
// Policy
@JsonIgnoreProperties(ignoreUnknown = true)
class Policy {
private String policyId;
private String name;
private String version;
private String comment;
private Map<String, Object> rules;
// Getters and setters
public String getPolicyId() { return policyId; }
public void setPolicyId(String policyId) { this.policyId = policyId; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public String getComment() { return comment; }
public void setComment(String comment) { this.comment = comment; }
public Map<String, Object> getRules() { return rules; }
public void setRules(Map<String, Object> rules) { this.rules = rules; }
}

Anchore Service Layer

Comprehensive Anchore Service

package com.anchore.service;
import com.anchore.client.AnchoreClient;
import com.anchore.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
public class AnchoreService {
private static final Logger logger = LoggerFactory.getLogger(AnchoreService.class);
private final AnchoreClient client;
private final long analysisTimeoutMs;
public AnchoreService(String baseUrl, String username, String password, long analysisTimeoutMs) {
this.client = new AnchoreClient(baseUrl, username, password);
this.analysisTimeoutMs = analysisTimeoutMs;
}
/**
* Check if Anchore Engine is available
*/
public boolean isAvailable() {
try {
SystemStatus status = client.getSystemStatus();
logger.info("Anchore Engine status: {} - Version: {}", 
status.getService(), status.getVersion());
return true;
} catch (Exception e) {
logger.error("Anchore Engine is not available: {}", e.getMessage());
return false;
}
}
/**
* Analyze image and wait for completion
*/
public ImageAnalysisStatus analyzeImage(String imageTag, boolean force) 
throws IOException, InterruptedException {
logger.info("Starting analysis for image: {}", imageTag);
// Add image for analysis
ImageAnalysisResponse response = client.addImage(imageTag, force);
String imageDigest = response.getImageDigest();
logger.info("Image analysis started. Digest: {}", imageDigest);
// Wait for analysis to complete
client.waitForAnalysis(imageDigest, analysisTimeoutMs);
// Get final status
return client.getImageStatus(imageDigest);
}
/**
* Get comprehensive security report for image
*/
public SecurityReport getSecurityReport(String imageTag) 
throws IOException, InterruptedException {
// First, ensure image is analyzed
ImageAnalysisStatus status = analyzeImage(imageTag, false);
String imageDigest = status.getImageDigest();
// Get vulnerabilities
VulnerabilityReport vulnReport = client.getVulnerabilities(imageDigest);
// Get policy evaluation
PolicyEvaluation policyEval = client.evaluatePolicy(imageDigest, imageTag);
// Get SBOM
ImageContent content = client.getImageContent(imageDigest);
return new SecurityReport(imageTag, imageDigest, vulnReport, policyEval, content);
}
/**
* Check if image passes security policy
*/
public PolicyCheckResult checkPolicyCompliance(String imageTag) 
throws IOException, InterruptedException {
ImageAnalysisStatus status = analyzeImage(imageTag, false);
String imageDigest = status.getImageDigest();
PolicyEvaluation policyEval = client.evaluatePolicy(imageDigest, imageTag);
boolean passed = policyEval.getPolicyResults().stream()
.allMatch(result -> "pass".equals(result.getStatus()));
List<String> failedPolicies = policyEval.getPolicyResults().stream()
.filter(result -> !"pass".equals(result.getStatus()))
.map(PolicyResult::getPolicyId)
.collect(Collectors.toList());
return new PolicyCheckResult(passed, failedPolicies, policyEval);
}
/**
* Get critical and high vulnerabilities
*/
public List<Vulnerability> getCriticalVulnerabilities(String imageTag) 
throws IOException, InterruptedException {
ImageAnalysisStatus status = analyzeImage(imageTag, false);
String imageDigest = status.getImageDigest();
VulnerabilityReport vulnReport = client.getVulnerabilities(imageDigest);
return vulnReport.getVulnerabilities().stream()
.filter(vuln -> "Critical".equalsIgnoreCase(vuln.getSeverity()) || 
"High".equalsIgnoreCase(vuln.getSeverity()))
.collect(Collectors.toList());
}
/**
* Generate SBOM for image
*/
public SBOM generateSBOM(String imageTag) throws IOException, InterruptedException {
ImageAnalysisStatus status = analyzeImage(imageTag, false);
String imageDigest = status.getImageDigest();
ImageContent content = client.getImageContent(imageDigest);
List<SBOM.Component> components = content.getContent().stream()
.map(entry -> new SBOM.Component(
entry.getPackageName(),
entry.getPackageVersion(),
entry.getPackageType(),
entry.getLicense(),
entry.getLocation()
))
.collect(Collectors.toList());
return new SBOM(imageTag, imageDigest, components);
}
// Custom result classes
public static class SecurityReport {
private final String imageTag;
private final String imageDigest;
private final VulnerabilityReport vulnerabilityReport;
private final PolicyEvaluation policyEvaluation;
private final ImageContent imageContent;
public SecurityReport(String imageTag, String imageDigest, 
VulnerabilityReport vulnerabilityReport,
PolicyEvaluation policyEvaluation, 
ImageContent imageContent) {
this.imageTag = imageTag;
this.imageDigest = imageDigest;
this.vulnerabilityReport = vulnerabilityReport;
this.policyEvaluation = policyEvaluation;
this.imageContent = imageContent;
}
// Getters
public String getImageTag() { return imageTag; }
public String getImageDigest() { return imageDigest; }
public VulnerabilityReport getVulnerabilityReport() { return vulnerabilityReport; }
public PolicyEvaluation getPolicyEvaluation() { return policyEvaluation; }
public ImageContent getImageContent() { return imageContent; }
}
public static class PolicyCheckResult {
private final boolean passed;
private final List<String> failedPolicies;
private final PolicyEvaluation evaluation;
public PolicyCheckResult(boolean passed, List<String> failedPolicies, 
PolicyEvaluation evaluation) {
this.passed = passed;
this.failedPolicies = failedPolicies;
this.evaluation = evaluation;
}
// Getters
public boolean isPassed() { return passed; }
public List<String> getFailedPolicies() { return failedPolicies; }
public PolicyEvaluation getEvaluation() { return evaluation; }
}
public static class SBOM {
private final String imageTag;
private final String imageDigest;
private final List<Component> components;
public SBOM(String imageTag, String imageDigest, List<Component> components) {
this.imageTag = imageTag;
this.imageDigest = imageDigest;
this.components = components;
}
// Getters
public String getImageTag() { return imageTag; }
public String getImageDigest() { return imageDigest; }
public List<Component> getComponents() { return components; }
public static class Component {
private final String name;
private final String version;
private final String type;
private final String license;
private final String location;
public Component(String name, String version, String type, 
String license, String location) {
this.name = name;
this.version = version;
this.type = type;
this.license = license;
this.location = location;
}
// Getters
public String getName() { return name; }
public String getVersion() { return version; }
public String getType() { return type; }
public String getLicense() { return license; }
public String getLocation() { return location; }
}
}
}

Spring Boot Integration

Configuration Class

package com.anchore.config;
import com.anchore.service.AnchoreService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AnchoreConfig {
@Value("${anchore.engine.url:http://localhost:8228}")
private String anchoreUrl;
@Value("${anchore.engine.username:admin}")
private String anchoreUsername;
@Value("${anchore.engine.password:foobar}")
private String anchorePassword;
@Value("${anchore.analysis.timeout.ms:300000}") // 5 minutes default
private long analysisTimeoutMs;
@Bean
public AnchoreService anchoreService() {
return new AnchoreService(anchoreUrl, anchoreUsername, anchorePassword, analysisTimeoutMs);
}
}

REST Controller

package com.anchore.controller;
import com.anchore.service.AnchoreService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/anchore")
public class AnchoreController {
private static final Logger logger = LoggerFactory.getLogger(AnchoreController.class);
@Autowired
private AnchoreService anchoreService;
@GetMapping("/status")
public ResponseEntity<Map<String, Object>> getStatus() {
Map<String, Object> response = new HashMap<>();
boolean available = anchoreService.isAvailable();
response.put("available", available);
response.put("service", "Anchore Engine");
return ResponseEntity.ok(response);
}
@PostMapping("/scan")
public ResponseEntity<Map<String, Object>> scanImage(
@RequestParam String image,
@RequestParam(defaultValue = "false") boolean force) {
Map<String, Object> response = new HashMap<>();
try {
var status = anchoreService.analyzeImage(image, force);
response.put("success", true);
response.put("image", image);
response.put("digest", status.getImageDigest());
response.put("status", status.getAnalysisStatus());
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("Image scan failed: {}", e.getMessage(), e);
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
@GetMapping("/report/{image}")
public ResponseEntity<Map<String, Object>> getSecurityReport(
@PathVariable String image,
@RequestParam(defaultValue = "latest") String tag) {
Map<String, Object> response = new HashMap<>();
String fullImage = image + ":" + tag;
try {
var report = anchoreService.getSecurityReport(fullImage);
var vulnSummary = report.getVulnerabilityReport().getVulnerabilitySummary();
response.put("success", true);
response.put("image", fullImage);
response.put("digest", report.getImageDigest());
// Vulnerability summary
Map<String, Object> vulnerabilities = new HashMap<>();
vulnerabilities.put("critical", vulnSummary.getCritical());
vulnerabilities.put("high", vulnSummary.getHigh());
vulnerabilities.put("medium", vulnSummary.getMedium());
vulnerabilities.put("low", vulnSummary.getLow());
vulnerabilities.put("total", vulnSummary.getTotal());
response.put("vulnerabilities", vulnerabilities);
// Policy status
boolean policyPassed = report.getPolicyEvaluation().getPolicyResults().stream()
.allMatch(result -> "pass".equals(result.getStatus()));
response.put("policyPassed", policyPassed);
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("Security report generation failed: {}", e.getMessage(), e);
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
@GetMapping("/compliance/{image}")
public ResponseEntity<Map<String, Object>> checkCompliance(
@PathVariable String image,
@RequestParam(defaultValue = "latest") String tag) {
Map<String, Object> response = new HashMap<>();
String fullImage = image + ":" + tag;
try {
var result = anchoreService.checkPolicyCompliance(fullImage);
response.put("success", true);
response.put("image", fullImage);
response.put("policyPassed", result.isPassed());
response.put("failedPolicies", result.getFailedPolicies());
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("Compliance check failed: {}", e.getMessage(), e);
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
@GetMapping("/sbom/{image}")
public ResponseEntity<Map<String, Object>> getSBOM(
@PathVariable String image,
@RequestParam(defaultValue = "latest") String tag) {
Map<String, Object> response = new HashMap<>();
String fullImage = image + ":" + tag;
try {
var sbom = anchoreService.generateSBOM(fullImage);
response.put("success", true);
response.put("image", fullImage);
response.put("digest", sbom.getImageDigest());
response.put("componentCount", sbom.getComponents().size());
response.put("components", sbom.getComponents());
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("SBOM generation failed: {}", e.getMessage(), e);
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
@GetMapping("/critical/{image}")
public ResponseEntity<Map<String, Object>> getCriticalVulnerabilities(
@PathVariable String image,
@RequestParam(defaultValue = "latest") String tag) {
Map<String, Object> response = new HashMap<>();
String fullImage = image + ":" + tag;
try {
var criticalVulns = anchoreService.getCriticalVulnerabilities(fullImage);
response.put("success", true);
response.put("image", fullImage);
response.put("criticalVulnerabilities", criticalVulns.size());
response.put("vulnerabilities", criticalVulns);
return ResponseEntity.ok(response);
} catch (Exception e) {
logger.error("Critical vulnerabilities check failed: {}", e.getMessage(), e);
response.put("success", false);
response.put("error", e.getMessage());
return ResponseEntity.badRequest().body(response);
}
}
}

CI/CD Pipeline Integration

Jenkins Pipeline Integration

package com.anchore.jenkins;
import com.anchore.service.AnchoreService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JenkinsAnchoreIntegration {
private static final Logger logger = LoggerFactory.getLogger(JenkinsAnchoreIntegration.class);
private final AnchoreService anchoreService;
private final String breakBuildOnCritical;
private final String breakBuildOnHigh;
private final String breakBuildOnPolicyFail;
public JenkinsAnchoreIntegration(AnchoreService anchoreService, 
String breakBuildOnCritical,
String breakBuildOnHigh,
String breakBuildOnPolicyFail) {
this.anchoreService = anchoreService;
this.breakBuildOnCritical = breakBuildOnCritical;
this.breakBuildOnHigh = breakBuildOnHigh;
this.breakBuildOnPolicyFail = breakBuildOnPolicyFail;
}
/**
* Execute security gate in CI/CD pipeline
*/
public PipelineResult executeSecurityGate(String imageTag) {
PipelineResult result = new PipelineResult();
try {
// Get security report
var report = anchoreService.getSecurityReport(imageTag);
var vulnSummary = report.getVulnerabilityReport().getVulnerabilitySummary();
// Check vulnerabilities
if ("true".equals(breakBuildOnCritical) && vulnSummary.getCritical() > 0) {
result.setPassed(false);
result.setReason("Critical vulnerabilities found: " + vulnSummary.getCritical());
} else if ("true".equals(breakBuildOnHigh) && vulnSummary.getHigh() > 0) {
result.setPassed(false);
result.setReason("High vulnerabilities found: " + vulnSummary.getHigh());
}
// Check policy compliance
if ("true".equals(breakBuildOnPolicyFail)) {
var policyResult = anchoreService.checkPolicyCompliance(imageTag);
if (!policyResult.isPassed()) {
result.setPassed(false);
result.setReason("Policy compliance failed: " + 
String.join(", ", policyResult.getFailedPolicies()));
}
}
// Set report data
result.setVulnerabilitySummary(vulnSummary);
result.setPolicyEvaluation(report.getPolicyEvaluation());
if (result.isPassed()) {
logger.info("Security gate passed for image: {}", imageTag);
} else {
logger.warn("Security gate failed for image: {} - {}", imageTag, result.getReason());
}
} catch (Exception e) {
result.setPassed(false);
result.setReason("Security analysis failed: " + e.getMessage());
logger.error("Security gate execution failed: {}", e.getMessage(), e);
}
return result;
}
public static class PipelineResult {
private boolean passed = true;
private String reason;
private VulnerabilitySummary vulnerabilitySummary;
private PolicyEvaluation policyEvaluation;
// Getters and setters
public boolean isPassed() { return passed; }
public void setPassed(boolean passed) { this.passed = passed; }
public String getReason() { return reason; }
public void setReason(String reason) { this.reason = reason; }
public VulnerabilitySummary getVulnerabilitySummary() { return vulnerabilitySummary; }
public void setVulnerabilitySummary(VulnerabilitySummary vulnerabilitySummary) { 
this.vulnerabilitySummary = vulnerabilitySummary; 
}
public PolicyEvaluation getPolicyEvaluation() { return policyEvaluation; }
public void setPolicyEvaluation(PolicyEvaluation policyEvaluation) { 
this.policyEvaluation = policyEvaluation; 
}
}
}

Advanced Features

Custom Policy Management

package com.anchore.policy;
import com.anchore.client.AnchoreClient;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class PolicyManager {
private static final Logger logger = LoggerFactory.getLogger(PolicyManager.class);
private final AnchoreClient client;
private final ObjectMapper objectMapper;
public PolicyManager(AnchoreClient client) {
this.client = client;
this.objectMapper = new ObjectMapper();
}
/**
* Create a custom security policy
*/
public boolean createPolicy(String policyId, String policyName, PolicyRules rules) 
throws IOException {
Map<String, Object> policyData = new HashMap<>();
policyData.put("policyId", policyId);
policyData.put("name", policyName);
policyData.put("version", "1.0");
policyData.put("comment", "Custom security policy");
policyData.put("rules", rules.toMap());
// This would use the actual Anchore policy API
// For demonstration, we're showing the structure
logger.info("Creating policy: {} with rules: {}", policyName, rules);
return true;
}
/**
* Policy rules builder
*/
public static class PolicyRules {
private boolean blockCriticalVulns = true;
private boolean blockHighVulns = false;
private boolean requireNonRoot = true;
private boolean blockSecrets = true;
private int maxImageAgeDays = 90;
public Map<String, Object> toMap() {
Map<String, Object> rules = new HashMap<>();
// Vulnerability rules
if (blockCriticalVulns) {
rules.put("vulnerabilities_critical", "stop");
}
if (blockHighVulns) {
rules.put("vulnerabilities_high", "stop");
}
// Security rules
if (requireNonRoot) {
rules.put("dockerfile_user", "warn");
}
if (blockSecrets) {
rules.put("secret_scan", "stop");
}
// Image age rule
rules.put("freshness", maxImageAgeDays + " days");
return rules;
}
// Builder methods
public PolicyRules blockCriticalVulns(boolean block) {
this.blockCriticalVulns = block;
return this;
}
public PolicyRules blockHighVulns(boolean block) {
this.blockHighVulns = block;
return this;
}
public PolicyRules requireNonRoot(boolean require) {
this.requireNonRoot = require;
return this;
}
public PolicyRules blockSecrets(boolean block) {
this.blockSecrets = block;
return this;
}
public PolicyRules maxImageAgeDays(int days) {
this.maxImageAgeDays = days;
return this;
}
}
}

Testing

Unit Tests

package com.anchore.test;
import com.anchore.client.AnchoreClient;
import com.anchore.service.AnchoreService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
class AnchoreServiceTest {
@Mock
private AnchoreClient mockClient;
private AnchoreService anchoreService;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
anchoreService = new AnchoreService("http://localhost:8228", "admin", "password", 30000);
// Would use reflection to inject mock client in real implementation
}
@Test
void testServiceAvailable() {
// Test service availability check
// Implementation would mock the client calls
}
@Test
void testImageAnalysis() {
// Test image analysis flow
// Mock client responses for addImage, getImageStatus, waitForAnalysis
}
@Test
void testPolicyComplianceCheck() {
// Test policy compliance checking
// Mock policy evaluation responses
}
@Test
void testVulnerabilityReporting() {
// Test vulnerability report generation
// Mock vulnerability data
}
}

Application Properties

Spring Boot Configuration

# Anchore Engine Configuration
anchore.engine.url=http://localhost:8228
anchore.engine.username=admin
anchore.engine.password=foobar
anchore.analysis.timeout.ms=300000
# Security Gate Settings
security.gate.break-on-critical=true
security.gate.break-on-high=false
security.gate.break-on-policy-fail=true
# Logging
logging.level.com.anchore=DEBUG

Conclusion

This comprehensive Anchore Engine integration for Java provides:

  1. Complete API client for Anchore Engine
  2. Security scanning service for container images
  3. Policy compliance checking with customizable rules
  4. Vulnerability reporting with severity filtering
  5. SBOM generation for software transparency
  6. CI/CD integration for pipeline security gates
  7. Spring Boot integration for easy configuration

Key benefits:

  • Automated security scanning in development pipelines
  • Policy-based compliance enforcement
  • Comprehensive vulnerability reporting
  • Software supply chain transparency
  • Production-ready integration

This implementation enables Java applications to leverage Anchore Engine for container security, making it ideal for DevOps teams implementing security in their CI/CD pipelines and runtime environments.

Leave a Reply

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


Macro Nepal Helper