Supply Chain Security #

Keamanan teknologi cloud-native tidak lagi terbatas pada pembatasan hak akses runtime (seperti RBAC dan Pod Security Standards) atau segmentasi jaringan melalui NetworkPolicy. Salah satu vektor serangan yang paling berbahaya dan terus berkembang adalah eksploitasi rantai pasok perangkat lunak (software supply chain). Dalam ekosistem Kubernetes, unit terkecil dari deployment adalah Pod yang membungkus container image. Jika container image yang kita deploy sudah disusupi malware, mengandung celah keamanan kritis (vulnerability), atau digantikan oleh penyerang di level registry, maka seluruh mekanisme pertahanan runtime di dalam kluster akan menjadi tidak berguna. Oleh karena itu, kita harus memastikan bahwa setiap image yang berjalan di kluster Kubernetes dapat diverifikasi keasliannya, bebas dari kerentanan berbahaya, dan berasal dari jalur pipa build (build pipeline) yang tepercaya.


Ancaman Rantai Pasok Container #

Sebelum merancang sistem pertahanan yang kokoh, kita harus memahami terlebih dahulu bagaimana rantai pasok container dapat disusupi. Vektor serangan ini sangat bervariasi, mulai dari tahap penulisan kode di komputer lokal developer, proses integrasi di server CI/CD, hingga penyimpanan image di container registry.

Vektor Serangan Utama #

Vektor Serangan Supply Chain pada Container:

1. Base Image yang Rentan atau Jahat (Malicious Base Image)
   - Menggunakan base image usang yang mengandung CVE (Common Vulnerabilities and Exposures) kritis.
   - Menggunakan image publik yang sengaja ditanami backdoor atau cryptocurrency miner oleh penyerang.

2. Kerentanan Dependensi Pihak Ketiga (Dependency Confusion & Typosquatting)
   - Menyisipkan dependensi jahat melalui repositori paket publik (npm, PyPI, Maven, dll.) dengan kemiripan nama.
   - Pipa CI/CD secara tidak sengaja menarik dependensi jahat saat proses kompilasi kode aplikasi.

3. Kompromi Jalur Pipa CI/CD (Compromised CI/CD Pipeline)
   - Penyerang meretas server CI/CD (misalnya, Jenkins, GitHub Actions runner) dan memodifikasi instruksi build.
   - Menyuntikkan malware ke dalam binary aplikasi sesaat sebelum image dibungkus dan di-push.

4. Manipulasi Tag Image di Registry (Image Spoofing/Overwriting)
   - Tanpa mekanisme immutability, penyerang yang memiliki akses ke registry dapat menimpa tag 'latest' atau 'v1.0.0' dengan image berbahaya.
   - Kluster menarik (pull) image baru yang telah dimodifikasi tanpa menyadari adanya perubahan konten.

5. Kebocoran Kredensial Registry (Credential Leakage)
   - Token akses atau password registry tersimpan secara tidak aman (hardcoded) di Git repositori atau konfigurasi CI/CD.
   - Penyerang menggunakan kredensial tersebut untuk mengunggah image berbahaya langsung ke registry privat kita.

Untuk mengamankan alur ini, kita membutuhkan strategi pertahanan berlapis (defense-in-depth) yang mencakup pemindaian kerentanan secara berkelanjutan, penandatanganan kriptografis terhadap artefak build, pembuatan daftar bahan perangkat lunak secara transparan, serta kebijakan penegakan hukum (policy enforcement) yang ketat sebelum image diizinkan berjalan di dalam kluster Kubernetes.


Arsitektur Keamanan Supply Chain #

Untuk mengamankan rantai pasok kontainer dari hulu ke hilir, kita perlu mengintegrasikan berbagai alat pengamanan ke dalam satu siklus hidup terpadu. Diagram alir berikut menunjukkan bagaimana kode yang dikomit oleh developer diverifikasi, dipindai, ditandatangani, dan divalidasi oleh mesin kebijakan (policy engine) di dalam Kubernetes.

