Pod Security #

Salah satu kesalahpahaman paling umum dalam arsitektur kontainer adalah menganggap kontainer sebagai sandbox keamanan terisolasi yang setara dengan Mesin Virtual (Virtual Machine / VM). Pada kenyataannya, kontainer hanyalah proses biasa yang berjalan di atas kernel sistem operasi host yang sama, yang diisolasi secara logis menggunakan fitur Linux kernel seperti Namespaces dan Control Groups (cgroups). Jika sebuah kontainer berjalan tanpa pembatasan keamanan yang memadai, ia akan memiliki hak istimewa yang terlalu besar.

Apabila kontainer tersebut berhasil dieksploitasi oleh penyerang (misalnya melalui celah Remote Code Execution), penyerang dapat dengan mudah memanfaatkan hak akses root di dalam kontainer untuk menembus batas isolasi kernel host (container breakout/escape). Begitu berhasil menembus kernel host, penyerang akan mendapatkan kendali penuh atas node worker fisik dan berpotensi melumpuhkan seluruh cluster. Untuk mencegah skenario ini, kita harus menerapkan pengerasan runtime kontainer menggunakan SecurityContext dan menegakkan kebijakan Pod Security Standards (PSS) secara disiplin di tingkat cluster.


1. Anatomi SecurityContext: Pod-Level vs Container-Level #

Kubernetes menyediakan properti securityContext pada manifes Deployment/Pod untuk mendefinisikan batasan keamanan operasional kontainer. Properti ini dapat dikonfigurasi pada dua tingkat (level) dengan cakupan pewarisan (inheritance) yang berbeda:

Pod Spec
  └── securityContext (Pod-Level: Berlaku global untuk semua kontainer di dalam Pod)
        ├── container 1 (Mewarisi pengaturan Pod-level)
        └── container 2 (Mengatur securityContext sendiri: Melakukan OVERRIDE)
  1. Pod-Level SecurityContext: Didefinisikan langsung di bawah .spec.securityContext. Parameter yang diatur di sini (seperti User ID proses, Group ID volume, dan profil Seccomp) akan diwariskan ke seluruh kontainer (termasuk kontainer aplikasi, init kontainer, dan kontainer sidecar) di dalam Pod tersebut.
  2. Container-Level SecurityContext: Didefinisikan di bawah .spec.containers[*].securityContext. Konfigurasi ini bersifat spesifik untuk kontainer tersebut dan dapat menimpa (override) parameter yang diwariskan dari level Pod. Beberapa fitur pengerasan sistem file (seperti readOnlyRootFilesystem) hanya dapat diatur pada level kontainer ini.

2. Parameter Kunci Pengerasan Kontainer #

Mari kita bedah parameter-parameter kritis dalam securityContext yang wajib kita aktifkan untuk mengamankan lingkungan runtime kontainer produksi:

A. Proteksi Pengguna: runAsNonRoot dan runAsUser #

Secara default, jika kita tidak menentukan user di Dockerfile atau manifes Kubernetes, kontainer akan berjalan sebagai user root (UID 0). Di dalam sistem operasi Linux, UID 0 di dalam kontainer dipetakan secara identik dengan UID 0 (root) di mesin host.

spec:
  securityContext:
    # Menginstruksikan Kubernetes untuk memvalidasi bahwa kontainer TIDAK dijalankan sebagai root (UID 0)
    runAsNonRoot: true
    # Memaksa kontainer berjalan menggunakan User ID 1000 (Non-Root User)
    runAsUser: 1000
    # Memaksa kontainer berjalan menggunakan Group ID 1000
    runAsGroup: 1000
  • Mengapa Ini Penting?: Jika terjadi container escape, proses penyerang yang berhasil keluar ke mesin host hanya akan memiliki hak akses sebagai user biasa (UID 1000) pada host tersebut, membatasi kemampuan mereka untuk merusak sistem operating system node.
  • fsGroup: Saat kita menempelkan Persistent Volume ke kontainer non-root, kontainer sering kali gagal menulis data karena masalah izin akses disk (permission denied). Properti fsGroup: 1000 memerintahkan Kubernetes untuk secara otomatis mengubah kepemilikan (ownership) volume yang di-mount agar dapat dibaca/ditulis oleh GID 1000.

B. Mencegah Eskalasi Hak Istimewa: allowPrivilegeEscalation: false #

