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.