flowchart TD
    Developer["Developer Commit Code"] -->|"Git Push"| GitRepo["Git Repository (GitHub/GitLab)"]
    GitRepo -->|"Webhook Trigger"| CIPipeline["CI/CD Pipeline (GitHub Actions/GitLab CI)"]
    
    subgraph BuildScanSign["Proses Build & Hardening (CI Node)"]
        direction TB
        BuildImage["Build Container Image (Multi-stage)"] --> ScanTrivy["Scan Vulnerabilities (Trivy)"]
        ScanTrivy -->|"Lolos Policy (No Critical CVE)"| SignCosign["Sign Image & Generate Attestation (Cosign)"]
        SignCosign --> GenerateSBOM["Generate SBOM (Syft)"]
    end
    
    CIPipeline --> BuildImage
    GenerateSBOM -->|"Push Image, Signature, & SBOM"| Registry["Secure Private Registry (Harbor/ECR)"]
    
    subgraph K8sAdmission["Kubernetes Cluster Admission Control"]
        direction TB
        DeployReq["kubectl apply / GitOps Sync"] --> K8sAPI["Kube-API Server"]
        K8sAPI -->|"Validating Webhook Request"| Kyverno["Kyverno Policy Engine"]
        Kyverno -->|"Verify Cosign Signature & Registry Policy"| PolicyResult{"Memenuhi Policy?"}
        PolicyResult -- "Ya" --> PullImage["Izinkan & Pull Image ke Kubelet"]
        PolicyResult -- "Tidak" --> RejectDeploy["Tolak Deployment (Blocked)"]
    end
    
    Registry --> PullImage
    K8sAPI -.-> DeployReq

Pemindaian Kerentanan dengan Trivy #

Langkah pertama dalam mengamankan rantai pasok adalah memastikan bahwa tidak ada celah keamanan yang dikenal (known vulnerabilities) di dalam container image kita. Trivy adalah alat pemindai kerentanan (vulnerability scanner) yang cepat, andal, dan mudah diintegrasikan ke dalam pipa CI/CD.

Trivy memindai sistem operasi kontainer (seperti Debian, Alpine, RedHat) dan paket dependensi aplikasi (seperti npm, pip, bundler, go.mod) untuk mencocokkannya dengan basis data kerentanan global (CVE).

Integrasi CI/CD Pipeline #

Kita tidak boleh membiarkan proses pemindaian ini bersifat manual. Pemindaian harus berjalan secara otomatis pada setiap proses build di dalam pipa CI/CD. Jika Trivy mendeteksi kerentanan dengan tingkat keparahan (severity) tinggi (HIGH) atau kritis (CRITICAL), pipa build harus digagalkan (fail-fast) secara otomatis.

Berikut adalah perbandingan antara konfigurasi Dockerfile yang tidak aman (menyebabkan banyak kerentanan) dengan pendekatan Dockerfile multi-stage yang bersih dan aman, diikuti oleh konfigurasi otomatis pemindaian Trivy di GitHub Actions.

# ANTI-PATTERN: Dockerfile menggunakan base image yang gemuk, menjalankan proses sebagai root,
# dan tidak membersihkan package manager cache, sehingga meningkatkan attack surface dan jumlah CVE.
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y python3 python3-pip curl
WORKDIR /app
COPY . /app
RUN pip3 install -r requirements.txt
# Menjalankan aplikasi sebagai user root secara default
CMD ["python3", "main.py"]

# ==============================================================================
# BENAR: Menerapkan multi-stage build untuk mengeliminasi compiler tools,
# menggunakan minimal base image (distroless), dan menjalankan proses sebagai non-root.
# Stage 1: Build & Dependensi
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

