Securing the Java Supply Chain: A Guide to Aqua Security Scanning

In the modern software development lifecycle, Java applications are built by assembling open-source dependencies, base images, and custom code. This complex supply chain introduces significant security risks, from vulnerable libraries to misconfigured containers. Aqua Security is a leading Cloud Native Application Protection Platform (CNAPP) that provides comprehensive scanning capabilities to identify and remediate these risks throughout the CI/CD pipeline and runtime environment.

This article explores how Aqua Security scans Java applications, the types of vulnerabilities it detects, and how to integrate it into your development workflow for a more secure software supply chain.


What is Aqua Security?

Aqua Security is a holistic security platform designed specifically for cloud-native applications. Its scanning capabilities cover the entire application lifecycle, from code to runtime. For Java developers, the most relevant components are:

  1. Aqua Trivy (Open Source): A comprehensive vulnerability scanner for containers, file systems, and Git repositories.
  2. Aqua CSP (Commercial Platform): Provides advanced scanning, compliance checks, and runtime security.

Why Scan Java Applications?

Java applications have unique security challenges:

  • Vulnerable Dependencies: Maven and Gradle projects can pull in hundreds of transitive dependencies, any of which could contain known vulnerabilities (CVEs).
  • Container Image Risks: The base image (e.g., openjdk:17), the JVM, and the application code itself can all introduce security issues.
  • Secrets in Code: Accidentally committed API keys, passwords, and certificates in source code or configuration files.
  • Infrastructure as Code (IaC) Misconfigurations: Unsafe Kubernetes manifests or Dockerfiles that deploy your Java application.

Key Scanning Capabilities for Java

1. Software Composition Analysis (SCA) - Dependency Scanning

Aqua scans your project's dependency manifest files (pom.xml, build.gradle) to identify vulnerable libraries.

What it detects:

  • Known vulnerabilities (CVEs) in direct and transitive dependencies
  • License compliance issues
  • Outdated packages with available patches

Example Vulnerabilities Found:

  • Log4Shell (CVE-2021-44228) in log4j-core
  • Spring4Shell (CVE-2022-22965) in Spring Framework
  • Apache Commons Text RCE (CVE-2022-42889)

2. Container Image Scanning

Aqua thoroughly scans Java application container images, analyzing:

  • Operating System Packages: Vulnerabilities in the base OS (e.g., Alpine, Debian)
  • Java-Specific Layers:
    • Base JDK/JRE image vulnerabilities
    • Application JAR/WAR files
    • Dependencies within the image
  • Configuration Issues:
    • Running as root user
    • Unnecessary privileges
    • Exposed sensitive ports

3. Infrastructure as Code (IaC) Security

Scans Dockerfiles, Kubernetes YAML, and Helm charts for security misconfigurations before deployment.

Java-specific IaC checks:

  • Using outdated base images (openjdk:8 instead of openjdk:17)
  • Including JDK instead of JRE in production images
  • Not setting memory limits for JVM in Kubernetes
  • Running container as root

4. Secrets Detection

Scans code repositories and container images for accidentally exposed secrets:

  • Database passwords in application.properties
  • API keys in source code
  • Cloud credentials in configuration files

5. Malware Detection

Identifies known malware and crypto miners in container images and dependencies.


Practical Implementation Examples

Example 1: Scanning a Java Project with Aqua Trivy

Scanning Dependencies:

# Scan a Maven project for vulnerabilities
trivy fs . --scanners vuln
# Scan with specific dependency focus
trivy fs . --scanners vuln --include-packages "log4j*,spring-core"
# Output example
my-spring-app/pom.xml
════════════════════════════════════════
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
┌───────────────┬───────────────┬──────────┬──────────┬───────────────────┬───────────────┬─────────────────────────────────────────────┐
│    Library    │ Vulnerability │ Severity │ Status   │ Installed Version │ Fixed Version │                    Title                    │
├───────────────┼───────────────┼──────────┼──────────┼───────────────────┼───────────────┼─────────────────────────────────────────────┤
│ log4j-core    │ CVE-2021-44228│ HIGH     │ affected │ 2.14.1            │ 2.17.0        │ Apache Log4j2 vulnerable to remote code    │
│               │               │          │          │                   │               │ execution when configured to use JNDI      │
└───────────────┴───────────────┴──────────┴──────────┴───────────────────┴───────────────┴─────────────────────────────────────────────┘

