Pengelolaan dependensi

Dokumen ini menjelaskan dependensi aplikasi dan praktik terbaik untuk mengelolanya, termasuk pemantauan kerentanan, verifikasi artefak, mengurangi jejak dependensi, dan mendukung build yang dapat direproduksi.

Dependensi software adalah bagian software yang diperlukan aplikasi Anda agar dapat berfungsi, seperti library software atau plugin. Penyelesaian dependensi dapat terjadi saat Anda mengompilasi kode, membangun, menjalankan, mendownload, atau menginstal software.

Dependensi dapat mencakup komponen yang Anda buat, software pihak ketiga berpemilik, dan software open source. Pendekatan yang Anda lakukan untuk mengelola dependensi dapat memengaruhi keamanan dan keandalan aplikasi Anda.

Spesifikasi untuk menerapkan praktik terbaik dapat bervariasi menurut format artefak dan alat yang Anda gunakan, tetapi prinsip umumnya tetap berlaku.

Dependensi langsung dan transitif

Aplikasi Anda dapat menyertakan dependensi langsung dan transitif:

Dependensi langsung
Komponen software yang direferensikan aplikasi secara langsung.
Dependensi transitif
Komponen software yang secara fungsional diperlukan oleh dependensi langsung aplikasi. Setiap dependensi dapat memiliki dependensi langsung dan tidak langsungnya sendiri, sehingga membuat hierarki rekursif dependensi transitif yang semuanya memengaruhi aplikasi.

Bahasa pemrograman yang berbeda menawarkan tingkat visibilitas yang berbeda ke dalam dependensi dan hubungannya. Selain itu, beberapa bahasa menggunakan pengelola paket untuk menyelesaikan hierarki dependensi saat menginstal atau men-deploy paket.

Dalam ekosistem Node.js, pengelola paket npm dan yarn menggunakan file lock untuk mengidentifikasi versi dependensi untuk membangun modul dan versi dependensi yang didownload pengelola paket untuk penginstalan modul tertentu. Di ekosistem bahasa lain seperti Java, dukungan untuk introspeksi dependensi lebih terbatas. Selain itu, sistem build harus menggunakan pengelola dependensi tertentu untuk mengelola dependensi secara sistematis.

Sebagai contoh, pertimbangkan modul npm glob versi 8.0.2. Anda mendeklarasikan dependensi langsung untuk modul npm dalam file package.json. Dalam file package.json untuk glob, bagian dependencies mencantumkan dependensi langsung untuk paket yang dipublikasikan. Bagian devDepdencies mencantumkan dependensi untuk pengembangan dan pengujian lokal oleh pengelola dan kontributor glob

  • Di situs npm, halaman glob mencantumkan dependensi langsung dan dependensi pengembangan, tetapi tidak menunjukkan apakah modul ini juga memiliki dependensi sendiri.

  • Anda dapat menemukan informasi dependensi tambahan tentang glob di situs Open Source Insights. Daftar dependensi untuk glob mencakup dependensi langsung dan dependensi tidak langsung (transitif).

    Dependensi transitif dapat memiliki beberapa lapisan dalam hierarki dependensi. Contoh:

    1. glob 8.0.2 memiliki dependensi langsung pada minimatch 5.0.1.
    2. minimatch 5.0.1 memiliki dependensi langsung brace-expression 2.0.1.
    3. brace-expression 2.0.1 memiliki dependensi langsung pada balanced-match 1.0.2.

Tanpa visibilitas ke dependensi tidak langsung, sangat sulit untuk mengidentifikasi dan menanggapi kerentanan dan masalah lain yang berasal dari komponen yang tidak dirujuk langsung oleh kode Anda.

Saat Anda menginstal paket glob, npm menyelesaikan seluruh hierarki dependensi dan menyimpan daftar versi spesifik yang didownload dalam file package.lock.json sehingga Anda memiliki catatan semua dependensi. Penginstalan berikutnya di lingkungan yang sama akan mengambil versi yang sama.

Alat untuk insight dependensi

Anda dapat menggunakan alat berikut untuk membantu Anda memahami dependensi open source dan mengevaluasi postur keamanan project Anda. Alat ini memberikan informasi di seluruh format paket.

