
Hari 17: Distroless 8MB vs Alpine 352MB, Sama-Sama 0 CVE
Scan Docker image dengan Trivy — distroless 8MB vs alpine 352MB, keduanya 0 CVE. Tapi attack surface jauh berbeda. Ini kenapa CVE count bukan satu-satunya metric.
Dari Filesystem Scan ke Image Scan
Kemarin kita bikin Docker image SecureBank API sebesar 7.97MB pakai multi-stage build + distroless. Hari ini kita scan image itu pakai Trivy buat cari CVE.
Trivy punya dua mode scanning:
trivy fs— scan filesystem (go.mod, dependencies) → ini yang kita pakai di Fase 1trivy image— scan container image (OS packages + binary dependencies) → ini yang kita pakai hari ini
Perbedaannya penting: trivy fs scan apa yang masuk ke go.mod, trivy image scan apa yang masuk ke container.
Scan Distroless Image: 0 CVE
$ trivy image --severity HIGH,CRITICAL securebank:v1
Target Type Vulnerabilities Secrets
securebank:v1 (debian 12.14) debian 0 -
securebank gobinary 0 -
0 CVE. Nol. Distroless image static-debian12:nonroot bersih dari vulnerability.
Ini bukan kebetulan — Google merawat distroless image dengan baik. Setiap CVE yang ditemukan di base image langsung di-patch dan image di-update.
Scan Naive Image: Juga 0 CVE, Tapi...
Buat perbandingan, kita build image "naif" yang pakai builder stage langsung (alpine + Go toolchain):
$ docker build -t securebank:naive --target builder .
$ trivy image --severity HIGH,CRITICAL securebank:naive
Target Type Vulnerabilities Secrets
securebank:naive (alpine 3.24.1) alpine 0 -
securebank gobinary 0 -
usr/local/go/bin/go gobinary 0 -
... (9 more Go tool binaries)
Juga 0 CVE, karena Alpine 3.24.1 yang sangat baru dan Go 1.26 yang juga baru.
Tapi perhatikan perbedaannya:
| Distroless | Naive (Alpine) | |
|---|---|---|
| CVE | 0 | 0 |
| Image Size | 7.97MB | 352MB |
| Attack Surface | Binary + CA certs | Shell + pkg manager + 11 Go tools |
| Shell | Tidak ada | sh, bash |
| Package Manager | Tidak ada | apk |
| Go Toolchain | Tidak ada | 11 binaries (go, gofmt, asm, cgo, dll) |
CVE count-nya sama, tapi risk-nya jauh berbeda.
Kenapa CVE Count Bukan Satu-Satunya Metric
Kalau cuma lihat CVE count, kedua image ini "sama aman." Tapi di dunia nyata:
Naive image (352MB):
- Attacker masuk → bisa
apk addtool tambahan - Bisa
curlatauwgetdownload payload - Bisa
go buildcompile exploit langsung di container - Bisa baca filesystem, environment variables, secret files
- Semua Go debugging tool tersedia buat reverse engineer binary
Distroless image (7.97MB):
- Attacker masuk → gak bisa apa-apa
- Gak ada shell, gak ada package manager
- Gak ada utilitas apapun
- Hanya binary aplikasi dan CA certs
- Surface area serendah mungkin
Ini analogi sederhana: rumah dengan pintu terbuka vs rumah dengan dinding kosong. CVE count cuma bilang "gak ada celah di dinding." Tapi kalau dindingnya gak ada, gak perlu celah — attacker gak butuh exploit, mereka cuma perlu masuk.
Size Difference 44x
securebank:v1 7.97MB
securebank:naive 352MB
44x lebih kecil. Kenapa ini penting di production?
- Pull time lebih cepat — container startup 44x lebih cepat karena image lebih kecil
- Registry storage lebih hemat — setiap push ke registry hemat 344MB
- Bandwidth lebih hemat — di scale (100 pods, 1000 pods), ini berarti GB per deployment
- Attack surface lebih kecil — lebih sedikit code = lebih sedikit celah
- Compliance lebih mudah — lebih sedikit komponen = lebih mudah audit
Lesson Learned
1. CVE count itu necessary tapi gak sufficient. Dua image dengan 0 CVE bisa punya risk profile yang sangat berbeda. Selalu perhatikan attack surface, bukan cuma vulnerability count.
2. Trivy punya dua mode: fs vs image. trivy fs buat dev-time (scan go.mod), trivy image buat runtime (scan container layers). Keduanya penting — jangan cuma pakai salah satu.
3. Image size = attack surface proxy. 7.97MB berarti cuma binary aplikasi dan CA certs. 352MB berarti ada shell, package manager, dan toolchain. Lebih kecil itu selalu lebih aman.
4. Alpine 3.24.1 itu bersih karena baru. Kalau pakai base image yang lebih lama (Alpine 3.18, Ubuntu 20.04), CVE count bisa 50-100+.Selalu gunakan base image versi terbaru atau distroless.
5. Naive image itu representasi "kalau kita gak pakai multi-stage build." Builder stage dengan Go toolchain itu 352MB dan punya semua tool yang dibutuhkan attacker. Multi-stage build memastikan yang masuk ke production cuma binary final.
Kesimpulan
Hari ini kita buktikan bahwa distroless image memang benar-benar bersih: 0 CVE, 7.97MB, tanpa shell. Naive image juga 0 CVE, tapi 352MB dengan shell dan toolchain lengkap.
CVE count sama, tapi risk-nya jauh berbeda. Distroless = minimal attack surface. Naive = maximal attack surface. Pilihannya jelas.
Besok: Hari 18 — Dockerfile Hardening — tambahkan security options lebih lanjut ke Dockerfile yang sudah ada (USER nonroot sudah ada dari Day 16, tapi masih ada yang bisa ditambahkan).
Diskusi & Komentar
Hari 16: Docker Image 8MB, Distroless Bikin Aman
Next ArticleHari 18: Docker Hardening, 8 Lapis Pertahanan Container
Artikel Terkait
Hari 5: Trivy SCA Scan Nemukan 4 CVE di Golang API
Hari kelima 60 hari DevSecOps! Scan dependensi Go pakai Trivy dan nemukan 4 CVE termasuk 1 CRITICAL — termasuk library deprecated jwt-go.
Hari 8: Semgrep SAST Scan Temukan Kode Tidak Aman
Hari kedelapan 60 hari DevSecOps! Install Semgrep, buat kode insecure (MD5), dan scan ketemu 2 finding — MD5 weak hash dan HTTP server tanpa TLS.
Hari 10: MD5 ke Bcrypt, Pipeline Hijau Lagi
Hari kesepuluh 60 hari DevSecOps! Fix SAST findings — ganti MD5 ke bcrypt, hapus custom rule HTTP TLS, dan pipeline CI kembali hijau setelah 4 job semua pass.