Network Security #
Secara default, model jaringan Kubernetes beroperasi berdasarkan prinsip dasar yang sangat terbuka: flat network. Seluruh Pod di dalam kluster dapat saling berkomunikasi satu sama lain secara bebas lintas namespace tanpa membutuhkan NAT (Network Address Translation) atau konfigurasi port routing tambahan. Di lingkungan pengembangan (development), model ini sangat memudahkan pengujian interaksi antar-layanan. Namun, di lingkungan produksi, membiarkan flat network terbuka lebar tanpa pembatasan adalah mimpi buruk bagi keamanan informasi.
Jika salah satu Pod aplikasi kita (misalnya blog publik yang kurang terawat) berhasil dieksploitasi oleh penyerang, model flat network akan mempermudah penyerang untuk melakukan pemindaian jaringan internal (lateral scanning). Penyerang dapat langsung mengirimkan paket data ke database transaksi, cache Redis, atau panel kontrol internal yang seharusnya terisolasi. Untuk mencegah hal tersebut, kita harus menerapkan arsitektur Zero-Trust Jaringan di Kubernetes menggunakan NetworkPolicy, Mutual TLS (mTLS), pembatasan metadata cloud provider, serta pengerasan (hardening) di pintu masuk trafik (Ingress).
1. Filosofi Zero-Trust Jaringan di Kubernetes #
Zero-Trust Jaringan didasarkan pada tiga postulat sederhana: jangan pernah percaya, selalu verifikasi, dan batasi hak akses jaringan seminimal mungkin. Di Kubernetes, ini berarti kita harus memutus asumsi bahwa lalu lintas data internal kluster bersifat aman.
Pilar Pengamanan Jaringan: #
- Segmentasi L3/L4 (NetworkPolicy): Membatasi koneksi antar-Pod berdasarkan alamat IP, selector label, namespace, dan port TCP/UDP.
- Identitas & Enkripsi L7 (mTLS): Menjamin bahwa data yang dikirimkan antar-Pod terenkripsi secara kriptografis di jaringan kabel (wire) dan hanya proses dengan identitas yang sah (SPIFFE/SPIRE) yang dapat membuka koneksi.
- Pengamanan Perimeter (Ingress Hardening): Menyaring lalu lintas dari internet publik sebelum masuk ke dalam jaringan internal kluster.
2. Segmentasi Jaringan dengan NetworkPolicy (L3/L4) #
NetworkPolicy adalah spesifikasi deklaratif Kubernetes yang bertindak sebagai firewall lokal untuk Pod. Perlu dicatat bahwa Kubernetes API Server hanya menyimpan definisi objek NetworkPolicy. Tugas untuk mengevaluasi dan menegakkan aturan paket data tersebut diserahkan sepenuhnya kepada CNI (Container Network Interface) Plugin yang kita pasang di cluster (seperti Calico, Cilium, atau Kube-Router).
[!WARNING] CNI Tanpa Dukungan Policy: Jika kita menggunakan CNI dasar seperti Flannel, seluruh objek NetworkPolicy yang kita buat akan diabaikan secara diam-diam (silently ignored). Flannel tidak memiliki mesin evaluasi paket data (iptables/eBPF), sehingga trafik tetap akan terbuka lebar. Selalu gunakan CNI dengan dukungan keamanan seperti Calico atau Cilium di produksi.
Tahap 1: Terapkan Default-Deny-All #
Dalam merancang firewall, taktik paling aman adalah memblokir seluruh lalu lintas terlebih dahulu (default-deny), baru kemudian membuka akses secara selektif (allow-list).
# Manifes Default Deny All untuk Ingress dan Egress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: e-commerce # Terapkan pada namespace produksi
spec:
# Menggunakan kurung kurawal kosong '{}' untuk mencocokkan seluruh Pod di namespace
podSelector: {}
policyTypes:
- Ingress
- Egress
Tahap 2: Buka Akses DNS (Egress Wajib) #
Setelah kita mengaktifkan default-deny Egress di atas, seluruh kueri resolusi nama domain (DNS) aplikasi ke CoreDNS cluster (kube-dns) akan terblokir. Aplikasi kita akan langsung lumpuh karena tidak dapat mencari alamat IP database atau layanan eksternal.
Oleh karena itu, kita wajib membuat aturan khusus yang mengizinkan lalu lintas keluar (Egress) ke CoreDNS pada port 53 (UDP/TCP).
# Manifes Mengizinkan Akses Resolusi CoreDNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-system-dns
namespace: e-commerce
spec:
podSelector: {} # Berlaku untuk seluruh Pod di namespace
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
# Membidik namespace 'kube-system' tempat CoreDNS berjalan
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Tahap 3: Buka Akses Ingress Antar-Layanan #
Misalkan kita memiliki microservice payment-api yang hanya boleh menerima koneksi masuk (Ingress) dari microservice gateway-api yang berada di namespace yang sama.
# Manifes Membatasi Ingress ke payment-api
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-payment-from-gateway
namespace: e-commerce
spec:
# Membidik Pod target (payment-api)
podSelector:
matchLabels:
app: payment-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
# Hanya izinkan koneksi masuk dari Pod yang memiliki label ini
app: gateway-api
ports:
- protocol: TCP
port: 8080 # Batasi akses hanya ke port aplikasi ini
3. Mencegah Kebocoran Kredensial: Blokir Metadata Cloud Provider #
Saat kita menjalankan Kubernetes di lingkungan cloud provider (seperti AWS EKS, GCP GKE, atau Azure AKS), setiap node worker memiliki akses fisik ke endpoint metadata lokal cloud melalui alamat IP link-local 169.254.169.254.
Jika salah satu aplikasi kita rentan terhadap celah SSRF (Server-Side Request Forgery), penyerang dapat mengeksploitasi aplikasi tersebut untuk mengirimkan kueri HTTP GET ke endpoint metadata tersebut.
[ Pod Aplikasi Terinfeksi ] ──► HTTP GET http://169.254.169.254/latest/meta-data/iam/security-credentials/
│
▼
[ Mengembalikan Token Kunci IAM Role Produksi ]
Penyerang akan mendapatkan token akses IAM Role yang melekat pada node worker, memberikan mereka kemampuan untuk mencuri data di bucket S3, memanipulasi database cloud, atau bahkan menghapus infrastruktur kluster secara keseluruhan.
Solusi NetworkPolicy Egress #
Kita harus membuat NetworkPolicy tingkat global yang melarang seluruh Pod kontainer mengakses IP 169.254.169.254.
# Manifes Memblokir Akses ke Endpoint Metadata Cloud Provider
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: block-cloud-metadata
namespace: e-commerce
spec:
podSelector: {} # Terapkan ke seluruh Pod di namespace
policyTypes:
- Egress
egress:
- to:
- ipBlock:
# Mengizinkan koneksi keluar ke seluruh alamat IP internet (0.0.0.0/0)
cidr: 0.0.0.0/0
except:
# KECUALI ke IP sensitif metadata cloud provider
- 169.254.169.254/32 # AWS / GCP / Azure Metadata IP
- 169.254.170.2/32 # AWS ECS Task Metadata IP
4. Otorisasi & Enkripsi Layer 7: Mutual TLS (mTLS) #
NetworkPolicy bekerja secara eksklusif pada Layer 3 (IP) dan Layer 4 (Port). Jaringan L3/L4 tidak memiliki kemampuan untuk:
- Mendeteksi apakah paket data dikirim dalam bentuk plaintext yang dapat disadap (sniffed) di switch jaringan host node.
- Memevalidasi identitas asli dari kontainer pengirim (penyerang dapat saja memanipulasi IP spoofing di level CNI yang rusak).
Untuk mengamankan lalu lintas data di level aplikasi, kita wajib mengaktifkan Mutual TLS (mTLS) menggunakan teknologi Service Mesh (seperti Istio atau Linkerd) atau di level CNI modern (seperti Cilium).
mTLS menjamin bahwa setiap koneksi antar-Pod melalui proses jabat tangan (handshake) TLS dua arah. Pod pengirim memvalidasi sertifikat Pod penerima, dan sebaliknya. Selain itu, seluruh lalu lintas data terenkripsi secara otomatis menggunakan algoritma enkripsi modern (AES-GCM).
sequenceDiagram
participant PodA as Pod Gateway (Client)
participant ProxyA as Envoy Proxy A (Sidecar)
participant ProxyB as Envoy Proxy B (Sidecar)
participant PodB as Pod Payment (Server)
PodA->>ProxyA: HTTP Request Plaintext (e.g., POST /pay)
ProxyA->>ProxyB: TLS Handshake (Kirim Sertifikat Client SPIFFE)
ProxyB->>ProxyA: TLS Handshake (Kirim Sertifikat Server SPIFFE)
Note over ProxyA,ProxyB: Verifikasi Validitas Sertifikat Dua Arah (mTLS)
ProxyA->>ProxyB: Kirim Data Terenkripsi (AES)
ProxyB->>PodB: Teruskan HTTP Request Plaintext (Localhost)
Jika kita menggunakan Istio, kita dapat menegakkan kebijakan mTLS ketat (strict mode) di seluruh namespace produksi dengan satu manifes berikut:
# Manifes Penegakan STRICT mTLS Istio
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default-mtls-strict
namespace: e-commerce
spec:
mtls:
# Mode STRICT menolak seluruh koneksi plaintext non-mTLS yang mencoba masuk ke namespace
mode: STRICT
5. Hardening Ingress (Security Perimeter) #
Ingress Controller adalah gerbang utama pertahanan kita dari ancaman lalu lintas internet publik. Kita harus mengonfigurasi pengerasan keamanan (hardening) pada Ingress untuk memitigasi serangan umum seperti brute force, payload injection, dan DDoS.
Berikut adalah konfigurasi anotasi Ingress NGINX yang direkomendasikan untuk produksi:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gateway-ingress
namespace: e-commerce
annotations:
# 1. Batasi Kecepatan Request per IP (Rate Limiting)
nginx.ingress.kubernetes.io/limit-rps: "50" # Maksimal 50 request per detik per client IP
nginx.ingress.kubernetes.io/limit-burst-multiplier: "3"
# 2. Paksa HTTPS dengan HTTP Strict Transport Security (HSTS)
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
nginx.ingress.kubernetes.io/hsts: "true"
nginx.ingress.kubernetes.io/hsts-max-age: "31536000" # Wajibkan HTTPS selama 1 tahun
nginx.ingress.kubernetes.io/hsts-include-subdomains: "true"
# 3. Batasi Ukuran Payload Request (Mitigasi Buffer Overflow)
nginx.ingress.kubernetes.io/proxy-body-size: "5m" # Tolak request dengan body > 5 MB
# 4. Suntikkan Header Keamanan HTTP (Configuration Snippet)
nginx.ingress.kubernetes.io/configuration-snippet: |
# Mencegah serangan Clickjacking (Clickjacking Protection)
more_set_headers "X-Frame-Options: DENY";
# Mencegah MIME-type Sniffing (MIME Sniffing Protection)
more_set_headers "X-Content-Type-Options: nosniff";
# Mengontrol informasi referer yang dikirimkan
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
# Menolak akses ke perangkat hardware client
more_set_headers "Permissions-Policy: camera=(), microphone=(), geolocation=()";
spec:
ingressClassName: nginx
rules:
- host: api.company.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gateway-service
port:
number: 80
6. Jaringan Keputusan Evaluasi Paket Jaringan (CNI Engine) #
Bagaimana CNI mengevaluasi setiap paket data yang melintasi antarmuka jaringan kontainer dapat digambarkan secara logika melalui flowchart berikut:
flowchart TD
Start["Paket Data Dikirim / Diterima di Node"] --> Q1{"Apakah ada NetworkPolicy yang aktif<br>membidik Pod target?"}
Q1 -- "Tidak" --> AllowDefault["IZINKAN PAKET (Flat Network Default)"]
Q1 -- "Ya" --> Q2{"Apakah asal / tujuan paket cocok dengan<br>aturan ALLOW-LIST di NetworkPolicy?"}
Q2 -- "Ya (Ada Aturan Yang Cocok)" --> AllowPolicy["IZINKAN PAKET"]
Q2 -- "Tidak (Tidak Ada Kecocokan)" --> DropPacket["BLOKIR & DROP PAKET<br>'(Silent Drop)'"]
style AllowDefault stroke:#f57c00,stroke-width:2px
style AllowPolicy stroke:#388e3c,stroke-width:2px
style DropPacket stroke:#d32f2f,stroke-width:2px
Anti-Pattern vs Solusi Terbaik #
Berikut adalah kesalahan umum konfigurasi keamanan jaringan di cluster Kubernetes beserta perbaikan terbaiknya.
Anti-Pattern 1: Mengaktifkan Ingress untuk Database Server #
Mengekspos database utama cluster (seperti PostgreSQL atau MySQL) menggunakan Service tipe LoadBalancer atau Ingress TCP agar tim developer dapat melakukan query langsung dari laptop mereka.
Konsekuensi #
Database terekspos secara publik ke seluruh internet. Hal ini mengundang serangan brute force massal dan meningkatkan risiko kebocoran data jika terdapat celah kerentanan zero-day pada mesin database.
Solusi Terbaik #
Pertahankan tipe Service database sebagai ClusterIP (hanya dapat diakses internal kluster). Jika tim developer membutuhkan akses debugging darurat, gunakan mekanisme Bastion Host atau port-forwarding terenkripsi melalui VPN / RBAC.
# ✓ SOLUSI: Gunakan port-forward lokal terenkripsi via RBAC Kubernetes
kubectl port-forward svc/postgres-db-service 5432:5432 -n database
# Developer mengakses database secara lokal di 'localhost:5432' via TLS tunnel kubectl
Anti-Pattern 2: Default-Deny Egress Tanpa Membuka Port DNS #
Menerapkan NetworkPolicy default-deny Egress secara ketat pada namespace produksi, tetapi lupa untuk secara spesifik membuka port UDP 53 ke CoreDNS.
Konsekuensi #
Seluruh aplikasi di dalam namespace tersebut akan mengalami CrashLoopBackOff karena gagal melakukan lookup DNS untuk menghubungi database atau API eksternal.
Solusi Terbaik #
Selalu pasang manifes allow-system-dns (seperti contoh di bagian atas artikel) di setiap namespace yang menerapkan default-deny Egress.
Manifes Lengkap Produksi Jaringan Zero-Trust #
Berikut adalah contoh manifes gabungan siap produksi yang mengunci keamanan jaringan microservice checkout-api di dalam namespace e-commerce:
# 1. Aturan DEFAULT-DENY-ALL untuk isolasi awal
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: checkout-default-deny
namespace: e-commerce
spec:
podSelector:
matchLabels:
app: checkout-api
policyTypes:
- Ingress
- Egress
---
# 2. Aturan ALLOW-INGRESS: Hanya izinkan trafik masuk dari gateway-api
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: checkout-allow-ingress
namespace: e-commerce
spec:
podSelector:
matchLabels:
app: checkout-api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: gateway-api
ports:
- protocol: TCP
port: 8080
---
# 3. Aturan ALLOW-EGRESS: Hanya izinkan trafik keluar ke CoreDNS dan Redis database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: checkout-allow-egress
namespace: e-commerce
spec:
podSelector:
matchLabels:
app: checkout-api
policyTypes:
- Egress
egress:
# A. Akses ke CoreDNS (Kube-System Namespace)
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
# B. Akses ke Database Redis (Redis Pod di namespace yang sama)
- to:
- podSelector:
matchLabels:
app: redis-cache
ports:
- protocol: TCP
port: 6379
Checklist Ulasan Jaringan Zero-Trust #
Gunakan checklist berikut untuk memverifikasi keamanan arsitektur jaringan kluster produksi kita:
SEGMENTASI & NETWORKPOLICY:
□ CNI plugin yang digunakan di produksi terverifikasi mendukung NetworkPolicy (e.g. Calico, Cilium).
□ Kebijakan 'default-deny-all' telah diterapkan pada seluruh namespace aplikasi.
□ Aturan 'allow-system-dns' telah dikonfigurasi sukses pada setiap namespace ber-default-deny.
□ Segmentasi trafik antar-namespace multi-tenant berjalan ketat (is-isolated).
ENKRIPSI & OTENTIKASI L7:
□ STRICT mTLS diaktifkan menggunakan Service Mesh (Istio/Linkerd) pada seluruh namespace sensitif.
□ Enkripsi jaringan transportasi (WireGuard/IPSec) diaktifkan di tingkat node-to-node (CNI Level).
□ Koneksi database internal dipastikan menggunakan port SSL/TLS terenkripsi.
PROTEKSI ENDPOINT & CLOUD PORT:
□ Akses keluar Pod ke IP metadata cloud provider (169.254.169.254) diblokir secara eksplisit.
□ Ingress Controller dikonfigurasi dengan aturan rate-limiting RPS dan batas proxy-body-size.
□ HTTP Header keamanan (X-Frame-Options, HSTS, Content-Type-Options) disuntikkan secara dinamis pada Ingress.
Ringkasan #
- Blokir flat network default — Matikan default behavior Kubernetes yang membiarkan semua Pod saling berkomunikasi dengan menerapkan segmentasi NetworkPolicy secara ketat.
- Wajib pasang CNI pengaman — Jangan gunakan Flannel di produksi karena tidak mengevaluasi manifest NetworkPolicy; pilih Calico atau Cilium yang mendukung penegakan firewall kluster.
- Terapkan default-deny-all — Mulai pengamanan jaringan dengan memblokir seluruh Ingress & Egress, kemudian buka akses secara spesifik dan granular untuk meminimalkan human-error.
- Isolasi IP metadata cloud — Lindungi kluster dari serangan pencurian token IAM (SSRF) dengan memblokir akses keluar Pod ke IP link-local cloud provider
169.254.169.254.- Tegakkan STRICT mTLS — Gunakan Service Mesh untuk menjamin lalu lintas data antar-Pod terenkripsi secara otomatis dan terotentikasi menggunakan identitas kriptografis.
- Hardening Ingress annotations — Lindungi perimeter luar kluster dengan mengaktifkan rate limiting, pembatasan payload size, HSTS redirection, dan security HTTP headers pada Ingress.
← Sebelumnya: Pod Security Berikutnya: Supply Chain Security →