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
| Component | Purpose |
|---|---|
| GitOps | Deployment driven entirely by Git commits—production mirrors repo state. |
| Immutable Artifacts | Once built, they cannot be modified (e.g., versioned JARs or container images). |
| Artifact Signing | Each artifact is cryptographically signed (e.g., Sigstore Cosign, GPG). |
| Signature Verification | Kubernetes or deployment agents verify signatures before applying. |
3. Example Architecture
- Developer merges code → CI builds artifact.
- CI signs artifact → pushes to registry.
- GitOps tool (e.g., Argo CD, Flux) monitors GitOps repo.
- Deployment manifest references signed immutable artifact.
- 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:
- Build → Java JAR inside container → tag with commit SHA.
- Sign → Using Cosign or GPG.
- Push → Immutable artifact to registry.
- Commit → Update GitOps repo with artifact reference.
- 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.

