Keamanan Rantai Pasok Software: SBOM dan Sigstore

Foto oleh Jim Bahn on flickr
Software bill of materials adalah daftar terstruktur yang mencatat setiap paket, pustaka, dan versi yang dipanggang ke dalam sebuah build artifact. Pipeline CI membutuhkannya karena pemindaian kerentanan pada kode sumber saja tidak menangkap dependency yang baru diselesaikan dan dibundel ke image container final setelah code review, jadi SBOM harus dibuat dari artifact sesungguhnya yang dirilis, bukan hanya dari lockfile.
Keyless signing menghilangkan beban operasional untuk membuat, menyimpan, dan merotasi kunci privat berumur panjang yang seharusnya dijaga oleh runner CI. Cosign meminta sertifikat berumur pendek dari Fulcio menggunakan token OIDC milik job CI itu sendiri, menandatangani dengan kunci sementara yang langsung dibuang, dan tanda tangan itu terikat pada identitas yang bisa diverifikasi seperti file workflow dan branch persis yang menghasilkannya, sehingga tidak ada rahasia yang bisa bocor sejak awal.
CycloneDX adalah standar OWASP yang dirancang terutama untuk alur kerja keamanan dan kerentanan, dengan dukungan bawaan untuk data kerentanan dan model yang ringkas. SPDX awalnya adalah proyek Linux Foundation yang fokus pada kepatuhan lisensi open source dan belakangan menambahkan field keamanan. Kebanyakan tool SBOM modern, termasuk Syft, mendukung pembuatan kedua format tersebut, jadi pilih sesuai kebutuhan pemindai kerentanan atau proses kepatuhanmu.
Bisa, ini biasanya dilakukan dengan pemeriksaan policy-controller atau admission-webhook di dalam cluster deployment yang memeriksa setiap image yang masuk dan menolak image apa pun tanpa tanda tangan cosign valid yang cocok dengan identitas OIDC yang secara eksplisit masuk allow-list, misalnya path repository dan branch spesifik dari workflow rilismu. Menerima tanda tangan valid apa saja tanpa memeriksa identitas justru menggagalkan tujuan gate itu sendiri.
SLSA Build Level 3 mensyaratkan platform build mengisolasi setiap run sehingga build yang berjalan bersamaan tidak bisa saling memengaruhi, dan menjaga kunci penandatanganan yang dipakai untuk provenance benar-benar tidak bisa diakses oleh langkah build yang didefinisikan pengguna. Kebanyakan tim yang memakai runner CI serbaguna berada di sekitar Build Level 2 dan butuh layanan build khusus yang diperkeras, seperti fitur attestations bawaan GitHub, untuk mencapai Level 3.

