In today's software supply chain landscape, simply writing secure code isn't enough. How can you prove that your Java artifacts haven't been tampered with between your CI/CD pipeline and your users? Enter SLSA (Supply-chain Levels for Software Artifacts) - a security framework that helps organizations ensure the integrity of their software supply chain.
Let's explore how Java developers can implement SLSA compliance to build more secure, verifiable, and trustworthy applications.
What is SLSA?
SLSA (pronounced "salsa") is a set of incrementally adoptable security guidelines created by the Open Source Security Foundation (OpenSSF). It's designed to protect against software supply chain attacks by ensuring the integrity and provenance of software artifacts.
The framework defines four levels (0-3) across several requirements:
- Source: How your source code is managed
- Build: How your software is built and packaged
- Provenance: Metadata about how artifacts were built
- Dependencies: How you manage third-party dependencies
Why SLSA Matters for Java Teams
- Mitigate Supply Chain Attacks: Prevent tampering with your JARs, WARs, and containers
- Compliance Requirements: Increasingly required by regulations and industry standards
- Customer Trust: Provide verifiable evidence that your artifacts are genuine
- Reproducible Builds: Ensure you can consistently rebuild identical artifacts
SLSA Implementation Roadmap for Java Projects
Let's walk through implementing SLSA Level 2 compliance for a typical Java Spring Boot application.
Step 1: Source Requirements (Level 2)
Requirement: Version-controlled and authenticated changes
// .github/workflows/slsa-source.yml name: SLSA Source Verification on: push: branches: [ main ] pull_request: branches: [ main ] jobs: verify-source: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # Full history for verification - name: Verify signed commits (if using GPG) run: | git verify-commit HEAD || echo "Warning: Commit not signed" - name: Verify build files exist run: | test -f pom.xml || test -f build.gradle || exit 1 test -f Dockerfile && echo "Dockerfile present" || echo "No Dockerfile" - name: Run security scan uses: ossf/scorecard-action@v2 with: results_file: results.sarif results_format: sarif
Step 2: Build Requirements (Level 2)
Requirement: Build service that generates provenance
// .github/workflows/slsa-build.yml
name: SLSA Build and Provenance
on:
workflow_dispatch:
release:
types: [published]
permissions:
id-token: write # Required for OIDC token
contents: read
jobs:
build:
runs-on: ubuntu-latest
outputs:
slsa-provenance: ${{ steps.build.outputs.slsa-provenance }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: |
mvn -B package -DskipTests
# Generate build metadata
echo "BUILD_TIMESTAMP=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
echo "ARTIFACT_SHA256=$(sha256sum target/myapp-*.jar | cut -d' ' -f1)" >> $GITHUB_ENV
- name: Generate SLSA Provenance
uses: slsa-framework/slsa-github-generator/.github/actions/[email protected]
with:
base64-subjects: "${{ hashFiles('target/myapp-*.jar') }}"
upload-assets: true
Step 3: Comprehensive Java SLSA Implementation
Let's create a complete SLSA-compliant build system for a Java application:
1. Build Configuration (pom.xml):
<!-- Ensure reproducible builds --> <project> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format> <reproducible-build>true</reproducible-build> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>17</source> <target>17</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- Reproducible builds plugin --> <plugin> <groupId>io.github.zlika</groupId> <artifactId>reproducible-build-maven-plugin</artifactId> <version>0.16</version> <executions> <execution> <goals> <goal>strip-jar</goal> </goals> </execution> </executions> </plugin> <!-- SBOM generation --> <plugin> <groupId>org.cyclonedx</groupId> <artifactId>cyclonedx-maven-plugin</artifactId> <version>2.7.9</version> <executions> <execution> <phase>package</phase> <goals> <goal>makeAggregateBom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
2. SLSA Build Script (Java-based verification):
// src/main/java/com/company/slsa/SLSABuildVerifier.java
package com.company.slsa;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.Base64;
/**
* SLSA Build Verification Utility for Java Applications
*/
public class SLSABuildVerifier {
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("Usage: SLSABuildVerifier <artifact-path>");
System.exit(1);
}
String artifactPath = args[0];
verifyBuildArtifact(artifactPath);
}
public static void verifyBuildArtifact(String artifactPath) throws Exception {
System.out.println("🔍 SLSA Artifact Verification");
System.out.println("Artifact: " + artifactPath);
// 1. Verify artifact integrity
String artifactHash = calculateSHA256(Paths.get(artifactPath));
System.out.println("SHA256: " + artifactHash);
// 2. Verify build environment
verifyBuildEnvironment();
// 3. Check for required metadata
verifyBuildMetadata();
System.out.println("âś… SLSA verification completed");
}
private static String calculateSHA256(Path file) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(Files.readAllBytes(file));
return bytesToHex(hash);
}
private static void verifyBuildEnvironment() {
String ciPlatform = System.getenv("CI");
String buildTimestamp = System.getenv("BUILD_TIMESTAMP");
if (ciPlatform == null) {
System.err.println("⚠️ Warning: Not running in CI environment");
}
if (buildTimestamp != null) {
System.out.println("Build timestamp: " + buildTimestamp);
}
}
private static void verifyBuildMetadata() {
// Check for required environment variables and files
String[] requiredEnvVars = {"GITHUB_ACTIONS", "GITHUB_RUN_ID", "GITHUB_SHA"};
for (String envVar : requiredEnvVars) {
if (System.getenv(envVar) != null) {
System.out.println("âś“ Found: " + envVar);
} else {
System.out.println("âś— Missing: " + envVar);
}
}
// Check for SBOM
Path sbomPath = Paths.get("target/bom.json");
if (Files.exists(sbomPath)) {
System.out.println("âś“ SBOM present: " + sbomPath);
} else {
System.err.println("⚠️ SBOM not found");
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
}
3. Dockerfile with SLSA Compliance:
# Use specific digest for reproducibility FROM eclipse-temurin:17-jre@sha256:a1d2fe2a... as runtime # Create non-root user RUN groupadd -r javaapp && useradd -r -g javaapp javaapp USER javaapp # Copy artifact COPY --chown=javaapp:javaapp target/myapp-*.jar /app/application.jar # Set metadata labels for provenance LABEL org.opencontainers.image.title="My Java App" \ org.opencontainers.image.version="1.0.0" \ org.opencontainers.image.created=$BUILD_TIMESTAMP \ org.opencontainers.image.source="https://github.com/company/myapp" # Health check HEALTHCHECK --interval=30s --timeout=3s \ CMD java -cp /app/application.jar com.company.HealthCheck EXPOSE 8080 ENTRYPOINT ["java", "-jar", "/app/application.jar"]
4. SBOM Generation and Verification:
// .github/workflows/sbom-generation.yml name: Generate SBOM on: push: tags: ['v*'] jobs: sbom: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate CycloneDX SBOM run: | mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom - name: Verify SBOM run: | if [ -f "target/bom.json" ]; then echo "SBOM generated successfully" # Validate SBOM structure jq '.bomFormat' target/bom.json else echo "SBOM generation failed" exit 1 fi - name: Upload SBOM uses: actions/upload-artifact@v4 with: name: sbom path: target/bom.json
SLSA Level 3 Aspirations
For organizations targeting the highest SLSA level:
// Advanced SLSA Level 3 features
public class SLSALevel3Features {
// 1. Binary Authorization
public void verifyBinaryAuthorization() {
// Implement attestation verification
String attestation = System.getenv("SLSA_ATTESTATION");
if (attestation == null) {
throw new SecurityException("Missing SLSA attestation");
}
// Verify signature and provenance
verifyAttestationSignature(attestation);
}
// 2. Ephemeral build environments
public void setupEphemeralBuild() {
// Use isolated, temporary build environments
System.setProperty("maven.repo.local", "/tmp/m2/repository");
}
// 3. Two-person review for critical changes
public boolean verifyTwoPersonReview() {
String reviewers = System.getenv("REQUIRED_REVIEWERS");
return reviewers != null && reviewers.split(",").length >= 2;
}
}
Monitoring and Compliance Checking
// SLSA Compliance Monitor
@Component
public class SLSAComplianceMonitor {
private final SLSAProvenanceService provenanceService;
public SLSAComplianceMonitor(SLSAProvenanceService provenanceService) {
this.provenanceService = provenanceService;
}
@EventListener
public void onApplicationStart(ApplicationReadyEvent event) {
verifyRuntimeCompliance();
}
private void verifyRuntimeCompliance() {
try {
// Verify artifact provenance at runtime
String artifactPath = getCurrentJarPath();
Provenance provenance = provenanceService.verifyProvenance(artifactPath);
if (!provenance.isValid()) {
log.warn("SLSA provenance verification failed");
// Take appropriate action
}
log.info("SLSA compliance verified for build: {}",
provenance.getBuildId());
} catch (Exception e) {
log.error("SLSA compliance check failed", e);
}
}
private String getCurrentJarPath() {
return getClass().getProtectionDomain()
.getCodeSource()
.getLocation()
.getPath();
}
}
Best Practices for Java Teams
- Start Small: Begin with SLSA Level 1 and gradually progress
- Automate Everything: Integrate SLSA checks into your existing CI/CD
- Use Sigstore: Leverage Sigstore for signing and verification
- Generate SBOMs: Make Software Bill of Materials generation mandatory
- Monitor Dependencies: Continuously scan for vulnerabilities
- Educate Teams: Ensure all developers understand SLSA principles
Tools for Java SLSA Compliance
- Sigstore: For signing and verification
- CycloneDX Maven Plugin: For SBOM generation
- SLSA GitHub Generator: For provenance generation
- OpenSSF Scorecard: For security posture assessment
- Reproducible Build Maven Plugin: For consistent builds
Conclusion
Implementing SLSA compliance for Java applications is no longer optional—it's becoming a necessity for secure software delivery. By following this guide, Java teams can:
- Build verifiable artifacts with complete provenance
- Protect against supply chain attacks through rigorous controls
- Meet compliance requirements from customers and regulators
- Establish trust through transparent build processes
The journey to SLSA compliance starts with understanding your current build process and incrementally adding security controls. For Java teams, this means leveraging existing tools like Maven/Gradle plugins, GitHub Actions, and container security features to build a robust, verifiable software supply chain.
Start your SLSA journey today by implementing Level 1 requirements and gradually working toward higher levels of security assurance. Your users—and your security team—will thank you.
Java Logistics, Shipping Integration & Enterprise Inventory Automation (Tracking, ERP, RFID & Billing Systems)
https://macronepal.com/blog/aftership-tracking-in-java-enterprise-package-visibility/
Explains how to integrate AfterShip tracking services into Java applications to provide real-time shipment visibility, delivery status updates, and centralized tracking across multiple courier services.
https://macronepal.com/blog/shipping-integration-using-fedex-api-with-java-for-logistics-automation/
Explains how to integrate the FedEx API into Java systems to automate shipping tasks such as creating shipments, calculating delivery costs, generating shipping labels, and tracking packages.
https://macronepal.com/blog/shipping-and-logistics-integrating-ups-apis-with-java-applications/
Explains UPS API integration in Java to enable automated shipping operations including rate calculation, shipment scheduling, tracking, and delivery confirmation management.
https://macronepal.com/blog/generating-and-reading-qr-codes-for-products-in-java/
Explains how Java applications generate and read QR codes for product identification, tracking, and authentication, supporting faster inventory handling and product verification processes.
https://macronepal.com/blog/designing-a-robust-pick-and-pack-workflow-in-java/
Explains how to design an efficient pick-and-pack workflow in Java warehouse systems, covering order processing, item selection, packaging steps, and logistics preparation to improve fulfillment efficiency.
https://macronepal.com/blog/rfid-inventory-management-system-in-java-a-complete-guide/
Explains how RFID technology integrates with Java applications to automate inventory tracking, reduce manual errors, and enable real-time stock monitoring in warehouses and retail environments.
https://macronepal.com/blog/erp-integration-with-odoo-in-java/
Explains how Java applications connect with Odoo ERP systems to synchronize inventory, orders, customer records, and financial data across enterprise systems.
https://macronepal.com/blog/automated-invoice-generation-creating-professional-excel-invoices-with-apache-poi-in-java/
Explains how to automatically generate professional Excel invoices in Java using Apache POI, enabling structured billing documents and automated financial record creation.
https://macronepal.com/blog/enterprise-financial-integration-using-quickbooks-api-in-java-applications/
Explains QuickBooks API integration in Java to automate financial workflows such as invoice management, payment tracking, accounting synchronization, and financial reporting.