Aqua Security for Java Applications: Complete Implementation Guide

Aqua Security is a cloud-native security platform that provides vulnerability scanning, runtime protection, and compliance assurance for applications, including Java-based workloads.


1. Aqua Vulnerability Scanning for Java

Aqua Trivy Integration for Java

Maven Plugin Configuration (pom.xml):

<build>
<plugins>
<!-- Aqua Trivy Vulnerability Scanner -->
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.7.9</version>
<configuration>
<projectType>library</projectType>
<schemaVersion>1.4</schemaVersion>
<includeBomSerialNumber>true</includeBomSerialNumber>
<includeCompileScope>true</includeCompileScope>
<includeRuntimeScope>true</includeRuntimeScope>
<includeSystemScope>true</includeSystemScope>
<includeTestScope>false</includeTestScope>
<includeLicenseText>false</includeLicenseText>
<outputFormat>json</outputFormat>
<outputName>sbom</outputName>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- JAR Vulnerability Check -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.2.1</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<format>HTML</format>
<failBuildOnAnyVulnerability>true</failBuildOnAnyVulnerability>
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
</configuration>
</plugin>
</plugins>
</build>

Gradle Configuration (build.gradle)

plugins {
id 'org.cyclonedx.bom' version '1.7.4'
id 'org.owasp.dependencycheck' version '8.2.1'
}
cyclonedxBom {
projectType = "library"
schemaVersion = "1.4"
includeBomSerialNumber = true
includeCompileScope = true
includeRuntimeScope = true
includeSystemScope = true
includeTestScope = false
outputName = "sbom"
outputFormat = "json"
}
dependencyCheck {
format = 'HTML'
failBuildOnAnyVulnerability = true
suppressionFile = 'dependency-check-suppressions.xml'
analyzers {
assemblyEnabled = false
}
}

Dockerfile with Aqua Security Scanning