Foto oleh Jim Bahn on flickr
Pada tahun 2020, penyerang membobol server build SolarWinds dan menyisipkan backdoor ke dalam update Orion yang sudah ditandatangani, dan pembaruan itu sampai ke sekitar 18.000 pelanggan, termasuk lembaga federal Amerika Serikat. Pada tahun 2024, seorang maintainer menghabiskan waktu bertahun-tahun membangun kepercayaan pada pustaka kompresi xz-utils sebelum diam-diam menambahkan backdoor SSH ke berkas rilisnya. Kedua serangan itu tidak mengeksploitasi bug pada kode aplikasi. Keduanya mengeksploitasi kenyataan bahwa kebanyakan tim tidak punya cara yang bisa diandalkan untuk menjawab pertanyaan sederhana: apa sebenarnya yang kita rilis, dan bisakah kita membuktikan tidak ada yang mengutak-atiknya antara baris kode terakhir sampai container yang berjalan di produksi.
Menutup celah itu butuh tiga hal yang bekerja bersamaan: software bill of materials yang mendaftar setiap komponen dalam sebuah artifact, tanda tangan kriptografis yang membuktikan artifact itu berasal dari pipeline milikmu bukan dari penyerang, dan atestasi provenance yang membuktikan bagaimana artifact itu dibangun. Tulisan ini membahas cara membuat SBOM dengan Syft, menandatangani image container tanpa kunci privat lewat Sigstore cosign, memahami level SLSA yang menggambarkan integritas proses build, dan menghubungkan ketiganya menjadi satu gate CI yang menolak artifact yang belum ditandatangani atau belum diverifikasi sebelum masuk ke produksi.
Aplikasi modern itu dirakit, bukan sekadar ditulis. Layanan Node.js yang biasa saja menarik ratusan dependency transitif, satu base image container, dan sejumlah CI action yang dikunci berdasarkan tag bukan hash. Setiap input itu adalah celah bagi penyerang untuk menyisipkan kode tanpa pernah menyentuh repository milikmu. Permukaan serangan sudah bergeser dari pertanyaan apakah ada orang yang menemukan bug di kodemu, menjadi apakah ada orang yang bisa merusak salah satu dari seratus hal yang menjadi ketergantungan buildmu.
Tidak satu pun dari masalah ini bisa diselesaikan dengan menulis kode aplikasi yang lebih baik. Solusinya adalah membuat pipeline build itu sendiri menghasilkan bukti: daftar apa saja yang masuk ke artifact, tanda tangan yang membuktikan siapa yang membangunnya, dan catatan bagaimana proses build itu berlangsung yang bisa diperiksa secara independen oleh pihak ketiga.
Pemindaian CVE pada repository sumber tidak memberi tahu apa pun tentang apa yang sebenarnya dirilis. Dependency baru diselesaikan, dibundel, dan dipanggang ke dalam image container jauh setelah code review terakhirmu. Selalu buat dan pindai SBOM dari artifact build final, bukan hanya dari package.json atau lockfile saja.
Software bill of materials adalah daftar terstruktur dan dapat dibaca mesin dari setiap paket, pustaka, dan versi yang dipanggang ke dalam sebuah artifact. Dua format yang paling dominan adalah CycloneDX, standar OWASP yang dirancang terutama untuk alur kerja keamanan dan kerentanan, dan SPDX, standar Linux Foundation yang awalnya dibuat untuk kepatuhan lisensi dan kemudian menambahkan field keamanan. Kebanyakan tooling mendukung keduanya, jadi pilih format sesuai kebutuhan pemindai kerentanan atau proses kepatuhan yang kamu pakai.
Syft adalah generator SBOM open source yang paling banyak dipakai. Alat ini bisa memindai image container, filesystem, atau arsip, dan secara otomatis mendeteksi package manager untuk kebanyakan ekosistem umum, termasuk npm, pip, Go modules, dan paket OS di dalam base image. Buat SBOM dari image persis yang akan kamu push, lalu masukkan SBOM itu ke pemindai kerentanan seperti Grype supaya CVE baru terhadap versi dependency yang sudah tetap tetap muncul walau image itu sudah lama dirilis.
# Generate a CycloneDX SBOM for a container image with Syft
syft packages docker:myorg/myapp:1.4.0 \
--output cyclonedx-json=sbom.cdx.json
# Or scan a source directory directly
syft packages dir:. \
--output spdx-json=sbom.spdx.json
# Scan the generated SBOM for known CVEs with Grype
grype sbom:sbom.cdx.json --fail-on highSimpan SBOM sebagai OCI artifact yang menempel pada digest image, bukan sebagai lampiran log build. Dengan begitu, siapa pun yang menarik image itu belakangan bisa mengambil SBOM persis untuk digest tersebut, bahkan berbulan-bulan setelah run CI yang menghasilkannya sudah dibersihkan dari sistem.
Sigstore adalah kumpulan infrastruktur publik gratis untuk menandatangani dan memverifikasi software: Fulcio menerbitkan sertifikat penandatanganan berumur pendek yang terikat pada identitas OpenID Connect, bukan kunci privat berumur panjang, dan Rekor mencatat setiap tanda tangan dalam log transparansi append-only yang bisa diaudit siapa saja. Cosign adalah klien command-line yang menyatukan semua ini untuk image container dan artifact lainnya.
Manfaat praktisnya adalah keyless signing. Alih-alih membuat, merotasi, dan menjaga kunci privat yang harus disimpan oleh runner CI, cosign meminta sertifikat dari Fulcio menggunakan token OIDC milik job CI itu sendiri, menandatangani artifact dengan kunci sementara yang langsung dibuang setelah dipakai, lalu mempublikasikan tanda tangan beserta entri log transparansi Rekor. Tidak ada rahasia berumur panjang yang bisa bocor, dan tanda tangan itu terikat pada identitas yang bisa diverifikasi, misalnya file workflow GitHub Actions dan branch persis yang menghasilkannya.
# Keyless signing inside GitHub Actions (OIDC identity, no private key to manage)
- name: Sign image with cosign
run: |
cosign sign --yes \
${{ steps.build.outputs.digest }}
# Attach the SBOM as a signed attestation on the same digest
cosign attest --yes \
--predicate sbom.cdx.json \
--type cyclonedx \
myorg/myapp@sha256:${DIGEST}
# Verify later, from any machine, against the recorded identity
cosign verify \
--certificate-identity="https://github.com/myorg/myapp/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
myorg/myapp@sha256:${DIGEST}Kamu bisa melangkah lebih jauh dengan melampirkan SBOM itu sendiri sebagai atestasi yang ditandatangani pada digest image yang sama memakai cosign attest. Satu perintah itu menghasilkan satu objek yang bisa diverifikasi secara kriptografis dan menyatakan: SBOM persis ini menggambarkan image persis ini, dan ditandatangani oleh identitas pipeline persis ini.
SBOM menjelaskan apa isi sebuah artifact dan tanda tangan membuktikan siapa yang mempublikasikannya, tapi keduanya tidak menjelaskan bagaimana artifact itu dibangun atau apakah proses buildnya sendiri bisa saja dimanipulasi. Itulah yang dijawab oleh SLSA, Supply-chain Levels for Software Artifacts. Kerangka ini mendefinisikan build track dengan empat level, masing-masing menambahkan jaminan yang lebih kuat soal integritas platform build dan provenance yang dihasilkannya.
| Level | Apa yang disyaratkan | Risiko apa yang dicegah |
|---|---|---|
| Build L0 | Tidak ada syarat apa pun. Biasa terjadi pada build yang dijalankan di laptop developer tanpa provenance yang tercatat. | Tidak ada. Tidak ada cara untuk mengetahui bagaimana atau di mana artifact itu dihasilkan. |
| Build L1 | Platform build secara otomatis menghasilkan provenance yang menjelaskan proses build dan input utamanya, lalu mendistribusikannya ke konsumen. | Kesalahan yang tidak disengaja, karena provenance sudah ada tapi belum tahan terhadap manipulasi. |
| Build L2 | Build berjalan di platform build bersama yang di-hosting, dan provenance-nya ditandatangani oleh platform tersebut. | Manipulasi setelah build terhadap artifact atau provenance-nya, karena tanda tangan akan mendeteksi perubahan. |
| Build L3 | Platform build mengisolasi setiap run supaya build tidak bisa saling memengaruhi, dan menjaga kunci penandatanganan agar tidak bisa diakses oleh langkah build yang didefinisikan pengguna. | Manipulasi selama proses build berlangsung dan ancaman dari orang dalam pada satu job build tertentu. |
Kebanyakan tim yang membangun di GitHub Actions atau GitLab CI dengan runner ter-hosting dan langkah provenance yang ditandatangani sudah berada di sekitar Build L2. Mencapai L3 biasanya berarti mengadopsi layanan build khusus yang dirancang untuk isolasi, seperti fitur attestations bawaan GitHub atau platform build yang sudah diperkeras, bukan sekadar runner CI serbaguna.
Semua ini tidak melindungi apa pun kalau hasilnya cuma artifact yang tidak pernah diperiksa siapa pun. Nilainya baru terasa kalau verifikasi tanda tangan dan SBOM dijadikan gate yang keras, baik di CI sebelum merge maupun saat deploy sebelum image sampai ke cluster.
Langkah terakhir ini lebih penting dari yang terlihat. Tanda tangan cosign yang valid hanya membuktikan bahwa image ditandatangani oleh identitas apa pun yang meminta sertifikat itu. Kalau gate-mu menerima tanda tangan valid apa saja bukan hanya dari identitas yang secara eksplisit masuk allow-list, penyerang yang berhasil membobol lingkungan satu developer yang punya akses OIDC tetap bisa menandatangani dan merilis image berbahaya.
Mengunci GitHub Actions berdasarkan tag, seperti v4, saja tidak cukup. Tag itu bisa diubah dan diarahkan ulang oleh siapa pun yang punya akses tulis ke repository action tersebut. Kunci action pihak ketiga berdasarkan commit SHA lengkap, dan perlakukan file workflow CI-mu dengan kehati-hatian yang sama seperti kode produksi, karena file itu bagian dari jalur build tepercaya yang ingin dilindungi oleh SLSA.
SBOM, penandatanganan, dan provenance bukan tiga inisiatif terpisah, ketiganya adalah satu pipeline: buat SBOM dari artifact yang sudah dibangun, pindai kerentanan yang sudah dikenal, tandatangani artifact dan SBOM-nya bersamaan lewat alur keyless cosign, lalu jadikan setiap deployment tergantung pada verifikasi tanda tangan itu terhadap identitas yang secara eksplisit kamu percayai. Tidak ada satu pun komponen ini yang lagi jadi teknologi eksotis. Yang kebanyakan tim belum punya hanyalah menghubungkan semuanya jadi gate, bukan membiarkannya sebagai laporan opsional yang tidak pernah dibaca siapa pun.
Mulai dari pembuatan SBOM dan pemindaian kerentanan dulu meskipun kamu belum siap menerapkan penandatanganan. Visibilitas saja, mengetahui persis base image dan paket apa yang kamu rilis, sudah menangkap masalah nyata jauh sebelum kamu sampai ke pekerjaan yang lebih berat yaitu penegakan tanda tangan berbasis identitas.