# Stage 2: Runtime Image (Distroless)
FROM gcr.io/distroless/python3-debian12:nonroot
WORKDIR /app
# Salin dependensi dari stage builder
COPY --from=builder /root/.local /home/nonroot/.local
COPY . /app
ENV PATH=/home/nonroot/.local/bin:$PATH
# Image distroless secara otomatis menjalankan proses sebagai user nonroot (ID 65532)
CMD ["main.py"]

Setelah Dockerfile dioptimalkan, kita menerapkan langkah pemindaian otomatis di dalam pipa CI/CD menggunakan konfigurasi berikut:

# Contoh implementasi workflow GitHub Actions untuk scanning dengan Trivy
name: Security Scan and Build
on:
  push:
    branches: [ "main" ]

jobs:
  build-and-scan:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Build Local Image
        run: |
          docker build -t my-app:${{ github.sha }} .          

      - name: Run Trivy Scan (Fails on CRITICAL vulnerabilities)
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: 'my-app:${{ github.sha }}'
          format: 'table'
          exit-code: '1' # Pipa build akan gagal jika kriteria terpenuhi
          ignore-unfixed: true # Fokus hanya pada CVE yang sudah memiliki patch resmi
          vuln-type: 'os,library'
          severity: 'CRITICAL,HIGH'

Dengan mengonfigurasi parameter --exit-code 1 pada Trivy, kita memaksa proses build untuk berhenti jika ditemukan kerentanan berisiko tinggi yang memiliki perbaikan (fixed version). Hal ini mencegah tim developer mendorong image yang rentan ke repositori pusat.


Verifikasi Identitas Image dengan Cosign #

Memiliki image yang bebas dari kerentanan tidak menjamin keamanan jika kita tidak bisa membuktikan bahwa image yang ditarik oleh kluster Kubernetes adalah benar-benar image yang sama yang lolos dari pipa CI/CD tepercaya kita. Di sinilah teknologi penandatanganan kriptografis (cryptographic signing) diperlukan.

Cosign (bagian dari proyek Sigstore di bawah Linux Foundation) menyederhanakan proses penandatanganan kontainer. Cosign menulis tanda tangan digital langsung ke dalam container registry sebagai objek OCI (OCI artifact) yang berdampingan dengan kontainer asli.

Metode Statis Menggunakan Keypair #

Metode konvensional menggunakan sepasang kunci kriptografi (kunci publik dan kunci privat) yang dibuat secara lokal atau disimpan di dalam Key Management Service (KMS) seperti AWS KMS, GCP KMS, atau HashiCorp Vault.

# 1. Generate keypair untuk penandatanganan di mesin lokal/admin
# Perintah ini akan menghasilkan dua file: cosign.key (private) dan cosign.pub (public)
# Kita akan diminta memasukkan passphrase untuk mengamankan private key.
cosign generate-key-pair

# 2. Tandatangani container image di dalam pipeline build
# Kita harus menyediakan private key (cosign.key) dan password-nya melalui environment variable.
export COSIGN_PASSWORD="super-secret-passphrase"
cosign sign --key cosign.key registry.company.com/apps/secure-api:v1.0.0

# 3. Verifikasi tanda tangan secara manual sebelum deployment
# Kluster atau operator dapat memverifikasi keabsahan image menggunakan kunci publik (cosign.pub).
cosign verify --key cosign.pub registry.company.com/apps/secure-api:v1.0.0

Metode Keyless Signing (Direkomendasikan) #

Dalam lingkungan modern, mengelola kunci privat statis di dalam pipeline CI/CD memunculkan risiko baru: jika pipa CI/CD bocor, kunci privat tersebut dapat dicuri oleh penyerang untuk menandatangani image jahat.

Untuk mengatasi ini, Cosign memperkenalkan mekanisme Keyless Signing. Mekanisme ini memanfaatkan integrasi OpenID Connect (OIDC) antara penyedia identitas pipa CI/CD (seperti GitHub Actions) dengan infrastruktur Sigstore (Fulcio sebagai Certificate Authority dan Rekor sebagai Transparency Log).