# Multi-stage build for security
FROM eclipse-temurin:17-jdk-jammy as builder
WORKDIR /app
COPY . .
RUN ./mvnw clean package -DskipTests
# Runtime stage
FROM eclipse-temurin:17-jre-jammy
RUN addgroup --system --gid 1000 javauser && \
adduser --system --uid 1000 --gid 1000 javauser
WORKDIR /app
# Copy application JAR
COPY --from=builder /app/target/*.jar app.jar
# Security hardening
RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
# Non-root user
USER javauser
# Security-focused JVM options
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

Aqua Security Pipeline Integration

GitHub Actions Workflow (.github/workflows/aqua-scan.yml):

name: Aqua Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: maven
- name: Build and generate SBOM
run: mvn clean package cyclonedx:makeAggregateBom -DskipTests
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
- name: Docker build
run: docker build -t my-java-app:${{ github.sha }} .
- name: Scan Docker image with Trivy
run: |
trivy image \
--format template \
--template "@contrib/gitlab.tpl" \
--output gl-dependency-scanning-report.json \
my-java-app:${{ github.sha }}
- name: Check for critical vulnerabilities
run: |
trivy image \
--severity CRITICAL \
--exit-code 1 \
my-java-app:${{ github.sha }}

2. Aqua Runtime Security for Java

Aqua Enforcer Configuration

Kubernetes Deployment with Aqua Security:

apiVersion: apps/v1
kind: Deployment
metadata:
name: java-app
labels:
app: java-app
spec:
replicas: 3
selector:
matchLabels:
app: java-app
template:
metadata:
labels:
app: java-app
annotations:
aquasec.com/enforcer: "true"
aquasec.com/image: "registry.company.com/java-app:1.0.0"
spec:
serviceAccountName: java-app-sa
containers:
- name: java-app
image: registry.company.com/java-app:1.0.0
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: java-app-sa
annotations:
aquasec.com/enforcer: "true"

Java Application Security Configuration

Spring Security with Aqua Integration:

@Configuration
@EnableWebSecurity
public class AquaSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.requestMatchers("/actuator/aqua/**").hasRole("AQUA_MONITOR")
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults())
)
.csrf(csrf -> csrf
.ignoringRequestMatchers("/actuator/aqua/**")
);
return http.build();
}
@Bean
public AquaRuntimeMonitor aquaRuntimeMonitor() {
return new AquaRuntimeMonitor();
}
}

Aqua Runtime Monitoring Component:

@Component
public class AquaRuntimeMonitor {
private static final Logger logger = LoggerFactory.getLogger(AquaRuntimeMonitor.class);
private final Map<String, SecurityEvent> securityEvents = new ConcurrentHashMap<>();
@EventListener
public void handleAuthenticationFailure(AuthenticationFailureBadCredentialsEvent event) {
SecurityEvent securityEvent = new SecurityEvent(
"AUTH_FAILURE",
"Authentication failure for user: " + event.getAuthentication().getName(),
Instant.now(),
SecurityEvent.Severity.MEDIUM
);
logSecurityEvent(securityEvent);
reportToAqua(securityEvent);
}
@EventListener
public void handleAccessDenied(AccessDeniedEvent event) {
SecurityEvent securityEvent = new SecurityEvent(
"ACCESS_DENIED",
"Access denied for user: " + event.getAuthentication().getName() + 
" to resource: " + event.getSource(),
Instant.now(),
SecurityEvent.Severity.HIGH
);
logSecurityEvent(securityEvent);
reportToAqua(securityEvent);
}
public void monitorFileSystemAccess(String path, String operation) {
if (isSensitivePath(path)) {
SecurityEvent securityEvent = new SecurityEvent(
"SENSITIVE_FILE_ACCESS",
String.format("Access to sensitive path: %s, operation: %s", path, operation),
Instant.now(),
SecurityEvent.Severity.HIGH
);
logSecurityEvent(securityEvent);
reportToAqua(securityEvent);
}
}
private boolean isSensitivePath(String path) {
return path.contains("/etc/passwd") || 
path.contains("/etc/shadow") ||
path.contains("/proc/") ||
path.contains("/sys/");
}
private void logSecurityEvent(SecurityEvent event) {
logger.warn("Security Event - Type: {}, Message: {}, Severity: {}", 
event.getType(), event.getMessage(), event.getSeverity());
securityEvents.put(event.getId(), event);
}
private void reportToAqua(SecurityEvent event) {
// Integrate with Aqua API to report runtime security events
// This would typically send events to Aqua CSP (Cloud Security Platform)
}
@RestController
@RequestMapping("/actuator/aqua")
public static class AquaMonitorEndpoint {
private final AquaRuntimeMonitor monitor;
public AquaMonitorEndpoint(AquaRuntimeMonitor monitor) {
this.monitor = monitor;
}
@GetMapping("/events")
public List<SecurityEvent> getSecurityEvents() {
return new ArrayList<>(monitor.securityEvents.values());
}
@PostMapping("/scan")
public ResponseEntity<String> triggerRuntimeScan() {
// Trigger runtime security scan
return ResponseEntity.ok("Runtime scan initiated");
}
}
}
// Security Event DTO
class SecurityEvent {
private String id;
private String type;
private String message;
private Instant timestamp;
private Severity severity;
public SecurityEvent(String type, String message, Instant timestamp, Severity severity) {
this.id = UUID.randomUUID().toString();
this.type = type;
this.message = message;
this.timestamp = timestamp;
this.severity = severity;
}
// Getters
public String getId() { return id; }
public String getType() { return type; }
public String getMessage() { return message; }
public Instant getTimestamp() { return timestamp; }
public Severity getSeverity() { return severity; }
public enum Severity {
LOW, MEDIUM, HIGH, CRITICAL
}
}

3. Aqua CSP (Cloud Security Platform) Integration

Application-Specific Policies

Aqua CSP Policy Definition (YAML):

# aqua-policy.yaml
apiVersion: aquasec.com/v1
kind: ApplicationPolicy
metadata:
name: java-app-security-policy
spec:
application: java-order-service
rules:
- name: block-critical-vulnerabilities
description: Block deployment if critical vulnerabilities found
condition:
severity: CRITICAL
maxAllowed: 0
action: BLOCK
- name: warn-high-vulnerabilities
description: Warn on high severity vulnerabilities
condition:
severity: HIGH
maxAllowed: 3
action: WARN
- name: require-non-root-user
description: Require containers to run as non-root user
condition:
container:
runAsRoot: false
action: BLOCK
- name: block-privileged-containers
description: Block privileged containers
condition:
container:
privileged: false
action: BLOCK
- name: require-readonly-filesystem
description: Require read-only root filesystem
condition:
container:
readOnlyRootFilesystem: true
action: WARN
- name: block-dangerous-capabilities
description: Block containers with dangerous capabilities
condition:
container:
capabilities:
- NET_RAW
- SYS_ADMIN
- SYS_MODULE
action: BLOCK
- name: runtime-threat-detection
description: Enable runtime threat detection
condition:
runtime:
threatDetection: true
action: ENFORCE

Kubernetes Security Policies

Aqua Admission Controller Configuration:

apiVersion: aquasec.com/v1
kind: ClusterAdmissionRule
metadata:
name: java-app-admission
spec:
match:
- namespace: "production"
policies:
- name: java-app-security-policy
actions:
- audit
- deny
settings:
enabled: true
blockUnauthorizedImages: true

4. Aqua Security in CI/CD Pipeline

Jenkins Pipeline with Aqua Security

pipeline {
agent any
environment {
AQUA_URL = 'https://aqua.company.com'
AQUA_USERNAME = credentials('aqua-username')
AQUA_PASSWORD = credentials('aqua-password')
}
stages {
stage('Checkout') {
steps {
git branch: 'main', url: 'https://github.com/company/java-app.git'
}
}
stage('Build') {
steps {
sh 'mvn clean compile -DskipTests'
}
}
stage('Dependency Scan') {
steps {
sh 'mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom'
aquaMicroscanner imageName: 'java-app:latest'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Build Docker Image') {
steps {
sh 'docker build -t java-app:${GIT_COMMIT} .'
}
}
stage('Aqua Security Scan') {
steps {
script {
def scanner = aquaScanner(
image: 'java-app:${GIT_COMMIT}',
aquaServer: AQUA_URL,
aquaUsername: AQUA_USERNAME,
aquaPassword: AQUA_PASSWORD,
failBuild: true
)
if (scanner.hasVulnerabilities()) {
error "Aqua Security scan found vulnerabilities"
}
}
}
}
stage('Deploy to Staging') {
when {
expression { env.BRANCH_NAME == 'main' }
}
steps {
kubernetesDeploy(
kubeconfigId: 'k8s-cluster',
configs: 'k8s/staging-deployment.yaml'
)
}
}
}
post {
always {
aquaPublishResults(
aquaServer: AQUA_URL,
aquaUsername: AQUA_USERNAME,
aquaPassword: AQUA_PASSWORD
)
}
}
}

5. Aqua Runtime Security Monitoring

Custom Java Security Agent

@Component
public class AquaSecurityAgent {
private final Runtime runtime = Runtime.getRuntime();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@PostConstruct
public void init() {
// Monitor system properties for security violations
scheduler.scheduleAtFixedRate(this::monitorSecurity, 0, 30, TimeUnit.SECONDS);
}
private void monitorSecurity() {
monitorSystemProperties();
monitorEnvironmentVariables();
monitorFileSystemAccess();
monitorNetworkConnections();
}
private void monitorSystemProperties() {
Properties props = System.getProperties();
// Check for suspicious system properties
String suspiciousProps = props.stringPropertyNames().stream()
.filter(this::isSuspiciousProperty)
.collect(Collectors.joining(", "));
if (!suspiciousProps.isEmpty()) {
reportSecurityEvent("SUSPICIOUS_SYSTEM_PROPERTIES", 
"Found suspicious system properties: " + suspiciousProps);
}
}
private boolean isSuspiciousProperty(String propertyName) {
return propertyName.contains("jndi") ||
propertyName.contains("ldap") ||
propertyName.contains("rmi") ||
propertyName.contains("codebase");
}
private void monitorEnvironmentVariables() {
Map<String, String> env = System.getenv();
// Check for sensitive environment variables exposure
env.forEach((key, value) -> {
if (key.toUpperCase().contains("PASSWORD") || 
key.toUpperCase().contains("SECRET") ||
key.toUpperCase().contains("KEY")) {
reportSecurityEvent("SENSITIVE_ENV_VAR_EXPOSED",
"Sensitive environment variable detected: " + key);
}
});
}
private void monitorFileSystemAccess() {
// Monitor file system access patterns
// This would integrate with Java Security Manager or custom file system watcher
}
private void monitorNetworkConnections() {
try {
// Monitor outbound network connections
Process process = runtime.exec("netstat -an");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("ESTABLISHED")) {
// Analyze established connections
analyzeNetworkConnection(line);
}
}
}
} catch (IOException e) {
logger.error("Failed to monitor network connections", e);
}
}
private void analyzeNetworkConnection(String connectionInfo) {
// Analyze if connection is to suspicious destinations
if (connectionInfo.contains(":1337") || 
connectionInfo.contains(":4444") ||
connectionInfo.contains(".onion")) {
reportSecurityEvent("SUSPICIOUS_NETWORK_CONNECTION",
"Suspicious network connection detected: " + connectionInfo);
}
}
private void reportSecurityEvent(String type, String message) {
// Report to Aqua CSP
logger.warn("Security Event - {}: {}", type, message);
// Integration with Aqua API would go here
// aquaClient.reportSecurityEvent(type, message, getContext());
}
@PreDestroy
public void cleanup() {
scheduler.shutdown();
}
}

6. Aqua Compliance and Governance

Compliance Check Configuration

# compliance-policy.yaml
apiVersion: aquasec.com/v1
kind: CompliancePolicy
metadata:
name: java-app-pci-dss
spec:
standards:
- name: PCI-DSS
version: "3.2.1"
rules:
- id: "java-app-encryption"
description: "Java app must use TLS 1.2 or higher"
check:
type: "configuration"
path: "app.security.tls.version"
expected: ">=1.2"
- id: "java-app-logging"
description: "Java app must implement audit logging"
check:
type: "file"
path: "/app/logs/audit.log"
exists: true
- id: "java-app-authentication"
description: "Java app must use strong authentication"
check:
type: "configuration"
path: "app.security.auth.strength"
expected: "high"

Aqua Security Dashboard Integration

Custom Security Metrics Exporter:

@Component
public class AquaSecurityMetrics {
private final MeterRegistry meterRegistry;
private final Counter securityViolations;
private final Gauge vulnerabilityCount;
public AquaSecurityMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.securityViolations = Counter.builder("aqua.security.violations")
.description("Number of security policy violations")
.tag("application", "java-app")
.register(meterRegistry);
this.vulnerabilityCount = Gauge.builder("aqua.security.vulnerabilities")
.description("Number of known vulnerabilities")
.tag("application", "java-app")
.register(meterRegistry);
}
public void recordViolation(String policy, String severity) {
securityViolations.increment();
// Additional metrics recording
Counter.builder("aqua.security.violations.by.policy")
.tag("policy", policy)
.tag("severity", severity)
.register(meterRegistry)
.increment();
}
public void updateVulnerabilityCount(int count) {
vulnerabilityCount.set(count);
}
}

This comprehensive guide shows how to integrate Aqua Security throughout the Java application lifecycle, from development to runtime, ensuring security compliance and vulnerability management at every stage.

Leave a Reply

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


Macro Nepal Helper