Esalasi hak istimewa terjadi ketika sebuah proses anak (child process) memperoleh hak akses yang lebih tinggi daripada proses induknya (parent process). Hal ini biasanya dicapai melalui eksekusi berkas biner yang memiliki bit setuid atau setcap aktif (seperti program sudo atau passwd).

spec:
  containers:
  - name: app
    securityContext:
      # Wajib diatur ke 'false' untuk seluruh kontainer produksi
      allowPrivilegeEscalation: false
  • Mekanisme: Parameter ini mengaktifkan bendera kernel no_new_privs pada proses kontainer. Begitu bendera ini aktif, sistem operasi Linux akan menolak untuk menaikkan hak akses proses anak meskipun mereka menjalankan file biner ber-bit setuid. Aturan ini secara instan memblokir sebagian besar trik eksploitasi eskalasi lokal (local privilege escalation).

C. Pengerasan Sistem File: readOnlyRootFilesystem: true #

Secara default, filesystem kontainer bersifat writable (dapat ditulis). Penyerang yang berhasil masuk ke dalam kontainer akan segera mencoba mengunduh perkakas hacking (seperti curl, wget, nmap, atau backdoor script) dan menulisnya ke direktori sistem kontainer.

spec:
  containers:
  - name: app
    securityContext:
      # Mengunci filesystem kontainer menjadi hanya-baca (Read-Only)
      readOnlyRootFilesystem: true
  • Mekanisme: Mengunci seluruh filesystem root kontainer menjadi Read-Only. Penyerang tidak akan bisa memodifikasi berkas biner aplikasi, menimpa file konfigurasi, atau menulis malware ke disk.
  • Solusi Menulis File Sementara (Volume Mounts): Banyak framework aplikasi (seperti Node.js, Python, atau Java) tetap membutuhkan folder khusus untuk menulis berkas sementara (temporary files, log, atau cache). Kita harus menyediakan direktori khusus tersebut menggunakan volume emptyDir yang dipasang di memori (tmpfs/RAM).
# ✓ SOLUSI: Kombinasi Read-Only Filesystem dengan emptyDir Volume Mounts
spec:
  containers:
  - name: app
    securityContext:
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: ephemeral-storage
      mountPath: /tmp # Direktori tulis sementara untuk aplikasi
  volumes:
  - name: ephemeral-storage
    emptyDir:
      # Menggunakan RAM host sebagai media penyimpanan (tidak pernah tertulis ke disk fisik)
      medium: Memory
      # Batasi ukuran penyimpanan sementara untuk menghindari pemborosan RAM
      sizeLimit: 128Mi

D. Pembatasan Hak Istimewa Kernel: Linux Capabilities #

Linux memecah kekuasaan mutlak super-user root menjadi unit-unit hak akses yang lebih kecil dan independen, yang disebut Capabilities. Secara default, runtime kontainer Kubernetes memberikan subset capabilities bawaan ke kontainer (seperti CAP_CHOWN, CAP_NET_RAW, CAP_MKNOD).

Banyak aplikasi web mikroservice sama sekali tidak membutuhkan capabilities ini untuk dapat melayani trafik HTTP. Memberikan capabilities yang tidak digunakan hanya akan mempermudah penyerang untuk melakukan eksploitasi sistem operasi host.

[!TIP] Prinsip Drop All, Add Selective: Cara terbaik adalah menghapus seluruh capabilities bawaan kontainer terlebih dahulu menggunakan kueri drop: ["ALL"], lalu secara selektif menambahkan kembali hanya yang benar-benar dibutuhkan oleh logika bisnis aplikasi.

spec:
  containers:
  - name: app
    securityContext:
      capabilities:
        drop:
        - ALL # ← Wajib: Hapus seluruh capabilities default Linux kernel
        add:
        - NET_BIND_SERVICE # ← Contoh: Hanya izinkan aplikasi mengikat socket port di bawah 1024 (e.g. port 80)