flowchart LR
    CI["CI Runner (GitHub Actions)"] -->|"1. Request OIDC Token"| GitHub["GitHub OIDC Provider"]
    GitHub -->|"2. JWT Token"| CI
    CI -->|"3. Kirim JWT & Public Key sementara"| Fulcio["Fulcio CA (Sigstore)"]
    Fulcio -->|"4. Verifikasi JWT & Terbitkan Sertifikat X.509"| CI
    CI -->|"5. Tandatangani Image & Kirim ke Registry"| Registry["Container Registry"]
    CI -->|"6. Catat Transaksi Tanda Tangan"| Rekor["Rekor Transparency Log"]

Ketika proses signing menggunakan metode keyless berjalan:

  1. Pipa build meminta token OIDC berumur pendek (JWT) dari penyedia platform (misalnya GitHub).
  2. Cosign mengirimkan token ini ke Fulcio (CA milik Sigstore).
  3. Fulcio memverifikasi identitas pipa build tersebut dan menerbitkan sertifikat X.509 berumur sangat pendek (hanya berlaku 10 menit) yang diikat dengan identitas pipa build (misalnya URL workflow GitHub Actions).
  4. Cosign menandatangani image menggunakan kunci privat sekali pakai (ephemeral key) yang dicocokkan dengan sertifikat dari Fulcio.
  5. Detail penandatanganan dicatat di Rekor, sebuah log transaksi publik yang bersifat append-only (tidak dapat diubah) guna mencegah penyangkalan (non-repudiation).
  6. Kunci privat sekali pakai langsung dihancurkan. Tidak ada kunci privat statis yang perlu disimpan atau dikelola di dalam pipa CI/CD kita.

Pembuatan dan Pengelolaan SBOM (Software Bill of Materials) #

Untuk melakukan analisis dampak saat terjadi kerentanan baru (misalnya insiden zero-day seperti Log4Shell), kita harus memiliki visibilitas penuh terhadap semua pustaka (libraries) dan dependensi transitif yang terpasang di dalam container image. Daftar inventaris ini disebut dengan Software Bill of Materials (SBOM).

Kita dapat menggunakan Syft (alat pembuat SBOM dari Anchore) atau Trivy untuk menghasilkan file SBOM dengan format standar industri seperti CycloneDX atau SPDX, kemudian mengunggahnya ke registry sebagai bagian dari pengesahan kontainer (attestation).

Siklus Hidup Pembuatan dan Pengunggahan SBOM #

# 1. Analisis kontainer dan hasilkan SBOM dalam format CycloneDX JSON menggunakan Syft
syft registry.company.com/apps/secure-api:v1.0.0 -o cyclonedx-json > sbom.json

# 2. Verifikasi konten SBOM yang dihasilkan secara lokal
# Memastikan library tertentu (misalnya, openssl) ada dalam daftar inventaris
grep -i "openssl" sbom.json

# 3. Unggah SBOM ke Container Registry sebagai Attestation menggunakan Cosign
# Attestation mengikat dokumen SBOM secara kriptografis ke SHA256 digest dari image tersebut.
cosign attest --key cosign.key \
  --type cyclonedx \
  --predicate sbom.json \
  registry.company.com/apps/secure-api:v1.0.0

# 4. Verifikasi attestation di sisi registry
cosign verify-attestation --key cosign.pub \
  --type cyclonedx \
  registry.company.com/apps/secure-api:v1.0.0

Dengan melampirkan SBOM langsung ke kontainer di registry, tim keamanan dapat memindai status kerentanan seluruh aplikasi secara terpusat tanpa harus membangun ulang atau membongkar container image satu per satu di masa mendatang.


Penegakan Kebijakan di Cluster dengan Kyverno #

