Series MapLesson 27 / 34
Deepen PracticeOrdered learning track

Learn Java Security Cryptography Integrity Hardening Part 027 Artifact Signing Jarsigner Cosign

14 min read2794 words
PrevNext
Lesson 2734 lesson track1928 Deepen Practice

title: Learn Java Security, Cryptography, Integrity and Platform Hardening - Part 027 description: Artifact signing untuk Java: JAR signing, jarsigner, Maven artifact signing, Sigstore/cosign, container image verification, trust policy, timestamping, revocation, dan release gate yang fail-closed. series: learn-java-security-cryptography-integrity-hardening seriesTitle: Learn Java Security, Cryptography, Integrity and Platform Hardening order: 27 partTitle: Artifact Signing, jarsigner and cosign tags:

  • java
  • security
  • cryptography
  • integrity
  • platform-hardening
  • artifact-signing
  • jarsigner
  • cosign
  • sigstore
  • supply-chain date: 2026-06-28

Part 027 — Artifact Signing, jarsigner and cosign

Tujuan bagian ini: membangun kemampuan untuk menjawab pertanyaan berikut secara teknis, operasional, dan defensible:

Apakah artifact Java yang kita build, publish, promote, dan deploy masih sama dengan artifact yang disetujui, berasal dari signer yang dipercaya, dan belum dimodifikasi setelah proses release?

Part 025 membahas dependency supply-chain risk. Part 026 membahas SBOM, provenance, dan SLSA. Part 027 membahas artifact signing: mekanisme cryptographic binding antara artifact, signer identity, metadata, waktu, dan trust policy.

Mental model:

Hash memberi identity. Signature memberi authenticity dan tamper evidence. Certificate memberi binding ke identity. Timestamp memberi konteks waktu. Policy memberi keputusan boleh/tidak boleh dipakai.

Referensi utama:


1. Posisi Bagian Ini dalam Framework Kaufman

Dalam Kaufman-style skill acquisition, artifact signing dipecah menjadi subskill kecil:

SubskillPertanyaanOutput
Artifact identityArtifact mana yang sedang diverifikasi?Digest, coordinate, tag, immutable reference
Signing primitiveApa yang ditandatangani?Bytes/canonical payload
Signer identitySiapa/apa signer-nya?Certificate, key, Fulcio identity, GPG key
VerificationBagaimana membuktikan signature valid?Verification command/library result
Trust policySignature valid saja cukup?Allow/deny decision
TimestampingValid pada waktu kapan?Signed timestamp / transparency log evidence
Revocation and compromiseBagaimana kalau key bocor?Key rotation and distrust plan
Release gateDi titik mana verification wajib?CI/CD/admission policy
Evidence retentionBagaimana audit nanti membuktikan?Release evidence packet

Target kita bukan hafal command jarsigner. Targetnya adalah mampu mendesain integrity chain dari source sampai runtime.


2. Problem yang Ingin Diselesaikan

Tanpa signing dan verification policy, pipeline modern mudah jatuh ke kondisi berikut:

  • CI membangun artifact yang benar, tetapi artifact yang berbeda masuk registry.
  • Developer meng-upload JAR manual tanpa provenance.
  • Container tag latest berubah tanpa bukti siapa yang mengubah.
  • Dependency internal diserang lewat repository poisoning.
  • Build plugin menghasilkan bytecode tambahan yang tidak terlihat dalam review.
  • Artifact production tidak bisa dibuktikan berasal dari commit tertentu.
  • Incident response tidak tahu artifact mana yang harus dicabut.

Artifact signing tidak membuat kode aman. Ia menjawab pertanyaan lebih sempit:

Apakah artifact ini masih artifact yang sama dan ditandatangani oleh identity yang kita percaya?

Security mistake paling umum: menganggap “signed” berarti “safe”. Signature tidak membuktikan kode bebas vulnerability. Signature hanya membuktikan origin dan integrity relatif terhadap trust policy.


3. Empat Layer Integrity Artifact

Layer yang perlu dipisahkan:

