Core Java

Set Up a True Zero-Trust CI/CD for Java Apps: GitOps Deployments with Signed Immutable Artifacts

The concept of Zero Trust is often discussed in the context of network security, but it’s equally crucial for your software delivery pipeline. In a world of supply chain attacks, insider threats, and compromised build servers, a Zero-Trust CI/CD ensures that every deployment can be verified, audited, and trusted—no matter where it comes from.

In this guide, we’ll show how to set up a true Zero-Trust pipeline for Java applications, using GitOps, signed immutable artifacts, and secure verification steps before deployment.

1. What Is Zero Trust in CI/CD?

A Zero-Trust CI/CD pipeline assumes:

  • No build agent is inherently trusted.
  • No artifact is safe unless verified.
  • No deployment happens without a signature check.

This approach ensures:

  • You can trace exactly which commit was deployed.
  • Artifacts can’t be tampered with after build.
  • Only signed and approved versions go to production.

2. Core Components of a Zero-Trust Java Pipeline

ComponentPurpose
GitOpsDeployment driven entirely by Git commits—production mirrors repo state.
Immutable ArtifactsOnce built, they cannot be modified (e.g., versioned JARs or container images).
Artifact SigningEach artifact is cryptographically signed (e.g., Sigstore Cosign, GPG).
Signature VerificationKubernetes or deployment agents verify signatures before applying.

3. Example Architecture

  1. Developer merges code → CI builds artifact.
  2. CI signs artifact → pushes to registry.
  3. GitOps tool (e.g., Argo CD, Flux) monitors GitOps repo.
  4. Deployment manifest references signed immutable artifact.
  5. Signature verified before deployment → if invalid, block release.

4. Step-by-Step Setup

4.1 Build and Sign Immutable Java Artifacts

Let’s assume you package your Java app as a container image.

Dockerfile:

FROM eclipse-temurin:17-jdk
COPY target/myapp-1.0.0.jar /app/myapp.jar
ENTRYPOINT ["java", "-jar", "/app/myapp.jar"]

GitHub Actions Build & Sign with Cosign:

name: Build and Sign
on:
  push:
    branches: [ "main" ]

jobs:
  build-sign:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
      - run: mvn clean package -DskipTests
      - run: docker build -t ghcr.io/my-org/myapp:${GITHUB_SHA} .
      - run: echo "${{ secrets.COSIGN_KEY }}" > cosign.key
      - run: cosign sign --key cosign.key ghcr.io/my-org/myapp:${GITHUB_SHA}

Here, the container image is immutable because it’s tagged with the commit SHA.

4.2 GitOps Deployment with Argo CD

In GitOps, you don’t kubectl apply from CI. Instead, CI updates Kubernetes manifests in a separate Git repo, and Argo CD syncs them.

Deployment manifest example (deployment.yaml):

spec:
  template:
    spec:
      containers:
        - name: myapp
          image: ghcr.io/my-org/myapp:3a4b5c6

The commit to this GitOps repo is what triggers deployment.

4.3 Signature Verification Before Deployment

If we want true Zero Trust, Argo CD should verify the artifact signature before allowing deployment.

Example using Cosign policy-controller:

apiVersion: policy.sigstore.dev/v1beta1
kind: ClusterImagePolicy
metadata:
  name: verify-myapp-signature
spec:
  images:
    - glob: "ghcr.io/my-org/myapp:*"
  authorities:
    - key:
        secretRef:
          name: cosign-public-key

This ensures:

  • If the image is unsigned or signed with the wrong key, Kubernetes rejects it.

5. Putting It All Together

Pipeline Flow:

  1. Build → Java JAR inside container → tag with commit SHA.
  2. Sign → Using Cosign or GPG.
  3. Push → Immutable artifact to registry.
  4. Commit → Update GitOps repo with artifact reference.
  5. Sync → Argo CD deploys only if signature matches trusted key.

6. Real-World Example

Imagine an attacker gains access to your container registry and swaps your image with a malicious one.
Without signing, Kubernetes would deploy it.
With this Zero-Trust setup:

  • Kubernetes refuses to deploy unsigned or invalidly signed images.
  • The Git commit history still reflects the intended version—alerting you to any tampering.

7. Best Practices

  • Use short-lived signing keys and rotate them regularly.
  • Store signing keys in secure vaults (Vault, AWS KMS, GCP KMS).
  • Enforce immutable tags in your container registry.
  • Automate verification in staging and production environments.
  • Audit your GitOps repo to ensure only approved changes are merged.

8. Final Thoughts

A Zero-Trust CI/CD pipeline for Java apps is more than just “secure builds.”
It’s about making every step verifiable, every artifact immutable, and every deployment intentional.

By combining GitOps, artifact signing, and signature verification, you can make your pipeline resilient against supply chain attacks—and sleep better knowing your deployments are exactly what you built.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button