Anti-Pattern Security #

Sebagian besar insiden keamanan Kubernetes bukan disebabkan oleh zero-day vulnerability yang canggih — mereka disebabkan oleh konfigurasi yang terlalu permisif, kebiasaan buruk yang terbiasa dari development environment, atau fitur yang tidak dipahami risikonya. Artikel ini mengkompilasi anti-pattern keamanan yang paling sering ditemui di cluster production, lengkap dengan mengapa itu berbahaya dan bagaimana memperbaikinya.

Anti-Pattern 1: Container Berjalan sebagai Root #

# ANTI-PATTERN: tidak ada securityContext → container berjalan sebagai root
spec:
  containers:
  - name: api
    image: my-api:v2
    # Tidak ada securityContext
    # Container berjalan sebagai root (UID 0) secara default
Konsekuensi:
  Jika aplikasi dikompromis via RCE (Remote Code Execution):
  → Penyerang punya akses root di dalam container
  → Dengan kernel exploit atau container escape, bisa jadi root di node
  → Dari node: akses ke semua container lain di node yang sama
  → Dari node: akses ke API Server via node credentials
# BENAR: jalankan sebagai non-root user
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
  containers:
  - name: api
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]

Anti-Pattern 2: ClusterRoleBinding dengan cluster-admin untuk Service Account #

# ANTI-PATTERN: service account aplikasi punya akses cluster-admin
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: my-app-admin
subjects:
- kind: ServiceAccount
  name: my-app
  namespace: production
roleRef:
  kind: ClusterRole
  name: cluster-admin    # ← akses penuh ke seluruh cluster!
Ini adalah misconfiguration yang sangat umum, terutama dari:
  → Tutorial yang menyederhanakan RBAC
  → "Solusi cepat" saat aplikasi mendapat error permission
  → Warisan konfigurasi dari masa eksplorasi

Konsekuensi:
  Jika container yang pakai service account ini dikompromis:
  → Penyerang punya akses penuh ke seluruh cluster
  → Bisa baca semua Secret di semua namespace
  → Bisa buat, modifikasi, atau hapus resource apapun
  → Bisa escalate privilege lebih jauh

Cara identifikasi:
  kubectl get clusterrolebindings -o json | \
    jq '.items[] | select(.roleRef.name=="cluster-admin") |
    {name: .metadata.name, subjects: .subjects}'
# BENAR: permission minimal yang dibutuhkan, namespace-scoped
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: my-app-role
  namespace: production
rules:
- apiGroups: [""]
  resources: ["configmaps"]
  resourceNames: ["app-config"]
  verbs: ["get"]

Anti-Pattern 3: hostNetwork, hostPID, atau hostPath yang Tidak Perlu #

# ANTI-PATTERN: menggunakan host namespace
spec:
  hostNetwork: true    # ← Pod menggunakan network namespace host
  hostPID: true        # ← Pod bisa lihat semua proses di host
  hostIPC: true        # ← Pod menggunakan IPC namespace host
  volumes:
  - name: host-root
    hostPath:
      path: /           # ← mount root filesystem host
Konsekuensi:
  hostNetwork: true
    → Pod bisa sniff semua traffic di host, termasuk traffic cluster internal
    → Pod bisa bind ke port host langsung
    → Networking isolation tidak ada

  hostPID: true
    → Pod bisa lihat dan potensially signal semua proses di host
    → Bisa membaca /proc/<pid>/environ dari proses host → credential theft

  hostPath: / (mount root filesystem)
    → Baca/tulis ke seluruh filesystem host dari dalam container
    → Bisa modifikasi container runtime config, kubeconfig, dll

Hanya DaemonSet untuk infrastruktur (monitoring agent, CNI plugin)
yang boleh menggunakan host namespace. Aplikasi biasa tidak perlu ini.

Anti-Pattern 4: Image dari Registry Publik Tanpa Verifikasi #

# ANTI-PATTERN: pull image langsung dari Docker Hub tanpa verifikasi
spec:
  containers:
  - name: database-exporter
    image: prom/postgres-exporter:latest    # ← dari Docker Hub, tidak diverifikasi
  - name: cache
    image: redis                            # ← tag tidak di-pin
Risiko:
  → Image bisa di-overwrite di registry (kecuali immutable tags diaktifkan)
  → latest tag tidak menunjuk ke versi yang konsisten
  → Tidak ada verifikasi bahwa image tidak mengandung malware
  → Docker Hub pernah mengalami incident di mana image populer dikompromis