Scanning Container Images:

# Build your Java application image
docker build -t my-java-app:latest .
# Scan the image with Trivy
trivy image my-java-app:latest
# Scan with specific output format for CI/CD
trivy image --format sarif --output results.sarif my-java-app:latest
# Scan with severity threshold
trivy image --severity HIGH,CRITICAL my-java-app:latest

Example 2: CI/CD Integration with GitHub Actions

.github/workflows/aqua-scan.yml

name: Aqua Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Build Java application
run: mvn clean package -DskipTests
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'HIGH,CRITICAL'
- name: Build Docker image
run: docker build -t my-java-app:${{ github.sha }} .
- name: Scan Docker image
uses: aquasecurity/trivy-action@master
with:
scan-type: 'image'
scan-ref: 'my-java-app:${{ github.sha }}'
format: 'table'
exit-code: 1
severity: 'CRITICAL'
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
if: always()
with:
sarif_file: 'trivy-results.sarif'

Example 3: Aqua Enterprise Scanning in Pipeline

For commercial Aqua CSP, the scanning is typically integrated like this:

# Example Jenkins pipeline
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
sh 'docker build -t my-registry/my-java-app:${BUILD_NUMBER} .'
}
}
stage('Aqua Security Scan') {
steps {
// Scan with Aqua CSP scanner
sh 'aqua scan image my-registry/my-java-app:${BUILD_NUMBER}'
// Check for policy compliance
sh 'aqua cli scan --local image my-registry/my-java-app:${BUILD_NUMBER} --register --check-only'
}
}
stage('Deploy') {
when {
expression { currentBuild.result == 'SUCCESS' }
}
steps {
sh 'kubectl set image deployment/my-app app=my-registry/my-java-app:${BUILD_NUMBER}'
}
}
}
post {
always {
// Clean up images
sh 'docker rmi my-registry/my-java-app:${BUILD_NUMBER} || true'
}
}
}

Remediation Strategies for Common Java Findings

1. Vulnerable Dependencies

<!-- In pom.xml - BEFORE -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version> <!-- Vulnerable version -->
</dependency>
<!-- AFTER -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version> <!-- Patched version -->
</dependency>

Use tools like: mvn versions:use-latest-versions or ./gradlew dependencyUpdates

2. Insecure Base Images

# ❌ Insecure Dockerfile
FROM openjdk:8u181 # Old, vulnerable JDK
COPY target/app.jar app.jar
RUN adduser -D appuser
USER appuser
ENTRYPOINT ["java", "-jar", "/app.jar"]
# ✅ Secure Dockerfile
FROM eclipse-temurin:17.0.9_9-jre-alpine # Minimal, updated JRE
COPY target/app.jar app.jar
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
ENTRYPOINT ["java", "-jar", "/app.jar"]

3. Secrets in Configuration

// ❌ In application.properties
database.password=mysecretpassword
// ✅ Use environment variables or secret management
database.password=${DB_PASSWORD}
# Kubernetes deployment with secrets
apiVersion: v1
kind: Pod
metadata:
name: java-app
spec:
containers:
- name: app
image: my-java-app:latest
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password

Best Practices for Java Teams

  1. Shift Left: Integrate scanning early in the development process, ideally in pre-commit hooks and PR checks.
  2. Fail Builds on Critical Issues: Configure your CI/CD pipeline to fail when critical vulnerabilities are detected.
  3. Use Base Image Hardening: Prefer minimal base images like eclipse-temurin:17-jre-alpine or distroless images.
  4. Automate Dependency Updates: Use Dependabot, Renovate, or similar tools to automatically create PRs for vulnerable dependencies.
  5. Define Security Policies: Establish and enforce organizational policies for vulnerability severity thresholds.
  6. Runtime Protection: Complement pre-production scanning with Aqua's runtime security for production environments.

Conclusion

Aqua Security provides a comprehensive scanning solution that addresses the unique security challenges of Java applications in cloud-native environments. By integrating Aqua scanning into your CI/CD pipeline, Java teams can proactively identify and remediate vulnerabilities in dependencies, container images, and configuration before they reach production. This shift-left security approach, combined with runtime protection, creates a robust defense-in-depth strategy that is essential for securing modern Java applications in today's threat landscape.


Further Reading:

Leave a Reply

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


Macro Nepal Helper