Analisis Risiko Capabilities: #

  • CAP_SYS_ADMIN: Puncak bahaya. Memberikan hak akses setara root hampir penuh. Jangan pernah mengaktifkan ini untuk kontainer aplikasi biasa.
  • CAP_NET_RAW: Mengizinkan kontainer menyusun paket jaringan mentah (raw packets). Berguna untuk ping kueri, namun sangat berbahaya karena memungkinkan penyerang melakukan sniffing lalu lintas data kluster secara lateral.
  • CAP_NET_BIND_SERVICE: Mengizinkan proses non-root untuk mengikat port istimewa (privilege ports) di bawah 1024 (seperti port 80 atau 443). Jika aplikasi kita berjalan di port 8080, kita tidak membutuhkan capability ini.

E. Penyaringan System Call: seccompProfile #

Seccomp (Secure Computing Mode) adalah fitur keamanan kernel Linux yang membatasi panggilan sistem (system calls / syscalls) yang boleh diajukan oleh kontainer ke kernel host. Kernel Linux memiliki lebih dari 300 syscalls, tetapi rata-rata kontainer aplikasi hanya membutuhkan kurang dari 50 syscalls untuk berjalan.

spec:
  securityContext:
    seccompProfile:
      # Menggunakan profil default runtime kontainer (runc / containerd)
      type: RuntimeDefault
  • Mekanisme: Profil RuntimeDefault memblokir sekitar 300 syscalls berbahaya (seperti reboot, sys_ptrace, atau kueri manipulasi kernel lainnya) yang sering kali digunakan oleh eksploitasi zero-day untuk menembus isolasi kontainer. Pengaturan ini wajib diaktifkan pada level Pod untuk seluruh lingkungan produksi.

3. Pod Security Standards (PSS) & Pod Security Admission (PSA) #

Untuk menegakkan kebijakan pengerasan kontainer secara seragam di seluruh kluster, Kubernetes menyediakan mekanisme admission control bawaan bernama Pod Security Admission (PSA). PSA mengevaluasi setiap Pod yang akan dibuat terhadap tiga tingkatan Pod Security Standards (PSS):

+---------------------------------------------------------------------------------+
| POD SECURITY STANDARDS (PSS) LEVELS:                                            |
|                                                                                 |
| 1. PRIVILEGED (Tidak ada batasan)                                               |
|    - Mengizinkan hostNetwork, hostPath, run as root, dan privileges penuh.       |
|    - Hanya untuk CNI plugins, storage drivers, kube-proxy.                      |
|                                                                                 |
| 2. BASELINE (Mencegah eskalasi berbahaya)                                       |
|    - Memblokir hostNetwork, hostPID, hostIPC, dan hostPath volumes.             |
|    - Standar default aman untuk aplikasi umum.                                  |
|                                                                                 |
| 3. RESTRICTED (Pengerasan Keamanan Maksimal)                                    |
|    - Wajib runAsNonRoot, readOnlyRootFilesystem, seccompProfile, drop capabilities.|
|    - Standar wajib untuk kepatuhan tinggi (PCI-DSS / HIPAA).                    |
+---------------------------------------------------------------------------------+

Menegakkan Kebijakan di Tingkat Namespace #

Kita mengaktifkan kontrol PSS ini dengan memberikan label khusus pada objek Namespace. PSA memiliki tiga mode aksi yang dapat dikombinasikan:

  • enforce: Menolak pembuatan Pod secara keras jika Pod melanggar aturan standar.
  • warn: Mengizinkan Pod dibuat, tetapi mengirimkan pesan peringatan (warning) ke klien (misalnya ke CLI developer).
  • audit: Mengizinkan Pod dibuat, tetapi mencatat pelanggaran tersebut ke dalam audit log kluster.
# Manifes Namespace Produksi dengan Pengamanan Ketat (Restricted)
apiVersion: v1
kind: Namespace
metadata:
  name: payment-processing
  labels:
    # Mode Enforce: Tolak mentah-mentah jika Pod melanggar standar Restricted
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    
    # Mode Warn: Berikan peringatan visual saat developer melakukan kubectl apply
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: latest

PSS Restricted Validation Flow #

Ketika sebuah manifest Pod dikirimkan ke API Server, Admission Controller akan mengevaluasi label namespace dan memblokir Pod jika tidak memenuhi kriteria keamanan:

sequenceDiagram
    participant Dev as Operator / CI Pipeline
    participant API as Kubernetes API Server
    participant PSA as Pod Security Admission
    participant Kube as Kubelet Daemon
    
    Dev->>API: Kirim manifes Pod (kubectl apply)
    API->>PSA: Validasi manifes terhadap Kebijakan Namespace
    Note over PSA: Evaluasi Namespace: payment-processing<br>(Standard: Restricted Enforce)
    
    Alt Pod Melanggar Aturan (e.g., runAsNonRoot: false)
        PSA-->>API: Validasi Gagal (Tolak Pod)
        API-->>Dev: HTTP 403 Forbidden (Error: Pod does not meet Restricted standard)
    Else Pod Memenuhi Aturan (e.g., runAsNonRoot: true & seccomp aktif)
        PSA-->>API: Validasi Lulus (Izinkan Pod)
        API->>Kube: Jadwalkan kontainer ke Node Worker
        Kube-->>Dev: Pod Sukses Dibuat (Running)
    End

Anti-Pattern vs Solusi Terbaik #

Mari kita pelajari beberapa kesalahan konfigurasi keamanan runtime kontainer yang sering ditemui di industri beserta perbaikannya.

Anti-Pattern 1: Menggunakan Volume hostPath untuk Penyimpanan Sementara #

Menggunakan volume bertipe hostPath untuk memberikan write access folder log atau cache sementara ke kontainer.

# ✗ ANTI-PATTERN: Menggunakan hostPath yang memicu kebocoran host directory
spec:
  containers:
  - name: web-app
    image: company/web-app:v1.0.0
    volumeMounts:
    - name: host-log
      mountPath: /var/log/app
  volumes:
  - name: host-log
    hostPath:
      path: /var/log/host-system # ← KRITIS: Kontainer dapat mengakses file sistem host

Solusi Terbaik #

Gunakan volume emptyDir yang terisolasi di level Pod. Data tersimpan di memori node worker dan akan langsung dihapus bersih secara otomatis oleh Kubernetes saat Pod dimatikan, tanpa menyisipkan celah akses direktori host.


Anti-Pattern 2: Menjalankan Kontainer dengan privileged: true #

Menetapkan flag privileged: true pada spesifikasi kontainer biasa dengan alasan mempermudah debugging konektivitas jaringan atau akses perangkat.

# ✗ ANTI-PATTERN: Memberikan hak istimewa sistem penuh ke kontainer
spec:
  containers:
  - name: debug-tool
    image: company/debug-tool:latest
    securityContext:
      privileged: true # ← FATAL: Menghapus seluruh isolasi namespace dan kernel cluster

Solusi Terbaik #

Gunakan fitur kubectl debug dengan ephemeral container yang memuat image khusus seperti netshoot untuk melakukan debugging jaringan secara terarah tanpa mengorbankan keamanan Deployment utama.


Anti-Pattern 3: Menggunakan hostNetwork, hostPID, atau hostIPC #

Mengaktifkan pembagian namespace host fisik ke kontainer aplikasi biasa agar kontainer dapat melihat proses sistem host atau memanipulasi network card host secara langsung.

# ✗ ANTI-PATTERN: Mengaktifkan sharing namespace host
spec:
  hostNetwork: true # ← Mengikat port kontainer langsung ke port fisik node host
  hostPID: true     # ← Kontainer dapat melihat dan mematikan proses di mesin host
  hostIPC: true     # ← Kontainer dapat memanipulasi memory sharing host
  containers:
  - name: bad-app
    image: company/bad-app:v1.0.0

Solusi Terbaik #

Pertahankan nilai default false untuk ketiga parameter tersebut. Gunakan model isolasi jaringan Kubernetes (flat network model CNI) dan biarkan Kubernetes Service yang mengelola perutean port kontainer secara terabstraksi.


Manifes Deployment Produksi Terbaik (PSS Restricted Hardened) #

Berikut adalah contoh manifes Deployment siap produksi yang telah melalui pengerasan keamanan maksimal (highly hardened) memenuhi standar PSS Restricted:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: secured-api-gateway
  namespace: payment-processing
  labels:
    app.kubernetes.io/name: secured-api-gateway