Insight keamanan di konsol Google Cloud
Google Cloud memberikan insight keamanan untuk artefak Anda di Cloud Build, Cloud Run, dan GKE, termasuk kerentanan, informasi dependensi, software bill of materials (SBOM), dan asal-usul build. Layanan Google Cloud lain juga menyediakan fitur yang meningkatkan postur keamanan Anda di seluruh siklus proses pengembangan software. Untuk mempelajari lebih lanjut, lihat ringkasan keamanan supply chain software.
Alat open source

Sejumlah alat open source tersedia, termasuk:

  • Open Source Insights: Situs yang memberikan informasi tentang dependensi langsung dan tidak langsung yang diketahui, kerentanan yang diketahui, dan informasi lisensi untuk software open source. Project Open Source Insights juga menyediakan data ini sebagai Google Cloud Dataset. Anda dapat menggunakan BigQuery untuk menjelajahi dan menganalisis data.

  • Database Kerentanan Open Source: Database kerentanan yang dapat ditelusuri yang menggabungkan kerentanan dari database lain ke dalam satu lokasi.

  • Kartu skor: Alat otomatis yang dapat Anda gunakan untuk mengidentifikasi praktik supply chain software yang berisiko dalam project GitHub Anda. Fitur ini melakukan pemeriksaan terhadap repositori dan memberikan skor 0 hingga 10 untuk setiap pemeriksaan. Kemudian, Anda dapat menggunakan skor tersebut untuk mengevaluasi postur keamanan project Anda.

  • Allstar: Aplikasi GitHub yang terus-menerus memantau organisasi atau repositori GitHub untuk memastikan kepatuhan terhadap kebijakan yang dikonfigurasi. Misalnya, Anda dapat menerapkan kebijakan ke organisasi GitHub Anda yang memeriksa kolaborator di luar organisasi yang memiliki akses administrator atau akses push.

Pendekatan untuk menyertakan dependensi

Ada beberapa metode umum untuk menyertakan dependensi dengan aplikasi Anda:

Menginstal langsung dari sumber publik
Instal dependensi open source langsung dari repositori publik, seperti Docker Hub, npm, PyPI, atau Maven Central. Pendekatan ini praktis karena Anda tidak perlu memelihara dependensi eksternal. Namun, karena Anda tidak mengontrol dependensi eksternal ini, supply chain software Anda lebih rentan terhadap serangan supply chain open source.
Menyimpan salinan dependensi di repositori sumber Anda
Pendekatan ini juga dikenal sebagai vendoring. Daripada menginstal dependensi eksternal dari repositori publik selama build, Anda mendownloadnya dan menyalinnya ke dalam hierarki sumber project. Anda memiliki kontrol yang lebih besar atas dependensi yang Anda gunakan, tetapi ada beberapa kerugiannya:
  • Dependensi vendor meningkatkan ukuran repositori sumber Anda dan memperkenalkan lebih banyak churn.
  • Anda harus menyediakan dependensi yang sama ke setiap aplikasi terpisah. Jika repositori sumber atau proses build Anda tidak mendukung modul sumber yang dapat digunakan kembali, Anda mungkin perlu mempertahankan beberapa salinan dependensi.
  • Mengupgrade dependensi yang di-vendor bisa lebih sulit.
Menyimpan dependensi di registry pribadi

Registry pribadi, seperti Artifact Registry, memberikan kemudahan penginstalan dari repositori publik serta kontrol atas dependensi Anda. Dengan Artifact Registry, Anda dapat:

  • Pusatkan artefak build dan dependensi untuk semua aplikasi Anda.
  • Konfigurasi klien Docker dan paket bahasa Anda untuk berinteraksi dengan repositori pribadi di Artifact Registry dengan cara yang sama seperti yang mereka lakukan dengan repositori publik.
  • Memiliki kontrol yang lebih besar atas dependensi Anda di repositori pribadi:

    • Batasi akses ke setiap repositori dengan Identity and Access Management.
    • Gunakan repositori jarak jauh untuk menyimpan dalam cache dependensi dari sumber publik upstream dan memindainya untuk menemukan kerentanan (pratinjau pribadi).
    • Gunakan repositori virtual untuk mengelompokkan repositori jarak jauh dan pribadi di belakang satu endpoint. Tetapkan prioritas pada setiap repositori untuk mengontrol urutan penelusuran saat mendownload atau menginstal artefak (pratinjau pribadi).
  • Gunakan Artifact Registry dengan layanan Google Cloud lainnya, termasuk Cloud Build, Cloud Run, dan Google Kubernetes Engine. Gunakan pemindaian kerentanan otomatis di seluruh siklus proses pengembangan software, buat asal-usul build, kontrol deployment, dan lihat insight tentang postur keamanan Anda.