Membuat tanda tangan kriptografis dan pemindaian kerentanan di pipa CI/CD tidak akan efektif jika kita tidak memblokir deployment yang tidak memenuhi syarat di tingkat kluster Kubernetes. Kita harus mengonfigurasi pintu gerbang di Kubernetes API Server menggunakan admission webhook.

Kyverno adalah mesin kebijakan (policy engine) yang dirancang khusus untuk Kubernetes. Kyverno memungkinkan kita memvalidasi, memutasikan, dan membuat resource Kubernetes menggunakan manifest deklaratif, tanpa perlu menulis kode Go seperti pada Open Policy Agent (OPA) Gatekeeper.

Skenario Alur Kerja Kyverno Admission Controller #

flowchart TD
    Client["kubectl apply / GitOps Sync"] --> APIServer["Kubernetes API Server"]
    
    APIServer -->|"(1) Mutating Webhook: Inject Kredensial Registry / Label"| Kyverno["Kyverno Policy Engine<br/>- Memeriksa registry asal image<br/>- Mengunduh public key dari etcd/secret<br/>- Memverifikasi signature Cosign"]
    APIServer -->|"(2) Validating Webhook: Kirim Payload Pod ke Kyverno"| Kyverno
    
    Kyverno --> Lolos["LOLOS POLICY<br>Izinkan deployment"]
    Kyverno --> TidakLolos["TIDAK LOLOS<br>Tolak deployment dengan pesan error"]

Manifest Kebijakan Kyverno: Validasi Registry Tepercaya #

Kebijakan berikut memastikan bahwa kluster hanya akan menerima container image yang berasal dari registri internal perusahaan, dan secara otomatis menolak image dari registri publik yang tidak dikenal guna mencegah eksekusi kode bayangan (shadow deployments).

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-image-registries
  annotations:
    policies.kyverno.io/title: "Membatasi Registri Container Image"
    policies.kyverno.io/category: "Rantai Pasok Keamanan"
    policies.kyverno.io/severity: "High"
    policies.kyverno.io/description: "Memastikan semua pod hanya menarik image dari domain registri resmi milik organisasi."
spec:
  validationFailureAction: Enforce # Enforce: tolak deployment, Audit: izinkan tapi catat pelanggaran
  background: true
  rules:
  - name: check-trusted-registries
    match:
      any:
      - resources:
          kinds:
          - Pod
    validate:
      message: "Deployment ditolak! Image '{{request.object.spec.containers[*].image}}' harus menggunakan registri resmi perusahaan di 'registry.company.com/'."
      pattern:
        spec:
          containers:
          # Pola validasi untuk memastikan semua container menggunakan prefix registri perusahaan
          - image: "registry.company.com/*"
          # Kita juga memvalidasi initContainers jika didefinisikan di dalam spesifikasi pod
          # dengan menggunakan rule rekursif atau deklarasi eksplisit.

Manifest Kebijakan Kyverno: Verifikasi Signature Cosign #

Kebijakan ini memastikan bahwa setiap container image yang masuk harus memiliki tanda tangan digital yang sah yang dicocokkan dengan kunci publik organisasi. Jika image tidak ditandatangani atau ditandatangani dengan kunci yang salah, Kyverno akan memblokir Pod agar tidak dijalankan.

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: enforce-image-signatures
  annotations:
    policies.kyverno.io/title: "Verifikasi Tanda Tangan Image Cosign"
    policies.kyverno.io/category: "Rantai Pasok Keamanan"
    policies.kyverno.io/severity: "Critical"
spec:
  validationFailureAction: Enforce
  background: false # Evaluasi secara real-time saat admission request masuk
  rules:
  - name: verify-cosign-signature
    match:
      any:
      - resources:
          kinds:
          - Pod
    verifyImages:
    - imageReferences:
      - "registry.company.com/apps/*"
      attestors:
      - count: 1
        entries:
        - keys:
            publicKeys: |-
              -----BEGIN PUBLIC KEY-----
              MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9l/S02C3m4J2bA1w8s9dY1wZ
              U8uJ2K9kXj9W6+o/5g43209FASDF09asfFASKL12309ASDFK12309ASDFK12
              3u3X+N9w5xP8C5p5C0B7wY==
              -----END PUBLIC KEY-----              