spec:
  replicas: 3
  selector:
    matchLabels:
      app: secured-api-gateway
  template:
    metadata:
      labels:
        app: secured-api-gateway
    spec:
      # 1. Konfigurasi Keamanan di Tingkat Pod Spec
      securityContext:
        runAsNonRoot: true # Menolak kontainer yang mencoba jalan sebagai root
        runAsUser: 1000 # Menetapkan User ID non-root
        runAsGroup: 3000 # Menetapkan Group ID non-root
        fsGroup: 2000 # Menyelaraskan ownership volume mount ke GID 2000
        seccompProfile:
          type: RuntimeDefault # Mengaktifkan filtering syscall default
      containers:
      - name: gateway
        image: company/api-gateway:sha-9d8f3e2
        resources:
          requests:
            cpu: "250m"
            memory: "256Mi"
          limits:
            cpu: "1000m"
            memory: "512Mi"
        # 2. Konfigurasi Keamanan di Tingkat Kontainer Spec
        securityContext:
          allowPrivilegeEscalation: false # Mencegah eskalasi hak akses via setuid
          readOnlyRootFilesystem: true # Mengunci filesystem root kontainer menjadi read-only
          capabilities:
            drop:
            - ALL # Menghapus seluruh capabilities Linux kernel bawaan
        volumeMounts:
        - name: tmp-storage
          mountPath: /tmp # Direktori tulis sementara untuk cache framework
        ports:
        - containerPort: 8080
      volumes:
      - name: tmp-storage
        emptyDir:
          medium: Memory
          sizeLimit: 128Mi

Checklist Audit Hardening Keamanan Pod #

Pastikan seluruh Pod kontainer yang berjalan di kluster produksi kita lolos audit pengerasan keamanan menggunakan checklist berikut:

PENGELOLAAN USER & HAK AKSES:
  □ Parameter 'runAsNonRoot' diatur ke 'true' pada spesifikasi Pod level.
  □ Parameter 'runAsUser' dikonfigurasi menggunakan UID non-root spesifik (bukan 0).
  □ Parameter 'allowPrivilegeEscalation' diatur ke 'false' pada seluruh kontainer.
  □ Properti 'privileged: true' dipastikan telah dinonaktifkan dari seluruh aplikasi biasa.

PENGASIPAN & SISTEM FILE:
  □ Properti 'readOnlyRootFilesystem' diaktifkan pada spesifikasi kontainer level.
  □ Volume 'emptyDir' (RAM-backed/Memory) digunakan untuk direktori tulis sementara (/tmp).
  □ Penggunaan volume 'hostPath' telah dieliminasi penuh untuk aplikasi stateless.

LINUX CAPABILITIES & SYSCALLS:
  □ Blok 'capabilities.drop' diatur ke 'ALL' untuk menghapus capabilities Linux default.
  □ Penambahan capabilities ('capabilities.add') hanya dilakukan secara selektif dan terdokumentasi.
  □ Parameter 'seccompProfile.type' dikonfigurasi ke 'RuntimeDefault' pada tingkat Pod.

ISOLASI NAMESPACE & PSA ENFORCEMENT:
  □ Namespace produksi dilabeli dengan aturan 'pod-security.kubernetes.io/enforce: restricted'.
  □ Parameter 'hostNetwork', 'hostPID', dan 'hostIPC' dipastikan bernilai 'false' (default).
  □ Pengamanan runtime teruji berjalan lancar tanpa memicu CrashLoopBackOff akibat permission issues.

Ringkasan #

  • Wajib jalankan non-root — Aktifkan parameter runAsNonRoot: true pada tingkat Pod untuk memastikan tidak ada kontainer produksi yang beroperasi sebagai user root (UID 0).
  • Cegah eskalasi via no_new_privs — Konfigurasikan allowPrivilegeEscalation: false untuk memblokir eksekusi biner setuid yang dapat memicu eskalasi hak akses di kontainer.
  • Kunci filesystem kontainer — Gunakan properti readOnlyRootFilesystem: true untuk menolak modifikasi atau instalasi malware di sistem file kontainer oleh penyerang.
  • Gunakan emptyDir RAM untuk /tmp — Sediakan direktori tulis sementara menggunakan volume emptyDir dengan tipe media Memory untuk mengamankan proses write sementara aplikasi.
  • Drop ALL Linux capabilities — Terapkan taktik Drop All, Add Selective pada parameter capabilities kontainer guna meminimalkan hak akses kernel yang tidak digunakan.
  • Aktifkan Pod Security Admission — Labeli namespace produksi dengan standard restricted untuk menolak pembuatan manifest Pod yang tidak ramah pengerasan keamanan secara otomatis.

← Sebelumnya: RBAC   Berikutnya: Network Security →

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