Hari 17: Distroless 8MB vs Alpine 352MB, Sama-Sama 0 CVE
4 min read

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.

devsecops
docker
trivy
container-scanning
distroless
60-days-challenge
Share

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 1
  • trivy 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 add tool tambahan
  • Bisa curl atau wget download payload
  • Bisa go build compile 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?

  1. Pull time lebih cepat — container startup 44x lebih cepat karena image lebih kecil
  2. Registry storage lebih hemat — setiap push ke registry hemat 344MB
  3. Bandwidth lebih hemat — di scale (100 pods, 1000 pods), ini berarti GB per deployment
  4. Attack surface lebih kecil — lebih sedikit code = lebih sedikit celah
  5. 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).

Repo: github.com/stayrelevantid/chalange-devsecops

Enjoyed this article? Share it!

Share

Diskusi & Komentar

Artikel Terkait