Dengan menerapkan kebijakan ini di tingkat kluster, kita menutup celah bagi siapa pun (termasuk tim internal dengan akses administrator kluster) untuk menjalankan image mentah dari luar pipa CI/CD yang terverifikasi.


Hardening Container Registry & Pull Secrets #

Container registry adalah jantung dari distribusi software di Kubernetes. Kita harus memperlakukan registry sebagai sistem kritikal yang memerlukan pengerasan keamanan (hardening).

Immutability Tags #

Salah satu kesalahan paling umum adalah mengizinkan penulisan ulang tag image (tag mutability). Sebagai contoh, jika kita mengizinkan tag v1.0.0 diperbarui dengan image baru, kita kehilangan jaminan konsistensi.

Pola Mutabilitas Tag vs Immutabilitas:

[MUTABLE TAGS - RISIKO TINGGI]
Developer Build #1 ──> Push app:v1.0.0 (SHA: aaa) ──> Kubernetes Pull (Run SHA: aaa)
Developer Build #2 ──> Push app:v1.0.0 (SHA: bbb) ──> Kubernetes Pull (Run SHA: bbb)
✗ Kluster menjalankan dua versi kode berbeda dengan label tag yang sama.
✗ Audit logging menjadi kacau karena tag tidak merepresentasikan kode unik.

[IMMUTABLE TAGS - AMAN]
Developer Build #1 ──> Push app:v1.0.0 (SHA: aaa) ──> Sukses
Developer Build #2 ──> Push app:v1.0.0 (SHA: bbb) ──> TOLAK OLEH REGISTRY (Tag sudah ada)
✓ Kita dipaksa menaikkan versi (misal, app:v1.0.1) untuk setiap perubahan.
✓ Setiap deployment di kluster bersifat deterministik dan dapat di-rollback dengan aman.

Kita wajib mengaktifkan opsi Immutable Tags pada container registry yang kita gunakan (seperti Harbor, AWS ECR, GCP Artifact Registry, atau Azure ACR).

Autentikasi Menggunakan Image Pull Secret #

Menjalankan registri privat berarti kluster Kubernetes memerlukan kredensial untuk menarik (pull) image. Kita harus menghindari penggunaan kredensial global dengan hak akses tulis (write). Gunakan akun khusus dengan hak akses baca saja (read-only).

Berikut adalah contoh perbandingan penanganan kredensial penarikan image:

# ANTI-PATTERN: Membuat Secret docker-registry secara manual di setiap namespace secara acak,
# atau menempelkan kredensial langsung ke manifest deployment. Ini menyulitkan rotasi kredensial.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: insecure-app
  namespace: development
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: web
        image: registry.company.com/apps/web:v1.0.0
      # Tidak ada penanganan rahasia secara otomatis, developer terbiasa copy-paste secret
      imagePullSecrets:
      - name: manual-registry-secret

# ==============================================================================
# BENAR: Mengikat Kredensial Registry ke ServiceAccount Default Namespace.
# Setiap Pod yang berjalan dengan ServiceAccount ini otomatis mewarisi hak akses penarikan image.
apiVersion: v1
kind: ServiceAccount
metadata:
  name: secure-service-account
  namespace: production
# Mengikat pull secret di level ServiceAccount
imagePullSecrets:
- name: global-read-only-registry-secret
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      serviceAccountName: secure-service-account # Menggunakan ServiceAccount tepercaya
      containers:
      - name: web
        image: registry.company.com/apps/web:v1.0.0
        resources:
          limits:
            cpu: "500m"
            memory: "512Mi"
          requests:
            cpu: "200m"
            memory: "256Mi"

