Security scanning for serverless Java applications involves checking code, dependencies, configuration, and cloud resources for vulnerabilities and misconfigurations.
1. Serverless Java Project Setup with Security Scanning
Sample Serverless Framework Template (serverless.yml)
service: java-serverless-api
plugins:
- serverless-offline
- serverless-dependency-check
- serverless-prune-plugin
- serverless-iam-roles-per-function
provider:
name: aws
runtime: java11
region: us-east-1
stage: ${opt:stage, 'dev'}
memorySize: 2048
timeout: 30
versionFunctions: false
# Security settings
tracing:
apiGateway: true
lambda: true
logs:
restApi: true
environment:
STAGE: ${self:provider.stage}
SECURITY_SCAN_ENABLED: true
DEPENDENCY_CHECK_ENABLED: true
package:
individually: true
exclude:
- '**/*.log'
- '**/*.md'
- '**/*.txt'
- '.git/**'
- '.github/**'
- '.vscode/**'
- 'node_modules/**'
- '.serverless/**'
functions:
apiHandler:
handler: com.example.ApiHandler
memorySize: 1024
timeout: 15
events:
- http:
path: /api/{proxy+}
method: ANY
cors: true
environment:
FUNCTION_NAME: apiHandler
package:
include:
- build/libs/**
- dependency-check-report.html
securityScanner:
handler: com.example.SecurityScanner
memorySize: 1536
timeout: 300
events:
- schedule: rate(1 day)
environment:
SCAN_TYPE: full
REPORT_BUCKET: security-reports-${self:provider.stage}
resources:
Resources:
SecurityReportsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: security-reports-${self:provider.stage}
VersioningConfiguration:
Status: Enabled
LoggingConfiguration:
DestinationBucketName: !Ref AccessLogsBucket
LogFilePrefix: security-reports/
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
AccessLogsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: access-logs-${self:provider.stage}
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
2. Dependency Security Scanning
OWASP Dependency Check Maven Configuration (pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>serverless-java-api</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- Security Scanning Versions -->
<owasp.dependency.check.version>8.2.1</owasp.dependency.check.version>
<spotbugs.version>4.7.3</spotbugs.version>
<pmd.version>6.55.0</pmd.version>
<checkstyle.version>10.9.3</checkstyle.version>
<cyclonedx.version>2.7.9</cyclonedx.version>
</properties>
<dependencies>
<!-- AWS Lambda Dependencies -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>3.11.1</version>
</dependency>
<!-- Web Framework -->
<dependency>
<groupId>com.amazonaws.serverless</groupId>
<artifactId>aws-serverless-java-container-core</artifactId>
<version>1.9.1</version>
</dependency>
<!-- Security Dependencies -->
<dependency>
<groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>com.github.java-json-tools</groupId>
<artifactId>json-schema-validator</artifactId>
<version>2.2.14</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Shade Plugin for Lambda -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- OWASP Dependency Check -->
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>${owasp.dependency.check.version}</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<configuration>
<format>HTML</format>
<formats>HTML,JSON,XML</formats>
<failBuildOnAnyVulnerability>true</failBuildOnAnyVulnerability>
<failOnError>true</failOnError>
<suppressionFile>dependency-check-suppressions.xml</suppressionFile>
<cveValidForHours>24</cveValidForHours>
<skipTestScope>true</skipTestScope>
<assemblyAnalyzerEnabled>false</assemblyAnalyzerEnabled>
<nodeAnalyzerEnabled>false</nodeAnalyzerEnabled>
<nodeAuditAnalyzerEnabled>false</nodeAuditAnalyzerEnabled>
<retireJsAnalyzerEnabled>false</retireJsAnalyzerEnabled>
</configuration>
</plugin>
<!-- SpotBugs Security Scanner -->
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${spotbugs.version}</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<failOnError>true</failOnError>
<includeFilterFile>spotbugs-security-include.xml</includeFilterFile>
<excludeFilterFile>spotbugs-security-exclude.xml</excludeFilterFile>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- PMD Static Analysis -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<version>${pmd.version}</version>
<configuration>
<rulesets>
<ruleset>category/java/security.xml</ruleset>
<ruleset>category/java/bestpractices.xml</ruleset>
</rulesets>
<failOnViolation>true</failOnViolation>
<printFailingErrors>true</printFailingErrors>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- CycloneDX SBOM Generation -->
<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>${cyclonedx.version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
<configuration>
<projectType>library</projectType>
<schemaVersion>1.4</schemaVersion>
<includeBomSerialNumber>true</includeBomSerialNumber>
<includeCompileScope>true</includeCompileScope>
<includeRuntimeScope>true</includeRuntimeScope>
<includeTestScope>false</includeTestScope>
<outputFormat>all</outputFormat>
<outputName>sbom</outputName>
</configuration>
</plugin>
</plugins>
</build>
</project>
Dependency Check Suppression File (dependency-check-suppressions.xml)
<?xml version="1.0" encoding="UTF-8"?> <suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd"> <!-- Suppress false positives --> <suppress> <notes><![CDATA[ False positive - CVE affects different component ]]></notes> <cve>CVE-2022-00000</cve> </suppress> <suppress base="true"> <notes><![CDATA[ Suppress vulnerabilities in test scope dependencies ]]></notes> <gav regex="true">.*:.*:.*:.*:test</gav> </suppress> <suppress> <notes><![CDATA[ Accept risk for specific library with no available fix ]]></notes> <cve>CVE-2023-12345</cve> </suppress> </suppressions>
3. Code Security Scanning
SpotBugs Security Configuration (spotbugs-security-include.xml)
<?xml version="1.0" encoding="UTF-8"?> <FindBugsFilter> <Match> <Bug category="SECURITY"/> </Match> <Match> <Bug category="MALICIOUS_CODE"/> </Match> <Match> <Bug pattern="SQL_INJECTION"/> </Match> <Match> <Bug pattern="COMMAND_INJECTION"/> </Match> <Match> <Bug pattern="PATH_TRAVERSAL_IN"/> </Match> <Match> <Bug pattern="PATH_TRAVERSAL_OUT"/> </Match> <Match> <Bug pattern="LDAP_INJECTION"/> </Match> <Match> <Bug pattern="XXE_XMLSTREAMREADER"/> </Match> <Match> <Bug pattern="WEAK_MESSAGE_DIGEST"/> </Match> <Match> <Bug pattern="CIPHER_INTEGRITY"/> </Match> </FindBugsFilter>
Security-Focused Lambda Handler
package com.example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent;
import org.owasp.encoder.Encode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class ApiHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
private static final Logger logger = LoggerFactory.getLogger(ApiHandler.class);
private final SecurityScanner securityScanner;
public ApiHandler() {
this.securityScanner = new SecurityScanner();
}
@Override
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) {
try {
// Input validation and security checks
SecurityScanResult scanResult = securityScanner.scanInput(input);
if (!scanResult.isSafe()) {
return createErrorResponse(400, "Security validation failed: " + scanResult.getIssues());
}
// Sanitize headers and parameters
Map<String, String> sanitizedHeaders = sanitizeHeaders(input.getHeaders());
Map<String, String> sanitizedQueryParams = sanitizeQueryParameters(input.getQueryStringParameters());
// Process request
String response = processRequest(input.getBody(), sanitizedHeaders, sanitizedQueryParams);
return createSuccessResponse(response);
} catch (SecurityException e) {
logger.warn("Security violation detected", e);
return createErrorResponse(403, "Security violation");
} catch (Exception e) {
logger.error("Unexpected error", e);
return createErrorResponse(500, "Internal server error");
}
}
private Map<String, String> sanitizeHeaders(Map<String, String> headers) {
if (headers == null) return new HashMap<>();
Map<String, String> sanitized = new HashMap<>();
for (Map.Entry<String, String> entry : headers.entrySet()) {
String key = Encode.forHtml(entry.getKey());
String value = Encode.forHtml(entry.getValue());
sanitized.put(key, value);
}
return sanitized;
}
private Map<String, String> sanitizeQueryParameters(Map<String, String> queryParams) {
if (queryParams == null) return new HashMap<>();
Map<String, String> sanitized = new HashMap<>();
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
String key = Encode.forJava(entry.getKey());
String value = Encode.forJava(entry.getValue());
sanitized.put(key, value);
}
return sanitized;
}
private APIGatewayProxyResponseEvent createSuccessResponse(String body) {
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
response.setStatusCode(200);
response.setBody(body);
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("X-Content-Type-Options", "nosniff");
headers.put("X-Frame-Options", "DENY");
headers.put("X-XSS-Protection", "1; mode=block");
response.setHeaders(headers);
return response;
}
private APIGatewayProxyResponseEvent createErrorResponse(int statusCode, String message) {
APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
response.setStatusCode(statusCode);
String safeMessage = Encode.forHtml(message);
response.setBody("{\"error\": \"" + safeMessage + "\"}");
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
response.setHeaders(headers);
return response;
}
private String processRequest(String body, Map<String, String> headers, Map<String, String> queryParams) {
// Business logic implementation
return "{\"status\": \"success\"}";
}
}
Security Scanner Implementation
package com.example;
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class SecurityScanner {
private static final ObjectMapper mapper = new ObjectMapper();
// Security patterns
private static final Pattern SQL_INJECTION_PATTERN =
Pattern.compile("('(''|[^'])*')|(;)|(\\b(ALTER|CREATE|DELETE|DROP|EXEC(UTE){0,1}|INSERT( +INTO){0,1}|MERGE|SELECT|UPDATE|UNION( +ALL){0,1})\\b)", Pattern.CASE_INSENSITIVE);
private static final Pattern XSS_PATTERN =
Pattern.compile("<script|javascript:|onload=|onerror=", Pattern.CASE_INSENSITIVE);
private static final Pattern PATH_TRAVERSAL_PATTERN =
Pattern.compile("(\\.\\./|\\.\\.\\\\)");
public SecurityScanResult scanInput(APIGatewayProxyRequestEvent input) {
List<String> issues = new ArrayList<>();
// Scan headers
if (input.getHeaders() != null) {
input.getHeaders().forEach((key, value) -> {
if (detectMaliciousContent(key) || detectMaliciousContent(value)) {
issues.add("Malicious content in header: " + key);
}
});
}
// Scan query parameters
if (input.getQueryStringParameters() != null) {
input.getQueryStringParameters().forEach((key, value) -> {
if (detectSQLInjection(value) || detectXSS(value) || detectPathTraversal(value)) {
issues.add("Malicious content in query parameter: " + key);
}
});
}
// Scan request body
if (input.getBody() != null) {
try {
JsonNode body = mapper.readTree(input.getBody());
scanJsonNode(body, issues, "body");
} catch (Exception e) {
issues.add("Invalid JSON in request body");
}
}
// Scan path parameters
if (input.getPathParameters() != null) {
input.getPathParameters().forEach((key, value) -> {
if (detectPathTraversal(value)) {
issues.add("Path traversal attempt in path parameter: " + key);
}
});
}
return new SecurityScanResult(issues.isEmpty(), issues);
}
private boolean detectMaliciousContent(String input) {
return detectSQLInjection(input) || detectXSS(input) || detectPathTraversal(input);
}
private boolean detectSQLInjection(String input) {
return SQL_INJECTION_PATTERN.matcher(input).find();
}
private boolean detectXSS(String input) {
return XSS_PATTERN.matcher(input).find();
}
private boolean detectPathTraversal(String input) {
return PATH_TRAVERSAL_PATTERN.matcher(input).find();
}
private void scanJsonNode(JsonNode node, List<String> issues, String path) {
if (node.isObject()) {
node.fields().forEachRemaining(entry -> {
String fieldPath = path + "." + entry.getKey();
if (entry.getValue().isTextual()) {
String value = entry.getValue().asText();
if (detectMaliciousContent(value)) {
issues.add("Malicious content in " + fieldPath);
}
} else {
scanJsonNode(entry.getValue(), issues, fieldPath);
}
});
} else if (node.isArray()) {
for (int i = 0; i < node.size(); i++) {
scanJsonNode(node.get(i), issues, path + "[" + i + "]");
}
}
}
public static class SecurityScanResult {
private final boolean safe;
private final List<String> issues;
public SecurityScanResult(boolean safe, List<String> issues) {
this.safe = safe;
this.issues = issues;
}
public boolean isSafe() { return safe; }
public List<String> getIssues() { return issues; }
}
}
4. Infrastructure Security Scanning
CFN-NAG Security Scanning
cfn-nag-rules.yml
Rules: - id: W1 reason: "Security groups found with cidr open to world" rule: W2 reason: "Security groups found ingress with port range instead of just a single port" rule: W9 reason: "Security groups found with cidr open to world on port 22" rule: W12 reason: "Security groups found ingress with port range instead of just a single port" rule: W27 reason: "Security groups found with cidr open to world on port 3389" rule: W33 reason: "Security groups found egress with port range instead of just a single port"
Serverless Configuration with Security Hardening
# serverless-secure.yml
service: secure-java-serverless
provider:
name: aws
runtime: java11
stage: ${opt:stage, 'prod'}
# Enhanced security settings
apiGateway:
apiKeys:
- name: apiKey-${self:provider.stage}
usagePlan:
quota:
limit: 1000
offset: 2
period: DAY
throttle:
burstLimit: 200
rateLimit: 100
iamRoleStatements:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- arn:aws:logs:*:*:*
- Effect: Deny
Action:
- s3:DeleteBucket
- s3:DeleteBucketPolicy
- s3:DeleteObject
- s3:DeleteObjectVersion
Resource: "*"
stackTags:
Environment: ${self:provider.stage}
SecurityLevel: High
DataClassification: Confidential
vpc:
securityGroupIds:
- sg-secure123
subnetIds:
- subnet-private1
- subnet-private2
functions:
secureApi:
handler: com.example.SecureApiHandler
memorySize: 1024
timeout: 10
environment:
ENCRYPTION_KEY: ${ssm:/aws/reference/secretsmanager/encryption-key}
DB_PASSWORD: ${ssm:/aws/reference/secretsmanager/db-password}
events:
- http:
path: /secure/{proxy+}
method: ANY
private: true
authorizer:
name: customAuthorizer
type: TOKEN
layers:
- arn:aws:lambda:us-east-1:123456789012:layer:security-layer:1
resources:
Resources:
CustomAuthorizer:
Type: AWS::Lambda::Function
Properties:
FunctionName: custom-authorizer
Runtime: java11
Handler: com.example.CustomAuthorizer
Code:
S3Bucket: security-lambdas
S3Key: authorizer.jar
MemorySize: 512
Timeout: 5
SecurityLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: /aws/lambda/secure-java-api
RetentionInDays: 365
Outputs:
ApiUrl:
Description: "Secure API URL"
Value: !Sub "https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/${self:provider.stage}"
SecurityScanReport:
Description: "Security scan report location"
Value: !Ref SecurityReportsBucket
5. CI/CD Security Scanning Pipeline
GitHub Actions Workflow (.github/workflows/security-scan.yml)
name: Serverless Java Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 2 * * 1' # Weekly on Monday at 2 AM
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
cache: maven
- name: Cache Maven dependencies
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: OWASP Dependency Check
run: |
mvn org.owasp:dependency-check-maven:check -DfailBuildOnAnyVulnerability=true
continue-on-error: false
- name: Generate SBOM
run: |
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom
cat target/sbom.json
- name: SpotBugs Security Scan
run: |
mvn com.github.spotbugs:spotbugs-maven-plugin:check
continue-on-error: true
- name: PMD Static Analysis
run: |
mvn org.apache.maven.plugins:maven-pmd-plugin:check
continue-on-error: true
- name: Install Serverless Framework
run: |
npm install -g serverless@3
npm install -g serverless-dependency-check
serverless plugin install -n serverless-prune-plugin
- name: Serverless Configuration Audit
run: |
npx serverless-scan --config serverless.yml --output-format json > serverless-scan-report.json
cat serverless-scan-report.json
- name: CFN-NAG Security Scan
run: |
gem install cfn-nag
serverless package
cfn_nag_scan --input-path .serverless/cloudformation-template-update-stack.json \
--blacklist-path cfn-nag-rules.yml \
--output-format json > cfn-nag-report.json
- name: Upload Security Reports
uses: actions/upload-artifact@v3
with:
name: security-reports
path: |
dependency-check-report.html
target/spotbugs.xml
target/pmd.xml
serverless-scan-report.json
cfn-nag-report.json
retention-days: 30
- name: Run Trivy for Container Scanning
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy Results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
deploy-security-scanner:
runs-on: ubuntu-latest
needs: security-scan
if: github.ref == 'refs/heads/main'
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: Deploy Security Scanner Lambda
run: |
mvn clean package
serverless deploy --stage prod --verbose
6. Runtime Security Monitoring
Security Monitoring Lambda
package com.example;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
import com.amazonaws.services.lambda.runtime.events.ScheduledEvent;
import software.amazon.awssdk.services.securityhub.SecurityHubClient;
import software.amazon.awssdk.services.securityhub.model.*;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.PutMetricDataRequest;
import java.time.Instant;
import java.util.List;
public class SecurityScanner implements RequestHandler<ScheduledEvent, String> {
private final SecurityHubClient securityHub;
private final CloudWatchClient cloudWatch;
public SecurityScanner() {
this.securityHub = SecurityHubClient.create();
this.cloudWatch = CloudWatchClient.create();
}
@Override
public String handleRequest(ScheduledEvent event, Context context) {
try {
// Scan for vulnerabilities
scanDependencies();
// Check configuration compliance
checkInfrastructureCompliance();
// Monitor runtime security
monitorRuntimeMetrics();
return "Security scan completed successfully";
} catch (Exception e) {
context.getLogger().log("Security scan failed: " + e.getMessage());
throw new RuntimeException("Security scan failed", e);
}
}
private void scanDependencies() {
// Integrate with dependency scanning tools
// This could call OWASP DC API or similar services
// Report findings to Security Hub
List<String> vulnerabilities = List.of("CVE-2023-12345", "CVE-2023-67890");
for (String cve : vulnerabilities) {
AwsSecurityFinding finding = AwsSecurityFinding.builder()
.title("Vulnerable Dependency Found")
.description("Dependency with " + cve + " found in Lambda function")
.severity(Severity.builder().label(SeverityLabel.HIGH).build())
.productArn("arn:aws:securityhub:us-east-1:123456789012:product/123456789012/default")
.generatorId("java-serverless-scanner")
.awsAccountId("123456789012")
.schemaVersion("2018-10-08")
.types(List.of("Software and Configuration Checks/Vulnerabilities/CVE"))
.createdAt(Instant.now())
.updatedAt(Instant.now())
.build();
BatchImportFindingsRequest request = BatchImportFindingsRequest.builder()
.findings(finding)
.build();
securityHub.batchImportFindings(request);
}
}
private void checkInfrastructureCompliance() {
// Check Lambda function configurations
// Verify encryption, networking, permissions etc.
PutMetricDataRequest metricRequest = PutMetricDataRequest.builder()
.namespace("ServerlessSecurity")
.metricData(metric -> metric
.metricName("ComplianceScore")
.value(95.0)
.timestamp(Instant.now()))
.build();
cloudWatch.putMetricData(metricRequest);
}
private void monitorRuntimeMetrics() {
// Monitor runtime security metrics
// - Function invocation patterns
// - Error rates
// - Resource usage
// - Network activity
context.getLogger().log("Runtime security monitoring completed");
}
}
7. Security Reporting and Dashboards
Security Dashboard Configuration
package com.example;
import software.amazon.awssdk.services.cloudwatch.CloudWatchClient;
import software.amazon.awssdk.services.cloudwatch.model.DashboardValidationMessage;
import software.amazon.awssdk.services.cloudwatch.model.PutDashboardRequest;
public class SecurityDashboard {
private final CloudWatchClient cloudWatch;
public SecurityDashboard() {
this.cloudWatch = CloudWatchClient.create();
}
public void createSecurityDashboard() {
String dashboardJson = """
{
"widgets": [
{
"type": "metric",
"x": 0,
"y": 0,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[ "ServerlessSecurity", "VulnerabilityCount" ],
[ ".", "CriticalVulnerabilities" ],
[ ".", "HighVulnerabilities" ]
],
"period": 300,
"stat": "Maximum",
"region": "us-east-1",
"title": "Security Vulnerabilities"
}
},
{
"type": "metric",
"x": 0,
"y": 6,
"width": 12,
"height": 6,
"properties": {
"metrics": [
[ "ServerlessSecurity", "ComplianceScore" ]
],
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "Security Compliance Score"
}
}
]
}
""";
PutDashboardRequest request = PutDashboardRequest.builder()
.dashboardName("ServerlessJavaSecurity")
.dashboardBody(dashboardJson)
.build();
try {
cloudWatch.putDashboard(request);
System.out.println("Security dashboard created successfully");
} catch (Exception e) {
System.err.println("Failed to create dashboard: " + e.getMessage());
}
}
}
This comprehensive security scanning setup for Serverless Java applications covers dependency scanning, code analysis, infrastructure security, runtime monitoring, and CI/CD integration, providing end-to-end security assurance for your serverless workloads.