Jika memungkinkan, gunakan registry pribadi untuk dependensi Anda. Dalam situasi saat Anda tidak dapat menggunakan registry pribadi, pertimbangkan untuk menyediakan dependensi Anda sehingga Anda memiliki kontrol atas konten di supply chain software Anda.

Versi disematkan

Penyematan versi berarti membatasi dependensi aplikasi ke versi atau rentang versi tertentu. Idealnya, Anda menyematkan satu versi dependensi.

Menyematkan versi dependensi membantu memastikan bahwa build aplikasi Anda dapat direproduksi. Namun, hal ini juga berarti bahwa build Anda tidak menyertakan update pada dependensi, termasuk perbaikan keamanan, perbaikan bug, atau peningkatan.

Anda dapat memitigasi masalah ini menggunakan alat pengelolaan dependensi otomatis yang memantau dependensi di repositori sumber Anda untuk rilis baru. Alat ini memperbarui file persyaratan untuk mengupgrade dependensi sesuai kebutuhan, sering kali menyertakan informasi log perubahan atau detail tambahan.

Penyematan versi hanya berlaku untuk dependensi langsung, bukan dependensi transitif. Misalnya, jika Anda menyematkan versi paket my-library, pin tersebut membatasi versi my-library, tetapi tidak membatasi versi software yang memiliki dependensi my-library. Anda dapat membatasi pohon dependensi untuk paket dalam beberapa bahasa menggunakan file kunci.

Verifikasi tanda tangan dan hash

Ada sejumlah metode yang dapat Anda gunakan untuk memverifikasi keaslian artefak yang Anda gunakan sebagai dependensi.

Verifikasi hash

Hash adalah nilai yang dihasilkan untuk file yang berfungsi sebagai ID unik. Anda dapat membandingkan hash artefak dengan nilai hash yang dihitung oleh penyedia artefak untuk mengonfirmasi integritas file. Verifikasi hash membantu Anda mengidentifikasi penggantian, gangguan, atau kerusakan dependensi, melalui serangan man-in-the-middle atau penyusupan repositori artefak.

Penggunaan verifikasi hash mengharuskan Anda memercayai bahwa hash yang Anda terima dari repositori artefak tidak disusupi.

Verifikasi tanda tangan

Verifikasi tanda tangan menambahkan keamanan tambahan pada proses verifikasi. Repositori artefak, pengelola software, atau keduanya dapat menandatangani artefak.

Layanan seperti sigstore memberikan cara bagi pengelola untuk menandatangani artefak software dan bagi konsumen untuk memverifikasi tanda tangan tersebut.

Otorisasi Biner dapat memverifikasi bahwa image container yang di-deploy ke lingkungan runtime Google Cloud ditandatangani dengan pengesahan untuk berbagai kriteria.

File kunci dan dependensi yang dikompilasi

File kunci adalah file persyaratan yang sepenuhnya diselesaikan, yang menentukan secara persis versi setiap dependensi yang harus diinstal untuk aplikasi. Biasanya dibuat secara otomatis oleh alat penginstalan, file kunci menggabungkan penyematan versi dan verifikasi tanda tangan atau hash dengan pohon dependensi lengkap untuk aplikasi Anda.

Alat penginstalan membuat hierarki dependensi dengan sepenuhnya menyelesaikan semua dependensi transitif hilir dari dependensi tingkat teratas Anda, lalu menyertakan hierarki dependensi dalam file kunci Anda. Akibatnya, hanya dependensi ini yang dapat diinstal, sehingga membuat build lebih dapat direproduksi dan konsisten.

Mencampur dependensi pribadi dan publik

Aplikasi modern berbasis cloud sering kali bergantung pada kode open source dan pihak ketiga, serta library internal closed-source. Artifact Registry memungkinkan Anda membagikan logika bisnis di beberapa aplikasi, dan menggunakan kembali alat yang sama untuk menginstal library eksternal dan internal.

