Image container adalah unit deploy kalian dan setiap kerentanannya ikut ke mana-mana; di episode ini kalian membangun image minimal non-root dengan multi-stage build, scan Trivy/Grype sebagai gate CI, dan menyiapkan fondasi supply chain dengan SBOM serta signing yang dibahas tuntas di episode 12-13

Di episode 5 kita mengamankan secret. Sekarang perhatikan objek yang membawa semua itu — kode, library, konfigurasi — ke production: image container. Image adalah artefak yang paling lama hidup di sistem kalian; base image yang dipilih hari ini akan membawa ratusan package OS dan CVE-nya ke setiap environment selama berbulan-bulan.
Mengapa episode ini penting sekarang? Karena keputusan keamanan terbesar pada container justru diambil saat build, bukan saat runtime. Setelah image ter-push dan ter-deploy, memperbaikinya berarti rebuild + redeploy seluruh armada. Shift-left dalam konteks container artinya: desain Dockerfile yang aman sejak baris pertama, lalu verifikasi otomatis di pipeline.
Setiap layer base image adalah permukaan serangan. Perbandingan praktis:
| Base | Ukuran | Package OS | Kapan Dipakai |
|---|---|---|---|
ubuntu:24.04 | ~78 MB | Ratusan | Butuh toolchain OS lengkap |
alpine | ~8 MB | Minimal | Binary statis; hati-hati musl libc |
gcr.io/distroless/nodejs22 | ~130 MB | Hampir nol | Runtime Node tanpa shell |
scratch | 0 MB | Nol | Binary Go/Rust yang fully static |
Aturan praktisnya: semakin sedikit yang ada di image, semakin sedikit yang harus di-patch. Distroless tidak punya shell maupun package manager — attacker yang berhasil eksekusi kode tidak bisa spawn sh, download tool, atau enumerasi sistem dengan mudah. Ini disebut shrinking the attack surface, dan efeknya nyata terhadap banyak kelas exploit post-exploitation.
Perhatikan pola buruk yang masih umum ditemukan:
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["node", "server.js"]Empat masalah: base penuh toolchain, COPY . . membawa .env dan .git, npm install bukan deterministik, dan proses jalan sebagai root. Bandingkan versi yang di-hardening:
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
FROM gcr.io/distroless/nodejs22 AS runtime
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --chown=nonroot:nonroot src ./src
USER nonroot
CMD ["server.js"]Poin-poin penting dari versi kedua:
deps memakai alpine untuk npm ci; stage final distroless hanya membawa hasilnya — compiler dan shell tidak ikut ke production.npm ci membaca lockfile → build reproducible (dan SCA di episode 4 akurat).USER nonroot — jika aplikasi dicompromise, attacker mendapat user tanpa privilege, bukan root.COPY . . — hanya direktori yang benar-benar dibutuhkan.Tambahkan juga flag runtime defensif saat menjalankan:
docker run --rm --read-only \
--cap-drop=ALL \
--security-opt no-new-privileges \
-p 3000:3000 myapp:latestDua scanner open source dominan: Trivy (Aquasecurity) dan Grype (Anchore). Keduanya memindai layer image terhadap database CVE. Trivy unggul karena satu binary untuk banyak target (image, fs, IaC, K8s); Grype kuat untuk workflow SBOM-first. Pola gate di CI:
jobs:
image-scan:
needs: build
runs-on: ubuntu-latest
steps:
- name: Scan image hasil build
run: |
trivy image \
--exit-code 1 \
--ignore-unfixed \
--severity HIGH,CRITICAL \
myapp:${{ github.sha }}Tiga flag yang membuat gate ini realistis:
--ignore-unfixed — CVE tanpa patch tersedia tidak menggagalkan build (tidak ada aksi yang bisa dilakukan developer); tetap terlaporkan.--severity HIGH,CRITICAL — medium ke bawah masuk report, bukan blocker.github.sha) — scan persis artefak yang akan di-push, bukan latest yang isinya bisa berbeda.Tip
Scan dua kali: di CI sebelum push (gate) dan terjadwal harian/mingguan terhadap image yang sudah ada di registry (detective). CVE baru dirilis setiap hari — image yang bersih minggu lalu belum tentu bersih hari ini. Topik ini diperdalam di episode 10 tentang vulnerability management.
Dua fitur yang baru akan dibahas tuntas di episode 12-13, tetapi mulai sekarang biasakan:
trivy image --format cyclonedx --output sbom.json myapp:1.0.0
cosign sign myapp:1.0.0SBOM (Software Bill of Materials) adalah daftar isi resmi image — berguna saat CVE baru keluar untuk mencari "apakah kita memakai X?". Signing (cosign) memberi jaminan integritas: siapa pun yang menarik image bisa memverifikasi bahwa ia benar-benar dibangun oleh pipeline kalian, bukan image palsu di registry.
:latest di production — tag bergerak membuat rollback dan audit mustahil; pin by digest (@sha256:...) untuk deployment.RUN --mount=type=secret).Inti yang harus dibawa pulang:
Di episode 7 selanjutnya kita turun ke infrastruktur: IaC Security & Policy-as-Code — bagaimana bucket publik dan security group terbuka dicegah sebelum terraform apply, memakai scanner IaC dan aturan Rego/OPA yang bisa kalian tulis sendiri. Sampai jumpa!