LayerMenjawabContoh
DigestArtifact ini byte-for-byte apa?SHA-256 digest
SignatureSiapa/apa menandatangani digest/payload?JAR signature, cosign signature
AttestationMetadata apa yang diikat ke artifact?SBOM, provenance, test result
PolicyArtifact boleh dipakai?Required signer, builder, branch, environment

Signature tanpa policy hanya dekorasi. Policy tanpa signature mudah dipalsukan. Provenance tanpa artifact digest tidak mengikat ke binary tertentu.


4. Artifact Identity: Jangan Mulai dari Nama File

Nama file bukan identity keamanan.

Buruk:

case-management-service-1.8.4.jar
registry.example.com/case-management-service:prod

Lebih baik:

case-management-service-1.8.4.jar
sha256:7d2c...f91a

registry.example.com/case-management-service@sha256:3ae4...18bc

Invariant:

Semua verification, signing, SBOM, provenance, dan deployment decision harus mengikat ke immutable digest, bukan mutable name/tag.

Untuk Java build, coordinate seperti groupId:artifactId:version berguna untuk dependency management, tetapi bukan bukti integrity. Coordinate harus dipasangkan dengan digest dan sumber repository yang dipercaya.


5. Model JAR Signing

JAR adalah ZIP archive dengan manifest dan metadata di META-INF. Signing JAR secara konseptual membuat digest entry, lalu signature atas manifest/digest tersebut.

Komponen umum signed JAR:

KomponenFungsi
META-INF/MANIFEST.MFMetadata JAR dan digest per entry
META-INF/*.SFSignature file yang memuat digest manifest/sections
META-INF/*.RSA, *.DSA, *.ECSignature block dan certificate
KeystoreTempat private key dan certificate signer
Timestamp authorityMembuktikan waktu signing

JAR signing cocok untuk beberapa use case:

  • plugin JAR yang dimuat oleh platform internal;
  • distribusi library ke repository publik;
  • artifact yang perlu origin verification di runtime;
  • compliance evidence bahwa release ditandatangani identity resmi.

Tetapi JAR signing bukan silver bullet:

  • tidak membuktikan source commit;
  • tidak membuktikan build reproducible;
  • tidak membuktikan dependency aman;
  • tidak otomatis diverifikasi oleh semua runtime path;
  • bisa rusak bila artifact dimodifikasi setelah signing.

6. Signing JAR dengan jarsigner

Minimal signing flow:

# 1. Buat atau pakai keystore yang dikelola secure
keytool -genkeypair \
  -alias release-signing \
  -keyalg RSA \
  -keysize 3072 \
  -validity 365 \
  -keystore release-signing.p12 \
  -storetype PKCS12

# 2. Sign JAR
jarsigner \
  -keystore release-signing.p12 \
  -storetype PKCS12 \
  -signedjar app-signed.jar \
  app.jar \
  release-signing

# 3. Verify JAR
jarsigner -verify -verbose -certs app-signed.jar

Untuk production, jangan berhenti di minimal flow. Tambahkan:

  • dedicated release signing key;
  • key generated/stored di HSM/KMS bila memungkinkan;
  • timestamping authority;
  • explicit digest/signature algorithm;
  • CI-controlled signing step;
  • verification step setelah upload/download dari repository;
  • evidence retention.

Contoh dengan timestamp dan algorithm explicit:

jarsigner \
  -keystore release-signing.p12 \
  -storetype PKCS12 \
  -tsa https://timestamp.example.com \
  -digestalg SHA-256 \
  -sigalg SHA256withRSA \
  -signedjar app-signed.jar \
  app.jar \
  release-signing

Catatan penting:

  • Algorithm yang acceptable harus mengikuti kebijakan kriptografi organisasi.
  • Hindari key dan password di command history/log CI.
  • Jangan menandatangani artifact lokal developer untuk release resmi.
  • Signing harus terjadi setelah build final, bukan sebelum shading/repackaging.

7. Verification Bukan Formalitas

Command verify dasar:

jarsigner -verify app-signed.jar

Untuk gate, gunakan output verbose dan fail bila ada warning terkait:

jarsigner -verify -strict -verbose -certs app-signed.jar

Verification harus menjawab beberapa pertanyaan:

PertanyaanHarus dicek?
Signature cryptographically valid?Ya
Semua entry relevan signed?Ya
Certificate chain trusted?Ya
Certificate expired/revoked?Ya, sesuai policy
Timestamp valid?Ya untuk release panjang umur
Signer termasuk allowlist?Ya
Algorithm allowed?Ya
Artifact digest cocok dengan provenance/SBOM?Ya

Anti-pattern:

jarsigner -verify app.jar || true

Ini mengubah control menjadi theater. Verification gate harus fail-closed.


8. Runtime Verification untuk Plugin JAR

Untuk platform yang memuat plugin, JAR signing bisa diverifikasi sebelum classloading.

Sketch:

import java.io.IOException;
import java.nio.file.Path;
import java.security.CodeSigner;
import java.security.cert.Certificate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public final class SignedJarVerifier {

    public void verifyAllEntriesSigned(Path jarPath) throws IOException {
        try (JarFile jar = new JarFile(jarPath.toFile(), true)) {
            var entries = jar.entries();
            byte[] buffer = new byte[8192];

            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();

                if (entry.isDirectory() || entry.getName().startsWith("META-INF/")) {
                    continue;
                }

                // Reading the entire entry triggers signature verification.
                try (var in = jar.getInputStream(entry)) {
                    while (in.read(buffer) != -1) {
                        // consume stream
                    }
                }

                CodeSigner[] signers = entry.getCodeSigners();
                Certificate[] certs = entry.getCertificates();

                if ((signers == null || signers.length == 0) && (certs == null || certs.length == 0)) {
                    throw new SecurityException("Unsigned JAR entry: " + entry.getName());
                }
            }
        }
    }
}

Ini belum cukup untuk production. Tambahkan:

  • certificate chain validation terhadap trust anchor internal;
  • signer allowlist;
  • algorithm policy;
  • expiry/revocation policy;
  • plugin manifest policy;
  • version compatibility;
  • isolated classloader atau process isolation.

Invariant plugin platform:

Tidak ada bytecode plugin yang boleh dimuat sebelum artifact identity, signature, signer, manifest policy, dan capability policy diverifikasi.


9. Detached Signature untuk Artifact Non-JAR

Tidak semua artifact cocok disigned secara embedded. Container image, SBOM, provenance, native binary, ZIP bundle, dan config bundle sering memakai detached signature.

Keuntungan detached signature:

  • tidak mengubah artifact bytes;
  • cocok untuk content-addressed image;
  • bisa menyimpan banyak signature untuk artifact yang sama;
  • cocok untuk attestations;
  • lebih mudah dipakai di policy engine.

Risiko:

  • signature object harus ditemukan dan diikat ke digest yang benar;
  • registry/tag mutation tetap harus dicegah;
  • verification policy harus jelas;
  • metadata store menjadi bagian dari trust model.

10. Sigstore dan cosign

Sigstore/cosign populer untuk signing dan verifying container images serta blobs. Ada dua mode besar:

ModeKarakteristik
KeyfulSigner memakai key yang dikelola sendiri/KMS/HSM
KeylessIdentity berasal dari OIDC, certificate short-lived, dan transparency log

Contoh keyless signing image:

cosign sign registry.example.com/case-management-service@sha256:3ae4...

Contoh verification dengan identity policy:

cosign verify \
  --certificate-identity "https://github.com/acme/case-management/.github/workflows/release.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  registry.example.com/case-management-service@sha256:3ae4...

Contoh signing blob:

cosign sign-blob \
  --output-signature app.jar.sig \
  --output-certificate app.jar.pem \
  app.jar

Contoh verify blob:

cosign verify-blob \
  --certificate app.jar.pem \
  --signature app.jar.sig \
  --certificate-identity "release@acme.example" \
  --certificate-oidc-issuer "https://issuer.example" \
  app.jar

Security point:

Jangan hanya menjalankan cosign verify. Selalu nyatakan identity/issuer/key policy yang diharapkan.

Tanpa identity policy, Anda bisa membuktikan artifact ditandatangani oleh seseorang, tetapi belum tentu oleh signer yang benar.


11. JAR Signing vs Container Signing

AspekJAR SigningContainer Signing
TargetIsi JAR/ZIPImage digest
SignatureEmbedded di JARDetached di registry/transparency log
Tooljarsignercosign
Runtime usePlugin verification, library distributionAdmission control, deploy gate
MetadataCertificate dalam signature blockCertificate/attestation external
Risk utamaRepackaging invalidates signatureTag mutation, weak policy

Untuk service Java modern, biasanya keduanya relevan:

  • JAR internal bisa signed untuk artifact integrity.
  • Container image signed untuk deployment integrity.
  • SBOM/provenance attested untuk supply-chain evidence.

12. Artifact Signing in Maven/Gradle Publishing

Public Maven publishing often requires signed artifacts. Common outputs:

my-library-1.2.3.jar
my-library-1.2.3.jar.asc
my-library-1.2.3.pom
my-library-1.2.3.pom.asc
my-library-1.2.3-sources.jar
my-library-1.2.3-sources.jar.asc

This is usually PGP/GPG signing, not jarsigner embedded signing.

Difference:

TypeWhat it signsTypical verification
PGP artifact signatureWhole file as detached signatureRepository/client/tool policy
JAR signingJAR entries inside archivejarsigner, runtime API
Container signingImage digestcosign, admission policy

For internal organizations, standardize:

  • which artifacts must be signed;
  • who/what may sign release artifacts;
  • whether developer-local signatures are accepted;
  • how keys are rotated;
  • where public keys/certificates are distributed;
  • whether unsigned artifacts can enter artifact repositories.

13. Trust Policy: The Part Most Teams Skip

Signature verification has two stages:

Example policy fields:

artifactPolicy:
  artifact: case-management-service
  required:
    imageSignature: true
    provenance: true
    sbom: true
  signer:
    oidcIssuer: https://token.actions.githubusercontent.com
    identity: https://github.com/acme/case-management/.github/workflows/release.yml@refs/heads/main
  source:
    repository: github.com/acme/case-management
    branch: main
  builder:
    type: github-actions
  algorithms:
    disallow:
      - SHA1
      - MD5
  deployment:
    environment: production
    requireImmutableDigest: true

Policy should be versioned like code. A production incident often depends on knowing what policy was active at release time.


14. CI/CD Release Gate Pattern

Recommended gates:

Important design choice:

Verification must happen after artifact crosses each trust boundary.

Examples:

  • after build before upload;
  • after upload by downloading from repository and verifying again;
  • before promotion from dev to staging;
  • before production deploy;
  • at Kubernetes admission;
  • during periodic runtime inventory audit.

15. Admission Control for Java Services

For Kubernetes-deployed Java services, signing policy belongs near admission control.

Bad model:

CI signs image, but cluster deploys any image tag if someone has kubectl access.

Better model:

Cluster refuses image unless digest is signed by approved identity and has required attestations.

Pseudo-policy:

allow deployment if:
  image reference uses digest, not mutable tag
  image digest has valid signature
  signer identity is trusted release workflow
  provenance exists and references expected repository
  SBOM exists and passes vulnerability/license gate
  environment matches release approval
otherwise reject

For high-risk systems, combine:

  • registry immutability;
  • signed image digest;
  • provenance attestation;
  • namespace admission policy;
  • runtime inventory reporting;
  • break-glass logging.

16. Key Management for Signing Keys

Signing key compromise is severe because it can authorize malicious artifacts.

Signing key controls:

ControlReason
Dedicated release keyAvoid reuse with developer identity
HSM/KMS-backed signingReduce key exfiltration risk
Short-lived credentialsReduce blast radius
OIDC-bound signingBind signing to pipeline identity
MFA for manual releaseReduce account takeover risk
Separation of dutiesBuild cannot silently approve itself
Key rotation runbookPrepare for compromise
Revocation/disallow listStop trusting bad signer

Do not store signing private key as plain CI secret if a KMS/HSM/keyless approach is available. If CI secret is unavoidable, treat it as crown-jewel secret with strict access, masking, rotation, and audit.


17. Timestamping and Long-Lived Verification

Without timestamping, an artifact signed with an expired certificate creates ambiguity:

  • Was it signed while certificate was valid?
  • Was it signed after compromise?
  • Should old releases remain trusted?

Timestamping helps separate:

ConceptMeaning
Signing timeWhen signer produced signature
Certificate validityWhether cert was valid at that time
Verification timeWhen verifier checks artifact
Revocation timeWhen trust was withdrawn
Policy timeWhich policy was active

For regulated/release systems, keep evidence packet:

artifact digest
signature
signer certificate/identity
timestamp evidence
provenance
SBOM
policy version
CI run ID
approver record
verification output

18. Revocation, Distrust, and Re-Signing

Revocation strategy depends on why trust changes.

ScenarioResponse
Certificate expired normallyKeep old timestamped artifacts valid if policy allows
Signing key leakedDistrust signatures after suspected compromise time; investigate prior signatures
CI workflow compromisedRevoke trust in workflow identity; review provenance and release window
Artifact registry compromisedRe-verify all promoted digests from trusted evidence
Algorithm deprecatedStop new signatures; plan re-signing/migration

Key compromise playbook should answer:

  • Which artifacts were signed by this key?
  • Which environments accepted them?
  • Which artifacts are currently running?
  • What was the first suspicious signing event?
  • Can we distinguish legitimate vs malicious signatures?
  • How do we rotate trust without bricking production?

19. Common Anti-Patterns

19.1 Signing Mutable Tags

cosign sign registry.example.com/app:latest

This can be misleading. Prefer digest references.

cosign sign registry.example.com/app@sha256:...

19.2 Verifying Signature but Not Identity

cosign verify registry.example.com/app@sha256:...

Better:

cosign verify \
  --certificate-identity "...expected workflow identity..." \
  --certificate-oidc-issuer "...expected issuer..." \
  registry.example.com/app@sha256:...

19.3 Signing Before Final Mutation

If the artifact is modified after signing, signature no longer protects the final artifact.

Bad sequence:

package -> sign -> shade/rewrite -> upload

Good sequence:

package -> shade/rewrite -> sign -> upload -> download -> verify

19.4 Trusting Any Corporate Key

“Signed by any internal key” is too broad. Production release should require specific signer identity and workflow context.

19.5 Treating Signature as Vulnerability Scan

Signed vulnerable code is still vulnerable. Signing is integrity, not vulnerability elimination.


20. Java Implementation Pattern: Release Evidence Manifest

Create a small release evidence manifest that binds everything together.

{
  "artifact": {
    "name": "case-management-service",
    "version": "1.8.4",
    "jarDigest": "sha256:...",
    "imageDigest": "sha256:..."
  },
  "source": {
    "repository": "github.com/acme/case-management",
    "commit": "8c0f...",
    "branch": "main"
  },
  "build": {
    "pipeline": "release.yml",
    "runId": "123456789",
    "builder": "github-actions"
  },
  "signatures": {
    "jar": "app.jar.sig",
    "image": "cosign"
  },
  "attestations": {
    "sbom": "cyclonedx-json",
    "provenance": "slsa"
  },
  "policy": {
    "version": "release-policy-2026-06-28",
    "decision": "allow"
  }
}

Store this manifest as signed metadata, not as an editable wiki entry.


21. Verification Service Design

For large platforms, create a verification service or library used by deployment tools.

API sketch:

public interface ArtifactVerifier {
    VerificationDecision verify(ArtifactReference artifact, DeploymentContext context);
}

public record ArtifactReference(
        String registry,
        String repository,
        String digest
) {}

public record DeploymentContext(
        String environment,
        String serviceName,
        String namespace,
        String requestedBy,
        String policyVersion
) {}

public record VerificationDecision(
        boolean allowed,
        String reason,
        String signerIdentity,
        String provenanceDigest,
        String sbomDigest
) {}

Avoid returning only boolean. Security decisions need explainability.


22. Policy Failure Classification

Not all failures are equal.

FailureMeaningAction
Missing signatureNo authenticity evidenceReject
Invalid signatureArtifact/signature mismatchReject and investigate
Unknown signerValid but untrusted signerReject
Wrong issuerPossible identity confusionReject
Missing provenanceCannot prove build originReject or quarantine
Vulnerable SBOMKnown riskReject/exception workflow
Expired cert with valid timestampDepends policyAllow/review
Revoked signerTrust withdrawnReject and incident review

Never collapse all failures into “verification failed”. Auditors and responders need cause.


23. Release Evidence Packet

For every production release, retain:

1. Source repository and commit
2. Build pipeline ID and logs digest
3. Test report digest
4. JAR digest
5. Container image digest
6. JAR/container signatures
7. SBOM digest and content
8. Provenance attestation
9. Policy version and decision
10. Approver identity and timestamp
11. Deployment target and time
12. Runtime inventory confirmation

Evidence packet must itself be tamper-evident. Store it in append-only storage or sign it.


24. Review Checklist

Use this checklist for Java release pipelines:

  • Are release artifacts identified by digest?
  • Are mutable tags disallowed in production deployment?
  • Is JAR signing needed, container signing needed, or both?
  • Are signatures verified after upload/download boundary?
  • Is signer identity restricted to release workflow?
  • Is verification fail-closed?
  • Are weak algorithms disallowed?
  • Are timestamps captured for long-lived artifacts?
  • Is key compromise playbook documented?
  • Are SBOM and provenance attached to the same digest?
  • Is policy versioned and auditable?
  • Are break-glass deployments logged and reviewed?
  • Can incident response query all artifacts signed by a compromised signer?

25. Hands-on Lab

Lab 1 — Sign and Verify JAR

  1. Build a small Java JAR.
  2. Sign it with jarsigner.
  3. Verify it with jarsigner -verify -strict -verbose -certs.
  4. Modify one file in the JAR.
  5. Verify again and observe failure.

Expected lesson:

Signature protects bytes. Any post-signing mutation must be detected.

Lab 2 — Build Release Evidence Manifest

Create JSON containing:

  • artifact name/version;
  • JAR digest;
  • image digest;
  • source commit;
  • signer identity;
  • policy version.

Sign the manifest separately.

Expected lesson:

Release evidence must bind artifact, source, signer, and policy.

Lab 3 — Cosign Verification Policy

  1. Sign an image digest using cosign.
  2. Verify without identity policy.
  3. Verify with expected identity/issuer.
  4. Change identity expectation and confirm rejection.

Expected lesson:

Valid signature is not enough. The signer must be the expected signer.


26. Decision Record Template

# ADR: Artifact Signing Policy for <Service>

## Context
<Why this service needs signing and verification.>

## Artifacts Covered
- JAR: yes/no
- Container image: yes/no
- SBOM: yes/no
- Provenance: yes/no

## Signer Identity
<Expected key/certificate/OIDC identity.>

## Verification Points
- CI post-build
- Repository post-upload
- Promotion gate
- Admission control
- Runtime inventory audit

## Trust Policy
<Allowed signer, issuer, branch, builder, algorithm, timestamp.>

## Failure Behavior
<Fail-closed behavior, exception process, break-glass.>

## Key Rotation / Revocation
<Rotation schedule and compromise handling.>

## Evidence Retention
<What evidence is stored, where, and for how long.>

27. Summary

Artifact signing is not about adding a signature file to a release. It is about controlling trust transitions.

Key takeaways:

  • Use digest as artifact identity.
  • Use signature to prove authenticity and tamper evidence.
  • Use policy to decide whether valid signature is acceptable.
  • Use timestamp/provenance/SBOM to make release evidence defensible.
  • Verify after every trust boundary.
  • Fail closed on missing/invalid/untrusted signatures.
  • Prepare key compromise and revocation before incident day.

The top 1% engineering move is not “we sign artifacts”. It is:

We can prove exactly what was built, who/what signed it, what policy accepted it, where it ran, and how we would revoke trust if that signer was compromised.


28. What Comes Next

Part 028 moves from artifact integrity to operational evidence:

  • secure logging;
  • audit trail design;
  • tamper-evident logs;
  • forensic readiness;
  • actor attribution;
  • privacy-safe observability;
  • incident investigation evidence.
Lesson Recap

You just completed lesson 27 in deepen practice. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.