Namun, saat mencampur dependensi pribadi dan publik, rantai pasokan software Anda lebih rentan terhadap serangan kebingungan dependensi. Dengan memublikasikan project dengan nama yang sama dengan project internal Anda ke repositori open source, penyerang mungkin dapat memanfaatkan penginstal yang salah dikonfigurasi untuk menginstal kode berbahaya mereka, bukan dependensi internal Anda.

Untuk menghindari serangan kebingungan dependensi, Anda dapat melakukan sejumlah langkah:

  • Verifikasi tanda tangan atau hash dependensi Anda dengan menyertakannya dalam file kunci.
  • Pisahkan penginstalan dependensi pihak ketiga dan dependensi internal menjadi dua langkah yang berbeda.
  • Secara eksplisit mencerminkan dependensi pihak ketiga yang Anda butuhkan ke dalam repositori pribadi Anda, baik secara manual maupun dengan proxy pull-through. Repositori jarak jauh Artifact Registry adalah proxy pull-through untuk repositori publik upstream.
  • Gunakan repositori virtual untuk menggabungkan repositori Artifact Registry jarak jauh dan standar di belakang satu endpoint. Anda dapat mengonfigurasi prioritas untuk repositori upstream sehingga versi artefak pribadi Anda selalu diprioritaskan daripada artefak publik dengan nama yang sama.
  • Gunakan sumber tepercaya untuk paket publik dan image dasar.

Menghapus dependensi yang tidak digunakan

Seiring perubahan kebutuhan dan perkembangan aplikasi, Anda mungkin mengubah atau berhenti menggunakan beberapa dependensi. Terus menginstal dependensi yang tidak digunakan dengan aplikasi Anda akan meningkatkan jejak dependensi dan meningkatkan risiko Anda disusupi oleh kerentanan dalam dependensi tersebut.

Setelah aplikasi berfungsi secara lokal, praktik umum yang dilakukan adalah menyalin setiap dependensi yang Anda instal selama proses pengembangan ke dalam file persyaratan untuk aplikasi Anda. Kemudian, Anda men-deploy aplikasi dengan semua dependensi tersebut. Pendekatan ini membantu memastikan bahwa aplikasi yang di-deploy berfungsi, tetapi juga cenderung memperkenalkan dependensi yang tidak Anda perlukan dalam produksi.

Berhati-hatilah saat menambahkan dependensi baru ke aplikasi Anda. Setiap dependensi berpotensi memperkenalkan lebih banyak kode yang tidak sepenuhnya dapat Anda kontrol. Sebagai bagian dari pipeline linting dan pengujian reguler, integrasikan alat yang mengaudit file persyaratan untuk menentukan apakah Anda benar-benar menggunakan atau mengimpor dependensi.

Beberapa bahasa memiliki alat untuk membantu Anda mengelola dependensi. Misalnya, Anda dapat menggunakan Plugin Dependensi Maven untuk menganalisis dan mengelola dependensi Java.

Pemindaian kerentanan

Menanggapi kerentanan dalam dependensi Anda dengan cepat akan membantu Anda melindungi supply chain software Anda.

Pemindaian kerentanan memungkinkan Anda menilai secara otomatis dan konsisten apakah dependensi Anda menimbulkan kerentanan pada aplikasi Anda. Alat pemindaian kerentanan menggunakan file kunci untuk menentukan secara persis artefak yang Anda andalkan, dan memberi tahu Anda saat kerentanan baru muncul, terkadang bahkan dengan jalur upgrade yang disarankan.

Misalnya, Artifact Analysis mengidentifikasi kerentanan paket OS dalam image container. Layanan ini dapat memindai image saat diupload ke Artifact Registry dan terus memantaunya untuk menemukan kerentanan baru hingga 30 hari setelah image dikirim.

Anda juga dapat menggunakan Pemindaian Sesuai Permintaan untuk memindai image container secara lokal untuk menemukan kerentanan OS, Go, dan Java. Hal ini memungkinkan Anda mengidentifikasi kerentanan sejak awal sehingga Anda dapat mengatasinya sebelum menyimpannya di Artifact Registry.

Langkah berikutnya