Best practice:
  → Pull ke private registry dulu, lalu deploy dari private registry
  → Pin dengan digest: redis@sha256:abc123... (immutable, lebih aman dari tag)
  → Scan sebelum masuk ke registry internal
  → Atau aktifkan image signing dan verify di admission controller

Anti-Pattern 5: Secrets di Log atau Output Debug #

# ANTI-PATTERN: log yang tidak sengaja mencatat Secret
import logging, os

db_pass = os.getenv('DB_PASSWORD')
logging.info(f"Connecting to database with config: {os.environ}")  # ← LOG SEMUA ENV VAR
logging.debug(f"DB password: {db_pass}")  # ← LOG PASSWORD
Konsekuensi:
  → Log dikirim ke centralized logging (Elasticsearch, Splunk)
  → Semua orang yang punya akses ke log system bisa baca password
  → Termasuk contractor, junior developer, atau external monitoring vendor
  → Log mungkin juga disimpan di S3 bucket atau tempat lain dengan akses lebih luas

Dua sumber kebocoran yang umum:
  1. Framework yang log semua environment variable saat startup
     (Spring Boot Actuator, beberapa Go frameworks)
  2. Error handler yang dump seluruh stack trace termasuk variables
# BENAR: redact nilai sensitif dari log
logging.info(f"Connecting to {os.getenv('DB_HOST')}:{os.getenv('DB_PORT')}")
# Tidak pernah log password, token, atau key

Anti-Pattern 6: NetworkPolicy Tidak Diterapkan #

ANTI-PATTERN: cluster tanpa NetworkPolicy sama sekali

Kondisi yang sering terjadi di cluster yang tumbuh organik:
  → Awalnya cluster kecil, semua tim kenal satu sama lain
  → Tidak ada NetworkPolicy karena "tidak punya waktu"
  → Cluster berkembang, makin banyak service dan namespace
  → Masih tidak ada NetworkPolicy

Konsekuensi:
  Service staging bisa akses langsung database production
  Debugging Pod bisa hubungi service payment internal
  Pod yang dikompromis bisa lateral move ke service manapun di cluster
  Tidak ada yang tahu "blast radius" jika satu Pod dikompromis

Mulai dengan default-deny per namespace bahkan untuk cluster yang sudah ada:

# Apply default-deny ke namespace yang paling kritikal dulu
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF
# Lalu buka secara selektif berdasarkan kebutuhan aktual

Anti-Pattern 7: Tidak Ada Update Security Patch #

ANTI-PATTERN: cluster berjalan dengan versi Kubernetes yang sudah EOL
  kubectl version
  Server Version: v1.23.17   ← EOL sejak Februari 2024

Atau node OS dengan ratusan package outdated:
  apt list --upgradable | wc -l
  187 packages can be upgraded

Konsekuensi:
  → CVE yang sudah diketahui tidak di-patch
  → Exploit publik tersedia untuk vulnerability lama
  → Attacker tidak perlu zero-day — cukup pakai exploit lama
  → Compliance requirement (PCI-DSS, SOC2, ISO27001) biasanya
    mensyaratkan patch dalam N hari setelah release

Untuk cluster managed (GKE, EKS, AKS):
  Aktifkan auto-upgrade untuk node pool
  Atau jadwalkan maintenance window untuk upgrade rutin

Untuk self-managed:
  Gunakan tool seperti Renovate untuk dependency tracking
  Set alert untuk CVE yang mempengaruhi versi yang digunakan

Ringkasan #

  • Container root = blast radius besar — selalu set runAsNonRoot: true dan allowPrivilegeEscalation: false; satu misconfiguration ini bisa membuat container escape menjadi root di host.
  • cluster-admin untuk service account adalah kesalahan serius — audit secara rutin siapa yang punya ClusterRoleBinding ke cluster-admin; berikan hanya permission minimal yang dibutuhkan.
  • hostNetwork/hostPID/hostPath hanya untuk infrastruktur — aplikasi bisnis tidak pernah butuh akses ke host namespace; jika ada yang butuh, pertanyakan ulang desainnya.
  • Jangan log environment variable — banyak framework melakukan ini saat startup atau error; pastikan nilai sensitif tidak masuk ke log aggregation pipeline.
  • NetworkPolicy bukan optional untuk produksi — tanpa NetworkPolicy, satu Pod yang dikompromis bisa lateral move ke seluruh cluster; mulai dengan default-deny meski bertahap.
  • Security patch adalah kewajiban, bukan optional — cluster dengan CVE yang sudah diketahui adalah target mudah; update Kubernetes dan node OS secara rutin sebagai bagian operasional normal.

← Sebelumnya: Cluster Hardening   Berikutnya: Logging →

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