Dengan mengintegrasikan pull secret ke dalam ServiceAccount, tim developer tidak perlu lagi menuliskan blok imagePullSecrets di setiap file deployment aplikasi mereka. Hal ini mengurangi kesalahan konfigurasi manusia (human error) dan menyederhanakan manajemen siklus hidup token registry.


Meminimalkan Attack Surface dengan Distroless dan Multi-Stage #

Setiap baris kode dan peralatan (utilities) yang ada di dalam container image tetapi tidak digunakan oleh aplikasi saat runtime merupakan beban keamanan tambahan. Alat-alat seperti curl, wget, apt, npm, atau shell sh/bash di dalam image runtime adalah senjata bagi penyerang untuk melakukan eksploitasi lateral jika aplikasi kita berhasil ditembus.

Perbandingan Karakteristik Base Image #

Karakteristik Ubuntu / Debian Alpine Linux Google Distroless
Ukuran Image Besar (70MB - 200MB) Sangat Kecil (~5MB) Sangat Kecil (15MB - 50MB)
Package Manager Ada (apt, dpkg) Ada (apk) Tidak Ada
Shell System Ada (bash, sh) Ada (sh, ash) Tidak Ada
Kompatibilitas glibc Penuh (Asli) Terbatas (Menggunakan musl) Penuh (Debian-based glibc)
Jumlah CVE Default Tinggi Sangat Rendah Mendekati Nol
Skenario Penggunaan Tahap Build / Kompilasi Aplikasi Go / Rust Statis Aplikasi Node.js, Python, Java Runtime

Mengapa Distroless Lebih Aman? #

Kontainer Distroless hanya berisi aplikasi kita dan dependensi runtime minimalnya. Di dalam image distroless tidak terdapat sistem operasi penuh, package manager, shell, atau utilities standar Linux lainnya.

Jika penyerang menemukan kerentanan Remote Code Execution (RCE) pada aplikasi Python kita yang berjalan di atas kontainer distroless:

  • Penyerang tidak dapat menjalankan shell command karena /bin/sh or /bin/bash tidak ada.
  • Penyerang tidak dapat mengunduh skrip backdoor menggunakan curl atau wget karena alat tersebut tidak terpasang.
  • Penyerang tidak dapat memasang alat penetrasi baru karena tidak ada apt atau pip.

Hal ini membatasi ruang gerak eksploitasi pasca-penetrasi (post-exploitation) secara signifikan di tingkat kernel kontainer.


Anti-Pattern Keamanan Supply Chain #

Mari kita telusuri beberapa kesalahan umum (anti-pattern) yang sering dilakukan oleh tim DevOps dalam mengelola rantai pasok container dan bagaimana solusi yang tepat untuk mengatasinya.

1. Menggunakan Tag :latest di Lingkungan Produksi #

# ANTI-PATTERN: Menarik base image menggunakan tag dinamis 'latest'.
# Setiap kali pipeline berjalan, base image bisa berubah secara tidak terduga.
FROM node:latest
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "app.js"]

# ==============================================================================
# BENAR: Mengunci versi base image menggunakan tag spesifik yang presisi
# dan mengidentifikasi SHA256 digest untuk menjamin determinisme absolut.
FROM node:20.11.0-alpine3.19@sha256:7bc5be6704044...
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
CMD ["node", "app.js"]

2. Mengabaikan Verifikasi Signature di Lingkungan Kluster #

Banyak tim menandatangani image di pipa CI/CD tetapi tidak mengaktifkan admission controller untuk memverifikasi tanda tangan tersebut di Kubernetes. Akibatnya, perlindungan hanya bersifat administratif di luar kluster, sementara kluster tetap rentan terhadap eksekusi image asing secara langsung.

3. Menjalankan Scanning Hanya Sekali Saat Build Time #

