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)
- 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. - 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 (sepertireadOnlyRootFilesystem) 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: 1000memerintahkan 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_privspada proses kontainer. Begitu bendera ini aktif, sistem operasi Linux akan menolak untuk menaikkan hak akses proses anak meskipun mereka menjalankan file biner ber-bitsetuid. 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
emptyDiryang 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 bawah1024(seperti port80atau443). Jika aplikasi kita berjalan di port8080, 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
RuntimeDefaultmemblokir sekitar 300 syscalls berbahaya (sepertireboot,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: truepada tingkat Pod untuk memastikan tidak ada kontainer produksi yang beroperasi sebagai user root (UID 0).- Cegah eskalasi via
no_new_privs— KonfigurasikanallowPrivilegeEscalation: falseuntuk memblokir eksekusi binersetuidyang dapat memicu eskalasi hak akses di kontainer.- Kunci filesystem kontainer — Gunakan properti
readOnlyRootFilesystem: trueuntuk menolak modifikasi atau instalasi malware di sistem file kontainer oleh penyerang.- Gunakan emptyDir RAM untuk /tmp — Sediakan direktori tulis sementara menggunakan volume
emptyDirdengan tipe mediaMemoryuntuk 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
restricteduntuk menolak pembuatan manifest Pod yang tidak ramah pengerasan keamanan secara otomatis.