Membangun Docker Image yang Aman: Best Practices untuk Keamanan Container

Lhuqita Fazry
Docker DevOps Container Security CI/CD DevSecOps
Membangun Docker Image yang Aman: Best Practices untuk Keamanan Container

Memilih Base Image yang Minimal dan Terpercaya

Setiap container yang kita bangun dimulai dari base image. Semakin besar dan kompleks base image yang digunakan, semakin luas pula surface area yang bisa dieksploitasi. Oleh karena itu, pemilihan base image adalah keputusan keamanan pertama dan paling fundamental dalam proses build Docker.

Alpine Linux hadir dengan ukuran sekitar 5MB — sangat kecil dibandingkan Ubuntu yang mencapai 200MB. Kelebihan ini menjadikannya pilihan populer untuk image minimal. Namun, Alpine menggunakan musl libc yang terkadang menyebabkan inkompatibilitas dengan beberapa aplikasi Node.js atau Python yang bergantung pada glibc. Distroless images dari Google mengambil pendekatan berbeda: hanya berisi runtime yang diperlukan tanpa shell, package manager, atau utilitas lain. Image seperti gcr.io/distroless/nodejs secara drastis mengurangi CVE karena tidak ada komponen yang bisa dieksploitasi selain aplikasi itu sendiri. Sementara slim variants seperti node:20-slim menghapus paket build yang tidak diperlukan tetapi tetap menyisakan dasar Debian yang cukup stabil.

Kita juga perlu memverifikasi keaslian image sebelum menggunakannya. Gunakan image resmi dari Docker Hub yang sudah terverifikasi oleh publisher official, dan aktifkan Docker Content Trust untuk memastikan setiap image ditandatangani secara digital. Untuk tingkat keamanan yang lebih tinggi, tools seperti cosign memungkinkan kita memverifikasi signature image menggunakan kunci publik yang sudah terdistribusi.

dockerdockerfile
# Perbandingan ukuran dan CVE pada berbagai base image
FROM alpine:3.19            # ~5MB, CVE low
FROM gcr.io/distroless/nodejs  # ~120MB, CVE minimal
FROM node:20-slim           # ~240MB, CVE medium
FROM node:20                # ~1.1GB, CVE tinggi

Dengan memilih base image yang minimal, kita secara langsung mengurangi jumlah CVE potensial. Tools seperti Trivy atau Docker Scout dapat membantu memverifikasi jumlah vulnerability pada setiap base image sebelum kita menggunakannya di production.

Mengoptimalkan Build Context dan Layer Management

Setiap instruksi dalam Dockerfile menciptakan satu layer baru. Layer-layer ini bersifat cacheable, tetapi juga permanen dalam image final. File yang tidak perlu seperti node_modules, .git, atau file .env bisa saja ikut terbawa ke dalam image jika kita tidak hati-hati. Ini bukan hanya masalah ukuran — file konfigurasi yang berisi credential bisa terekspos melalui layer history.

Diagram Docker image layers — lapisan read-only yang membentuk image dan satu writeable layer container di atasnya

Gambar: Ilustrasi Docker image layers dengan base image, lapisan read-only, dan writable container layer — Sumber: [mrbobbytables/diagrams (CC BY 4.0)](https://github.com/mrbobbytables/diagrams)

.dockerignore adalah garis pertahanan pertama. File ini bekerja mirip .gitignore — file dan direktori yang disebutkan di dalamnya tidak akan dikirim ke daemon Docker saat proses build. Build context dikirim secara utuh ke daemon, sehingga file sensitif seperti credential file bisa saja tertinggal di layer jika tidak dikecualikan. Pastikan untuk selalu menyertakan .dockerignore di setiap proyek Docker.

Selain itu, kita bisa menggabungkan perintah RUN dengan operator && untuk mengurangi jumlah layer. Setiap instruksi RUN terpisah menciptakan layer baru. Menggabungkan instalasi paket, pembersihan cache APT, dan penghapusan file sementara dalam satu baris mengurangi jumlah layer dan mengoptimalkan ukuran image.

dockerdockerfile
# .dockerignore
node_modules/
.git/
.env
*.md
secrets/
dist/
coverage/

# Dockerfile dengan optimasi layer dan multi-stage build
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && \
    npm cache clean --force && \
    rm -rf /tmp/*

FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
CMD ["node", "server.js"]

Penggunaan multi-stage build memastikan bahwa tools build seperti compiler dan package manager tidak masuk ke image final. Hanya artifact yang diperlukan yang disalin ke stage terakhir, mengurangi ukuran sekaligus exposure permukaan serang secara signifikan.

Visualisasi dependency graph Docker image layers — menunjukkan hubungan antar layer dalam proses build

Gambar: Dependency graph layer Docker yang merepresentasikan multi-stage build dan hubungan antar stage — Sumber: [mrbobbytables/diagrams (CC BY 4.0)](https://github.com/mrbobbytables/diagrams)

Deep Learning Bootcamp
Machine Learning • Intermediate

Deep Learning Bootcamp

A beginner-friendly, highly interactive bootcamp designed to take you from found...

Daftar

Mengamankan Secret dan Credential dalam Build Process

Salah satu risiko terbesar dalam pembuatan Docker image adalah hardcoded credentials. API key, database password, atau token autentikasi yang ditulis langsung di Dockerfile akan tersimpan permanen di layer history. Bahkan jika secret dihapus di layer berikutnya menggunakan perintah RUN rm, data tersebut masih bisa diakses melalui docker history karena setiap layer menyimpan snapshot file system secara lengkap.

Docker BuildKit menyediakan solusi elegan untuk masalah ini melalui fitur --mount=type=secret. Secret hanya tersedia selama proses build berlangsung dan tidak akan pernah muncul di layer final. Fitur ini sempurna untuk menginstal paket private dari registry npm, mengakses repository Git pribadi, atau mengunduh dependensi yang memerlukan autentikasi.

dockerdockerfile
# Menggunakan BuildKit secret mount untuk credential aman
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./

# Secret hanya tersedia saat build, tidak tersimpan di layer
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci --only=production

FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
CMD ["node", "server.js"]

Jalankan build dengan flag --secret untuk memberikan akses ke file secret:

bashbash
docker build --secret id=npmrc,src=./.npmrc -t myapp:latest .

Perhatikan perbedaan antara ARG, ENV, dan BuildKit --secret. ARG hanya tersedia saat build tetapi nilainya bisa terlihat melalui docker history. ENV menetapkan environment variable yang bertahan di container runtime dan juga muncul di history. BuildKit --secret adalah satu-satunya metode yang benar-benar aman karena secret tidak pernah tertulis di image.

Menerapkan Prinsip Least Privilege pada Container Runtime

Container yang berjalan sebagai root memiliki risiko keamanan yang serius. Jika seorang attacker berhasil menembus container yang berjalan sebagai root melalui celah aplikasi, mereka bisa mendapatkan akses root ke host. Ini disebut container breakout — salah satu skenario terburuk dalam keamanan container.

Ilustrasi cyber security shield — perisai digital yang melambangkan perlindungan keamanan container

Gambar: Konsep keamanan cyber dengan perisai digital dan data streams — Sumber: [StockCake](https://stockcake.com/i/cyber-security-shield_3814301_1761865)

Menambahkan user non-root di Dockerfile sangat mudah dan harus menjadi kebiasaan standar. Gunakan addgroup dan adduser untuk membuat user khusus aplikasi, lalu alihkan konteks eksekusi dengan instruksi USER. Pastikan juga file dan direktori yang diperlukan memiliki kepemilikan yang sesuai menggunakan flag --chown pada instruksi COPY.

dockerdockerfile
FROM node:20-slim

# Buat grup dan user non-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser

CMD ["node", "server.js"]

Selain user non-root, kita harus membatasi kernel capabilities. Docker memberikan sekumpulan capabilities ke container secara default — seperti CHOWN, DAC_OVERRIDE, FOWNER — yang banyak di antaranya tidak diperlukan. Gunakan flag --cap-drop ALL untuk menghapus semua capabilities, lalu tambahkan kembali hanya yang benar-benar diperlukan.

bashbash
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE \
           --read-only \
           --security-opt=no-new-privileges:true \
           myapp:latest

Opsi --read-only membuat root filesystem menjadi read-only, mencegah penulisan file oleh attacker yang berhasil masuk. Sementara --security-opt=no-new-privileges:true mencegah container mendapatkan privilege tambahan melalui executables setuid. Kombinasi teknik ini menciptakan lapisan pertahanan yang kuat untuk runtime container.

Otomatisasi Pemindaian dan Signing Image dalam CI/CD

Keamanan Docker image bukanlah aktivitas satu kali — ini adalah proses berkelanjutan yang harus terintegrasi dalam pipeline CI/CD. Setiap kali kita membangun image baru, kita harus memindai CVE, menandatangani image, dan menegakkan threshold keamanan. Tanpa otomatisasi, celah keamanan bisa lolos ke production tanpa terdeteksi.

Trivy adalah tools pemindaian CVE open-source yang cepat, akurat, dan mendukung berbagai format image. Kita bisa mengintegrasikannya ke dalam GitHub Actions untuk memindai image setiap kali ada push ke repository. Jika ditemukan CVE dengan severity critical atau high, build bisa langsung dihentikan sebelum image masuk ke registry.

yamlyaml
# .github/workflows/security-scan.yml
name: Docker Security Scan
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build Docker Image
        run: docker build -t myapp:latest .

      - name: Run Trivy Scan
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: "myapp:latest"
          severity: "CRITICAL,HIGH"
          exit-code: "1"
          format: "table"

      - name: Sign Image with Cosign
        run: |
          cosign sign --key cosign.key myapp:latest
        env:
          COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}

Setelah pemindaian lolos, kita menandatangani image dengan cosign untuk menjamin integritas dan autentisitas. Image yang ditandatangani bisa diverifikasi oleh siapapun yang mendownloadnya, memastikan bahwa image tersebut benar-benar berasal dari kita dan belum dimodifikasi sejak proses build. Threshold policy yang ketat — misalnya, gagalkan build jika ada satu CVE critical — memaksa tim untuk selalu memperhatikan keamanan sejak awal.

Checklist Keamanan Docker Image dan Langkah Selanjutnya

Sebagai rangkuman, berikut checklist praktik keamanan yang sudah kita bahas:

1. Base image minimal: Pilih Alpine, Distroless, atau slim variants. Verifikasi autentisitas image dengan Docker Content Trust atau cosign. 2. Optimasi layer: Gunakan .dockerignore untuk mengecualikan file sensitif, gabungkan perintah RUN untuk mengurangi layer, dan terapkan multi-stage build. 3. Perlindungan secret: Gunakan BuildKit --mount=type=secret untuk credential. Hindari ARG dan ENV untuk data sensitif. 4. Least privilege: Jalankan container dengan user non-root, drop semua kernel capabilities, aktifkan --read-only dan no-new-privileges. 5. Otomatisasi keamanan: Integrasikan Trivy scan dan cosign signing ke dalam pipeline CI/CD. Terapkan threshold policy yang ketat.

Langkah selanjutnya yang bisa kita eksplorasi adalah SBOM generation menggunakan docker sbom untuk inventory komponen, penerapan registry policy di Docker Hub atau ECR untuk memblokir image yang tidak memenuhi standar keamanan, serta audit berkala untuk memperbarui base image dengan patch terbaru. Topik ini juga berkaitan erat dengan Kubernetes security context yang mengatur keamanan container di tingkat orchestration — seperti securityContext, PodSecurityPolicy, dan Open Policy Agent.

Praktik-praktik di atas adalah fondasi keamanan container yang wajib diterapkan di setiap proyek Docker. Di kursus Docker & DevOps Rumah Coding, kita praktikkan langsung dalam studi kasus deployment nyata bersama praktisi industri. Mulai dari container security sampai CI/CD pipeline hardening — semua dibahas dengan pendekatan hands-on dan best practices terkini.

Kursus Terkait

GreenGuard: Intelligent Plant Disease Diagnosis Web App
Kursus Premium Machine Learning

Deep Learning Bootcamp

A beginner-friendly, highly interactive bootcamp designed to take you from foundational concepts to deploying real-world Artificial Intelligence applications. Through a completely project-based approach, you will master the core of Deep Learning, Artificial Neural Networks, and Computer Vision using Python and TensorFlow, ultimately building a professional-grade AI web application for your portfolio.

Proyek Akhir

GreenGuard: Intelligent Plant Disease Diagnosis Web App

  • Interactive Image Upload UI: A clean, user-friendly interface built with Streamlit that supports drag-and-drop image uploads directly from a computer or mobile phone.
  • Real-Time AI Inference: Utilizes a lightweight, optimized CNN model (like MobileNetV2) to process the image and return a diagnosis in seconds without heavy server load.
  • Confidence Scoring Dashboard: Visually displays the model's prediction probability (e.g., "95% confident this is Tomato Late Blight") using interactive progress bars or charts.
7 Weeks Intermediate
Lihat Detail Kursus
Domain-Specific AI Knowledge Assistant
Kursus Premium Machine Learning

LLM Bootcamp

This project-based bootcamp is designed for beginners to dive practically into the world of Large Language Models (LLMs). Through hands-on building, you will learn how to interact with top-tier AI APIs, master prompt engineering, orchestrate complex workflows using LangChain, and implement Retrieval-Augmented Generation (RAG) to query your own documents. By the end of this course, you will have the skills to build, test, and deploy a fully functional, custom AI web application.

Proyek Akhir

Domain-Specific AI Knowledge Assistant

  • Dynamic Document Processing: A sidebar interface allowing users to upload new PDF or TXT files, which the app automatically chunks, embeds, and stores in the vector database.
  • Context-Aware Chat UI: A modern chat interface built with Streamlit that maintains conversation history, allowing users to ask follow-up questions naturally.
  • Strict Guardrails (Anti-Hallucination): System instructions designed so the AI politely declines to answer questions that fall outside the context of the uploaded documents.
7 Weeks Beginner
Lihat Detail Kursus
End-to-End Student Success Predictor
Kursus Premium Machine Learning

Machine Learning Bootcamp

A beginner-friendly, 7-week project-based bootcamp designed to take you from Python basics to deploying your first Machine Learning model. Through hands-on practice, you will master essential data manipulation, build predictive algorithms, and develop an end-to-end, industry-ready application to kickstart your career in data science.

Proyek Akhir

End-to-End Student Success Predictor

  • Automated Data Pipeline: A preprocessing script that automatically cleans missing values, encodes categorical data (like course type or student background), and scales numerical inputs.
  • Predictive Engine: A tuned machine learning classification model (e.g., Random Forest) specifically optimized for high Recall, ensuring that "at-risk" students are not missed.
  • Interactive Web Dashboard: A user-friendly Streamlit interface featuring a sidebar where instructors can manually input a student's study hours, quiz scores, and login frequency to get an instant pass/fail probability.
7 Weeks Intermediate
Lihat Detail Kursus

Artikel Terkait