Kerentanan baru (zero-day) ditemukan setiap hari. Container image yang dinyatakan bersih dari CVE saat di-build dua bulan lalu mungkin kini mengandung kerentanan berisiko kritis. Kita harus melakukan pemindaian terjadwal (scheduled scan) terhadap image yang sedang berjalan di dalam kluster, menggunakan alat seperti Trivy Operator yang secara aktif memperbarui status keamanan seluruh Pod yang berjalan.


Checklist Keamanan Supply Chain #

Sebelum melangkah ke tahap produksi, pastikan seluruh item di dalam daftar periksa berikut telah diimplementasikan dan diverifikasi keaslian fungsinya:

TAHAP BUILD (CI/CD PIPELINE):
  □ Dockerfile menggunakan pendekatan multi-stage build untuk memisahkan build tools.
  □ Base image menggunakan versi minimal (Distroless atau Alpine) dengan tag spesifik (SHA256 digest).
  □ Mengaktifkan pemindaian otomatis Trivy di setiap commit/pull request.
  □ Mengonfigurasi pipa CI/CD agar gagal (exit code 1) jika mendeteksi kerentanan CRITICAL atau HIGH.
  □ Mengintegrasikan Cosign untuk menandatangani image secara kriptografis setelah build selesai.
  □ Menghasilkan file dokumen SBOM (format CycloneDX JSON) dan mengunggahnya sebagai attestation ke registry.

TAHAP PENYIMPANAN (REGISTRY):
  □ Mengaktifkan kebijakan "Immutable Tags" pada container registry utama.
  □ Menerapkan rotasi kredensial akses registry secara otomatis dan berkala.
  □ Membatasi akses tulis (write) ke registry hanya untuk akun layanan pipa CI/CD resmi.
  □ Mengaktifkan pemindaian celah keamanan bawaan registri ( Harbor / ECR / ACR scan-on-push).

TAHAP RUNTIME (KUBERNETES CLUSTER):
  □ Menerapkan Kyverno Policy Engine untuk mengawasi dan memfilter setiap pod yang dibuat.
  □ Memasang aturan Kyverno tolak container image dari registri luar yang tidak tepercaya.
  □ Mengaktifkan aturan Kyverno untuk memvalidasi tanda tangan Cosign terhadap public key resmi.
  □ Mengikat kredensial Image Pull Secret ke ServiceAccount default daripada menulisnya di setiap deployment.
  □ Menjalankan Trivy Operator di dalam kluster untuk memonitor kerentanan image yang berjalan secara real-time.

Ringkasan #

  • Keamanan Rantai Pasok adalah Kunci Utama — Segala proteksi runtime kluster Kubernetes akan hancur jika container image awal yang kita deploy sudah disusupi oleh penyerang di level pipeline atau registry.
  • Trivy Menghentikan Image Rentan Sejak Dini — Pemindaian kerentanan di dalam pipa CI/CD dengan Trivy secara proaktif menghentikan pengunggahan image yang memiliki celah keamanan kritis (fail-fast).
  • Cosign Menjamin Autentisitas Kode — Tanda tangan kriptografis dari Cosign memastikan bahwa image yang berjalan di kluster adalah benar-benar hasil kompilasi resmi dari pipa build tepercaya, bukan image tiruan.
  • Kyverno Menjadi Penjaga Gerbang Kluster — Policy engine Kyverno bertindak sebagai validating admission controller yang memblokir secara otomatis image apa pun yang tidak memiliki tanda tangan sah atau berasal dari registri luar.
  • Minimal Base Image Mempersempit Attack Surface — Penggunaan image distroless tanpa shell, package manager, dan perkakas eksternal mencegah penyerang melakukan eksploitasi lateral jika aplikasi kita berhasil ditembus.
  • SBOM Mempermudah Audit Cepat — Inventaris komponen perangkat lunak (SBOM) yang diunggah ke registry mempermudah pelacakan dependensi yang terdampak saat kerentanan zero-day baru ditemukan di publik.

← Sebelumnya: Network Security   Berikutnya: Audit Logging →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact