Snyk Container in Java: Complete Container Security Guide


Article

Snyk Container provides comprehensive security scanning for container images, identifying vulnerabilities in both your application dependencies and the underlying OS packages. For Java applications running in containers, this is crucial for securing your deployment pipeline.

This guide covers everything from basic Snyk Container setup to advanced integration patterns with Java applications.

Snyk Container Architecture Overview

  • Image Scanning: Analyzes container images for vulnerabilities
  • Dependency Scanning: Java-specific vulnerability detection
  • Base Image Monitoring: Tracks vulnerabilities in parent images
  • CI/CD Integration: Automated scanning in pipelines
  • Policy Enforcement: Custom security rules and thresholds

1. Project Setup and Dependencies

Maven Dependencies:

<properties>
<snyk.java.version>1.119.0</snyk.java.version>
<jib.version>3.4.0</jib.version>
</properties>
<dependencies>
<!-- Snyk Java SDK (if available for programmatic access) -->
<dependency>
<groupId>io.snyk</groupId>
<artifactId>snyk-java-sdk</artifactId>
<version>${snyk.java.version}</version>
</dependency>
<!-- Snyk Maven Plugin -->
<dependency>
<groupId>io.snyk</groupId>
<artifactId>snyk-maven-plugin</artifactId>
<version>${snyk.java.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Jib for container building -->
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>${jib.version}</version>
</plugin>
</plugins>
</build>

2. Dockerfile Best Practices for Java

Secure Java Dockerfile:

# Multi-stage build for security and minimal image size
FROM eclipse-temurin:17-jdk-jammy as builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
# Production stage
FROM eclipse-temurin:17-jre-jammy as production
# Security best practices
RUN groupadd -r spring && useradd -r -g spring spring \
&& mkdir -p /app \
&& chown -R spring:spring /app
USER spring:spring
WORKDIR /app
# Copy application from builder stage
COPY --from=builder --chown=spring:spring /app/target/*.jar app.jar
# Security configurations
ENV JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -Dspring.profiles.active=prod"
ENV JAVA_TOOL_OPTIONS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
# Non-root user already set
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
# Secure entrypoint
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Distroless Java Dockerfile:

# Using distroless for minimal attack surface
FROM eclipse-temurin:17-jdk-jammy as builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
# Distroless Java runtime
FROM gcr.io/distroless/java17-debian11:nonroot
# Copy application
COPY --from=builder /app/target/*.jar /app/app.jar
WORKDIR /app
USER nonroot:nonroot
EXPOSE 8080
CMD ["app.jar"]

3. Snyk CLI Container Scanning

Basic Container Scanning:

# Install Snyk CLI
curl https://static.snyk.io/cli/latest/snyk-linux -o snyk
chmod +x snyk
sudo mv snyk /usr/local/bin/
# Authenticate with Snyk
snyk auth $SNYK_TOKEN
# Scan local Docker image
snyk container test my-java-app:1.0.0
# Scan with specific options
snyk container test my-java-app:1.0.0 \
--file=Dockerfile \
--org=my-team \
--project-name="my-java-app" \
--severity-threshold=high
# Monitor and track results
snyk container monitor my-java-app:1.0.0 \
--file=Dockerfile \
--project-name="my-java-app" \
--tags=production,backend

Advanced Scanning Script:

#!/bin/bash
# snyk-container-scan.sh
set -e
IMAGE_NAME="my-java-app"
IMAGE_TAG="${1:-latest}"
SNYK_ORG="${SNYK_ORG:-my-team}"
SEVERITY_THRESHOLD="${SEVERITY_THRESHOLD:-high}"
FAIL_ON_ISSUES="${FAIL_ON_ISSUES:-true}"
echo "🔍 Scanning container image: ${IMAGE_NAME}:${IMAGE_TAG}"
# Build image if not exists
if ! docker image inspect "${IMAGE_NAME}:${IMAGE_TAG}" > /dev/null 2>&1; then
echo "📦 Building Docker image..."
docker build -t "${IMAGE_NAME}:${IMAGE_TAG}" .
fi
# Run Snyk container test
echo "🚀 Starting Snyk container scan..."
snyk container test "${IMAGE_NAME}:${IMAGE_TAG}" \
--file=Dockerfile \
--org="${SNYK_ORG}" \
--severity-threshold="${SEVERITY_THRESHOLD}" \
--json > snyk-container-results.json
# Check for critical vulnerabilities
CRITICAL_COUNT=$(jq '.uniqueCounts.critical // 0' snyk-container-results.json)
HIGH_COUNT=$(jq '.uniqueCounts.high // 0' snyk-container-results.json)
echo "📊 Scan Results:"
echo "   Critical: $CRITICAL_COUNT"
echo "   High: $HIGH_COUNT"
# Fail build if critical/high vulnerabilities found and FAIL_ON_ISSUES is true
if [ "$FAIL_ON_ISSUES" = "true" ] && [ "$CRITICAL_COUNT" -gt 0 ] || [ "$HIGH_COUNT" -gt 0 ]; then
echo "❌ Critical or High vulnerabilities found. Failing build."
exit 1
fi
# Monitor to Snyk platform
echo "📈 Monitoring results to Snyk platform..."
snyk container monitor "${IMAGE_NAME}:${IMAGE_TAG}" \
--file=Dockerfile \
--org="${SNYK_ORG}" \
--project-name="${IMAGE_NAME}" \
--tags="java,spring-boot,${IMAGE_TAG}"
echo "✅ Container scan completed successfully"

4. Maven Integration

Snyk Maven Plugin Configuration:

<plugin>
<groupId>io.snyk</groupId>
<artifactId>snyk-maven-plugin</artifactId>
<version>1.119.0</version>
<configuration>
<apiToken>${env.SNYK_TOKEN}</apiToken>
<org>my-team</org>
<projectName>${project.artifactId}</projectName>
<tags>
<tag>java</tag>
<tag>container</tag>
<tag>${project.version}</tag>
</tags>
<severityThreshold>high</severityThreshold>
<failOnSeverityThreshold>true</failOnSeverityThreshold>
</configuration>
<executions>
<execution>
<id>snyk-test</id>
<phase>verify</phase>
<goals>
<goal>test</goal>
</goals>
</execution>
<execution>
<id>snyk-monitor</id>
<phase>deploy</phase>
<goals>
<goal>monitor</goal>
</goals>
</execution>
</executions>
</plugin>

Jib + Snyk Integration:

<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<from>
<image>eclipse-temurin:17-jre-jammy</image>
<platforms>
<platform>
<architecture>amd64</architecture>
<os>linux</os>
</platform>
</platforms>
</from>
<to>
<image>my-registry.com/my-java-app:${project.version}</image>
</to>
<container>
<entrypoint>
<shell>bash</shell>
<option>-c</option>
<arg>chmod +x /entrypoint.sh &amp;&amp; /entrypoint.sh</arg>
</entrypoint>
<ports>
<port>8080</port>
</ports>
<environment>
<JAVA_TOOL_OPTIONS>-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0</JAVA_TOOL_OPTIONS>
</environment>
<creationTime>USE_CURRENT_TIMESTAMP</creationTime>
</container>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>

5. CI/CD Integration

Jenkins Pipeline:

// Jenkinsfile
pipeline {
agent any
environment {
SNYK_TOKEN = credentials('snyk-api-token')
DOCKER_REGISTRY = 'my-registry.com'
}
stages {
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Build Container') {
steps {
script {
// Build with Jib
sh 'mvn compile jib:build -DskipTests'
// Or traditional Docker build
sh '''
docker build -t ${DOCKER_REGISTRY}/my-java-app:${BUILD_NUMBER} .
docker push ${DOCKER_REGISTRY}/my-java-app:${BUILD_NUMBER}
'''
}
}
}
stage('Snyk Container Scan') {
steps {
script {
// Test container image
sh '''
snyk container test ${DOCKER_REGISTRY}/my-java-app:${BUILD_NUMBER} \
--file=Dockerfile \
--org=my-team \
--severity-threshold=high \
--json-file-output=snyk-container-results.json
'''
// Monitor to Snyk platform
sh '''
snyk container monitor ${DOCKER_REGISTRY}/my-java-app:${BUILD_NUMBER} \
--file=Dockerfile \
--org=my-team \
--project-name="my-java-app"
'''
// Check for critical vulnerabilities
def scanResults = readJSON file: 'snyk-container-results.json'
def criticalCount = scanResults.uniqueCounts.critical ?: 0
def highCount = scanResults.uniqueCounts.high ?: 0
if (criticalCount > 0 || highCount > 0) {
error "Found ${criticalCount} critical and ${highCount} high vulnerabilities"
}
}
}
}
stage('Dependency Scan') {
steps {
sh 'mvn snyk:test'
}
}
}
post {
always {
// Archive Snyk reports
archiveArtifacts artifacts: 'snyk-*.json', fingerprint: true
// Cleanup
sh 'docker system prune -f'
}
}
}

GitHub Actions Workflow:

# .github/workflows/snyk-container.yml
name: Snyk Container Security
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 0 * * 1'  # Weekly scan
env:
IMAGE_NAME: my-java-app
REGISTRY: ghcr.io
jobs:
snyk-container-scan:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
security-events: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build Docker image
run: |
docker build -t $IMAGE_NAME:${{ github.sha }} .
- name: Run Snyk to check Docker image for vulnerabilities
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: $IMAGE_NAME:${{ github.sha }}
args: |
--file=Dockerfile 
--org=my-team 
--severity-threshold=high
--sarif-file-output=snyk-container.sarif
- name: Upload SARIF results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: snyk-container.sarif
- name: Monitor container in Snyk
uses: snyk/actions/docker@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
image: $IMAGE_NAME:${{ github.sha }}
command: monitor
args: |
--file=Dockerfile
--org=my-team
--project-name=$IMAGE_NAME
snyk-dependency-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/maven@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: |
--org=my-team 
--severity-threshold=high
--sarif-file-output=snyk-dependency.sarif
- name: Upload SARIF results to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: snyk-dependency.sarif

6. Programmatic Java Integration

Snyk Container Scanner Service:

package com.example.security.snyk;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
public class SnykContainerScanner {
private final ObjectMapper objectMapper;
private final String snykToken;
private final String snykOrg;
public SnykContainerScanner() {
this.objectMapper = new ObjectMapper();
this.snykToken = System.getenv("SNYK_TOKEN");
this.snykOrg = System.getenv("SNYK_ORG");
}
public ContainerScanResult scanImage(String imageName, String imageTag) 
throws IOException, InterruptedException {
String fullImageName = imageName + ":" + imageTag;
// Prepare Snyk command
List<String> command = new ArrayList<>();
command.add("snyk");
command.add("container");
command.add("test");
command.add(fullImageName);
command.add("--org=" + snykOrg);
command.add("--json");
command.add("--severity-threshold=high");
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.environment().put("SNYK_TOKEN", snykToken);
// Execute Snyk scan
Process process = processBuilder.start();
boolean completed = process.waitFor(10, TimeUnit.MINUTES);
if (!completed) {
throw new RuntimeException("Snyk scan timed out");
}
// Parse JSON output
try (InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
StringBuilder jsonOutput = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
jsonOutput.append(line);
}
return parseScanResults(jsonOutput.toString(), fullImageName);
}
}
private ContainerScanResult parseScanResults(String jsonOutput, String imageName) 
throws IOException {
JsonNode root = objectMapper.readTree(jsonOutput);
ContainerScanResult result = new ContainerScanResult();
result.setImageName(imageName);
result.setScanTimestamp(System.currentTimeMillis());
// Parse vulnerabilities
if (root.has("vulnerabilities")) {
for (JsonNode vuln : root.get("vulnerabilities")) {
Vulnerability vulnerability = new Vulnerability();
vulnerability.setId(vuln.get("id").asText());
vulnerability.setTitle(vuln.get("title").asText());
vulnerability.setSeverity(vuln.get("severity").asText());
vulnerability.setPackageName(vuln.get("packageName").asText());
if (vuln.has("cvssScore")) {
vulnerability.setCvssScore(vuln.get("cvssScore").asDouble());
}
result.addVulnerability(vulnerability);
}
}
// Parse summary
if (root.has("uniqueCounts")) {
JsonNode counts = root.get("uniqueCounts");
result.setCriticalCount(counts.has("critical") ? counts.get("critical").asInt() : 0);
result.setHighCount(counts.has("high") ? counts.get("high").asInt() : 0);
result.setMediumCount(counts.has("medium") ? counts.get("medium").asInt() : 0);
result.setLowCount(counts.has("low") ? counts.get("low").asInt() : 0);
}
return result;
}
public void monitorImage(String imageName, String imageTag, String projectName) 
throws IOException, InterruptedException {
String fullImageName = imageName + ":" + imageTag;
List<String> command = new ArrayList<>();
command.add("snyk");
command.add("container");
command.add("monitor");
command.add(fullImageName);
command.add("--org=" + snykOrg);
command.add("--project-name=" + projectName);
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.environment().put("SNYK_TOKEN", snykToken);
Process process = processBuilder.start();
process.waitFor(2, TimeUnit.MINUTES);
}
public boolean passesSecurityGate(ContainerScanResult result, SecurityPolicy policy) {
return result.getCriticalCount() <= policy.getMaxCritical() &&
result.getHighCount() <= policy.getMaxHigh() &&
result.getMediumCount() <= policy.getMaxMedium();
}
}
class ContainerScanResult {
private String imageName;
private long scanTimestamp;
private int criticalCount;
private int highCount;
private int mediumCount;
private int lowCount;
private List<Vulnerability> vulnerabilities = new ArrayList<>();
// Getters and setters
public String getImageName() { return imageName; }
public void setImageName(String imageName) { this.imageName = imageName; }
public long getScanTimestamp() { return scanTimestamp; }
public void setScanTimestamp(long scanTimestamp) { this.scanTimestamp = scanTimestamp; }
public int getCriticalCount() { return criticalCount; }
public void setCriticalCount(int criticalCount) { this.criticalCount = criticalCount; }
public int getHighCount() { return highCount; }
public void setHighCount(int highCount) { this.highCount = highCount; }
public int getMediumCount() { return mediumCount; }
public void setMediumCount(int mediumCount) { this.mediumCount = mediumCount; }
public int getLowCount() { return lowCount; }
public void setLowCount(int lowCount) { this.lowCount = lowCount; }
public List<Vulnerability> getVulnerabilities() { return vulnerabilities; }
public void addVulnerability(Vulnerability vulnerability) { this.vulnerabilities.add(vulnerability); }
}
class Vulnerability {
private String id;
private String title;
private String severity;
private String packageName;
private double cvssScore;
private String description;
private List<String> identifiers = new ArrayList<>();
// Getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
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 double getCvssScore() { return cvssScore; }
public void setCvssScore(double cvssScore) { this.cvssScore = cvssScore; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public List<String> getIdentifiers() { return identifiers; }
public void addIdentifier(String identifier) { this.identifiers.add(identifier); }
}
class SecurityPolicy {
private int maxCritical = 0;
private int maxHigh = 5;
private int maxMedium = 20;
// Getters and setters
public int getMaxCritical() { return maxCritical; }
public void setMaxCritical(int maxCritical) { this.maxCritical = maxCritical; }
public int getMaxHigh() { return maxHigh; }
public void setMaxHigh(int maxHigh) { this.maxHigh = maxHigh; }
public int getMaxMedium() { return maxMedium; }
public void setMaxMedium(int maxMedium) { this.maxMedium = maxMedium; }
}

7. Advanced Container Security Features

Runtime Security Monitoring:

package com.example.security.snyk;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@Component
public class ContainerSecurityHealthIndicator implements HealthIndicator {
private final SnykContainerScanner containerScanner;
private final ScheduledExecutorService scheduler;
private ContainerScanResult lastScanResult;
private Instant lastScanTime;
public ContainerSecurityHealthIndicator(SnykContainerScanner containerScanner) {
this.containerScanner = containerScanner;
this.scheduler = Executors.newSingleThreadScheduledExecutor();
startPeriodicScans();
}
private void startPeriodicScans() {
// Scan every 24 hours
scheduler.scheduleAtFixedRate(this::performSecurityScan, 0, 24, TimeUnit.HOURS);
}
private void performSecurityScan() {
try {
String imageName = System.getenv("CONTAINER_IMAGE_NAME");
String imageTag = System.getenv("CONTAINER_IMAGE_TAG");
if (imageName != null && imageTag != null) {
lastScanResult = containerScanner.scanImage(imageName, imageTag);
lastScanTime = Instant.now();
}
} catch (Exception e) {
System.err.println("Failed to perform security scan: " + e.getMessage());
}
}
@Override
public Health health() {
if (lastScanResult == null) {
return Health.unknown()
.withDetail("message", "Security scan not yet performed")
.build();
}
long hoursSinceScan = ChronoUnit.HOURS.between(lastScanTime, Instant.now());
Health.Builder healthBuilder;
if (lastScanResult.getCriticalCount() > 0) {
healthBuilder = Health.down();
} else if (lastScanResult.getHighCount() > 5 || hoursSinceScan > 48) {
healthBuilder = Health.outOfService();
} else {
healthBuilder = Health.up();
}
return healthBuilder
.withDetail("lastScan", lastScanTime.toString())
.withDetail("criticalVulnerabilities", lastScanResult.getCriticalCount())
.withDetail("highVulnerabilities", lastScanResult.getHighCount())
.withDetail("mediumVulnerabilities", lastScanResult.getMediumCount())
.build();
}
@PreDestroy
public void cleanup() {
scheduler.shutdown();
}
}

Security Policy Enforcement:

package com.example.security.snyk;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
@Component
public class ContainerSecurityEnforcer implements ApplicationListener<ContextRefreshedEvent> {
private final SnykContainerScanner containerScanner;
private final SecurityPolicy securityPolicy;
public ContainerSecurityEnforcer(SnykContainerScanner containerScanner, 
SecurityPolicy securityPolicy) {
this.containerScanner = containerScanner;
this.securityPolicy = securityPolicy;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
String imageName = System.getenv("CONTAINER_IMAGE_NAME");
String imageTag = System.getenv("CONTAINER_IMAGE_TAG");
if (imageName != null && imageTag != null) {
ContainerScanResult result = containerScanner.scanImage(imageName, imageTag);
if (!containerScanner.passesSecurityGate(result, securityPolicy)) {
throw new SecurityException(
"Container security policy violation: " +
result.getCriticalCount() + " critical, " +
result.getHighCount() + " high vulnerabilities found"
);
}
// Monitor to Snyk platform
containerScanner.monitorImage(imageName, imageTag, "my-java-app");
}
} catch (Exception e) {
System.err.println("Security enforcement failed: " + e.getMessage());
// In production, you might want to exit the application
// System.exit(1);
}
}
}

8. Custom Base Image Security

Secure Base Image Builder:

# secure-java-base/Dockerfile
FROM eclipse-temurin:17-jre-jammy
# Security updates
RUN apt-get update && apt-get upgrade -y && \
apt-get clean && rm -rf /var/lib/apt/lists/*
# Security hardening
RUN groupadd -r spring && useradd -r -g spring spring && \
mkdir -p /app && chown -R spring:spring /app
# Remove unnecessary packages
RUN apt-get purge -y --auto-remove && \
rm -rf /var/lib/apt/lists/*
# Security configurations
RUN echo "networkaddress.cache.ttl=60" >> $JAVA_HOME/conf/security/java.security
USER spring:spring
WORKDIR /app

Base Image Scanning Script:

#!/bin/bash
# scan-base-images.sh
BASE_IMAGES=(
"eclipse-temurin:17-jre-jammy"
"eclipse-temurin:11-jre-jammy"
"gcr.io/distroless/java17-debian11:nonroot"
)
for image in "${BASE_IMAGES[@]}"; do
echo "🔍 Scanning base image: $image"
# Pull latest version
docker pull "$image"
# Scan with Snyk
snyk container test "$image" \
--severity-threshold=high \
--json > "scan-$(echo $image | tr '/:' '-').json"
# Check for critical vulnerabilities
critical_count=$(jq '.uniqueCounts.critical // 0' "scan-$(echo $image | tr '/:' '-').json")
if [ "$critical_count" -gt 0 ]; then
echo "❌ $image has $critical_count critical vulnerabilities"
else
echo "✅ $image passed security scan"
fi
done

9. Kubernetes Integration

Kubernetes Deployment with Security Context:

# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-java-app
labels:
app: my-java-app
spec:
replicas: 3
selector:
matchLabels:
app: my-java-app
template:
metadata:
labels:
app: my-java-app
annotations:
snyk.io/container-image: "my-registry.com/my-java-app:1.0.0"
snyk.io/monitored: "true"
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: java-app
image: my-registry.com/my-java-app:1.0.0
securityContext:
allowPrivilegeEscalation: false
runAsNonRoot: true
runAsUser: 1000
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
env:
- name: JAVA_TOOL_OPTIONS
value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"

Snyk Kubernetes Monitoring:

# Install Snyk Monitor for Kubernetes
helm repo add snyk https://snyk.github.io/kubernetes-monitor
helm repo update
helm upgrade --install snyk-monitor snyk/snyk-monitor \
--namespace snyk-monitor \
--create-namespace \
--set clusterName="production" \
--set integrationApi=$SNYK_INTEGRATION_ID

10. Reporting and Alerting

Security Dashboard Integration:

package com.example.security.snyk;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class SecurityReportingService {
private final SnykContainerScanner containerScanner;
private final SecurityAlertService alertService;
public SecurityReportingService(SnykContainerScanner containerScanner,
SecurityAlertService alertService) {
this.containerScanner = containerScanner;
this.alertService = alertService;
}
@Scheduled(cron = "0 0 9 * * MON") // Every Monday at 9 AM
public void generateWeeklySecurityReport() {
try {
List<String> images = List.of(
"my-java-app:latest",
"my-java-app:1.0.0",
"my-base-image:latest"
);
List<ContainerScanResult> results = images.stream()
.map(image -> {
try {
String[] parts = image.split(":");
return containerScanner.scanImage(parts[0], parts[1]);
} catch (Exception e) {
return null;
}
})
.filter(result -> result != null)
.collect(Collectors.toList());
SecurityReport report = generateReport(results);
alertService.sendWeeklyReport(report);
} catch (Exception e) {
System.err.println("Failed to generate security report: " + e.getMessage());
}
}
private SecurityReport generateReport(List<ContainerScanResult> results) {
SecurityReport report = new SecurityReport();
int totalCritical = results.stream().mapToInt(ContainerScanResult::getCriticalCount).sum();
int totalHigh = results.stream().mapToInt(ContainerScanResult::getHighCount).sum();
report.setTotalCritical(totalCritical);
report.setTotalHigh(totalHigh);
report.setScanResults(results);
report.setGeneratedAt(System.currentTimeMillis());
return report;
}
}
class SecurityReport {
private int totalCritical;
private int totalHigh;
private List<ContainerScanResult> scanResults;
private long generatedAt;
// Getters and setters
public int getTotalCritical() { return totalCritical; }
public void setTotalCritical(int totalCritical) { this.totalCritical = totalCritical; }
public int getTotalHigh() { return totalHigh; }
public void setTotalHigh(int totalHigh) { this.totalHigh = totalHigh; }
public List<ContainerScanResult> getScanResults() { return scanResults; }
public void setScanResults(List<ContainerScanResult> scanResults) { this.scanResults = scanResults; }
public long getGeneratedAt() { return generatedAt; }
public void setGeneratedAt(long generatedAt) { this.generatedAt = generatedAt; }
}

Conclusion

Snyk Container provides comprehensive security scanning for Java applications in containers:

  1. Vulnerability Detection: OS packages and Java dependencies
  2. Base Image Security: Monitor parent image vulnerabilities
  3. CI/CD Integration: Automated scanning in pipelines
  4. Policy Enforcement: Custom security gates
  5. Runtime Monitoring: Continuous security assessment

Key Benefits for Java Applications:

  • Comprehensive vulnerability coverage
  • Integration with existing Java tooling
  • Automated security enforcement
  • Regulatory compliance support
  • Supply chain security

By implementing Snyk Container scanning throughout your Java container lifecycle, you can significantly improve your application security posture and catch vulnerabilities before they reach production.

Secure Java Supply Chain, Minimal Containers & Runtime Security (Alpine, Distroless, Signing, SBOM & Kubernetes Controls)

https://macronepal.com/blog/alpine-linux-security-in-java-complete-guide/
Explains how Alpine Linux is used as a lightweight base for Java containers to reduce image size and attack surface, while discussing tradeoffs like musl compatibility, CVE handling, and additional hardening requirements for production security.

https://macronepal.com/blog/the-minimalists-approach-building-ultra-secure-java-applications-with-scratch-base-images/
Explains using scratch base images for Java applications to create extremely minimal containers with almost zero attack surface, where only the compiled Java application and runtime dependencies exist.

https://macronepal.com/blog/distroless-containers-in-java-minimal-secure-containers-for-jvm-applications/
Explains distroless Java containers that remove shells, package managers, and unnecessary OS tools, significantly reducing vulnerabilities while improving security posture for JVM workloads.

https://macronepal.com/blog/revolutionizing-container-security-implementing-chainguard-images-for-java-applications/
Explains Chainguard images for Java, which are secure-by-default, CVE-minimized container images with SBOMs and cryptographic signing, designed for modern supply-chain security.

https://macronepal.com/blog/seccomp-filtering-in-java-comprehensive-security-sandboxing/
Explains seccomp syscall filtering in Linux to restrict what system calls Java applications can make, reducing the impact of exploits by limiting kernel-level access.

https://macronepal.com/blog/in-toto-attestations-in-java/
Explains in-toto framework integration in Java to create cryptographically verifiable attestations across the software supply chain, ensuring every build step is trusted and auditable.

https://macronepal.com/blog/fulcio-integration-in-java-code-signing-certificate-infrastructure/
Explains Fulcio integration for Java, which issues short-lived certificates for code signing in a zero-trust supply chain, enabling secure identity-based signing of artifacts.

https://macronepal.com/blog/tekton-supply-chain-in-java-comprehensive-ci-cd-pipeline-implementation/
Explains using Tekton CI/CD pipelines for Java applications to automate secure builds, testing, signing, and deployment with supply-chain security controls built in.

https://macronepal.com/blog/slsa-provenance-in-java-complete-guide-to-supply-chain-security-2/
Explains SLSA (Supply-chain Levels for Software Artifacts) provenance in Java builds, ensuring traceability of how software is built, from source code to final container image.

https://macronepal.com/blog/notary-project-in-java-complete-implementation-guide/
Explains the Notary Project for Java container security, enabling cryptographic signing and verification of container images and artifacts to prevent tampering in deployment pipelines.

Leave a Reply

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


Macro Nepal Helper