Network Policy #
Secara default, semua Pod di Kubernetes bisa berkomunikasi dengan semua Pod lain — tidak ada firewall antar Pod. Untuk cluster yang menjalankan workload dengan tingkat kepercayaan berbeda, ini adalah risiko keamanan yang nyata. NetworkPolicy adalah mekanisme Kubernetes untuk mendefinisikan aturan traffic yang diizinkan: Pod mana yang boleh berkomunikasi dengan siapa, melalui port apa, dari namespace mana.
Default: Semua Boleh Bicara dengan Semua #
Tanpa NetworkPolicy, model jaringan Kubernetes adalah open — setiap Pod bisa menghubungi Pod lain di seluruh cluster tanpa batasan.
Tanpa NetworkPolicy:
Namespace: production Namespace: staging
┌──────────────────┐ ┌──────────────────┐
│ Pod: api │ │ Pod: test-app │
│ Pod: database │ │ Pod: load-tester │
│ Pod: cache │ └──────────────────┘
└──────────────────┘
test-app → database (production) → ✓ BISA (tidak ada yang melarang)
load-tester → cache (production) → ✓ BISA
Ini bermasalah jika test-app bisa langsung akses database produksi.
Cara Kerja NetworkPolicy #
NetworkPolicy menggunakan label selector untuk menentukan Pod mana yang dikenai policy, dan aturan ingress/egress untuk menentukan traffic yang diizinkan.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-policy
namespace: production
spec:
podSelector: # policy ini berlaku untuk Pod dengan label ini
matchLabels:
app: api
policyTypes:
- Ingress # atur traffic masuk ke Pod ini
- Egress # atur traffic keluar dari Pod ini
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # hanya Pod berlabel app=frontend yang boleh masuk
ports:
- port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database # Pod ini hanya boleh keluar ke Pod berlabel app=database
ports:
- port: 5432
Penting: NetworkPolicy bersifat additive — jika ada beberapa policy yang berlaku untuk satu Pod, semua aturan di-OR. Tidak ada aturan yang saling menimpa.
Default Deny: Blokir Semua, Izinkan yang Perlu #
Pattern paling aman adalah default deny — blokir semua traffic, lalu buka secara selektif hanya yang dibutuhkan.
# Default deny semua ingress ke semua Pod di namespace ini
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # berlaku untuk SEMUA Pod di namespace ini
policyTypes:
- Ingress
# Tidak ada aturan ingress yang didefinisikan = semua ingress ditolak
# Default deny semua egress dari semua Pod
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
# Tidak ada aturan egress = semua egress ditolak
# Default deny semua ingress dan egress sekaligus
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Setelah default deny diterapkan, buat policy terpisah untuk membuka traffic yang memang dibutuhkan.
Pola: Isolasi per Tier #
Arsitektur tiga tier (frontend, backend, database) bisa di-isolasi dengan NetworkPolicy:
# Database hanya bisa diakses oleh backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database-isolation
namespace: production
spec:
podSelector:
matchLabels:
tier: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
tier: backend # hanya backend yang boleh hubungi database
ports:
- port: 5432
---
# Backend bisa diakses oleh frontend dan tidak bisa hubungi internet
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: backend-policy
namespace: production
spec:
podSelector:
matchLabels:
tier: backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
tier: frontend
ports:
- port: 8080
egress:
- to:
- podSelector:
matchLabels:
tier: database
ports:
- port: 5432
- to: # izinkan DNS lookup
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
Namespace Selector #
NetworkPolicy bisa membatasi atau mengizinkan traffic berdasarkan namespace:
ingress:
- from:
# Izinkan dari Pod di namespace "monitoring" yang berlabel app=prometheus
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector:
matchLabels:
app: prometheus
# ATAU: izinkan dari namespace apapun yang berlabel env=trusted
- namespaceSelector:
matchLabels:
env: trusted
Perhatikan perbedaan antara AND (gabungkan dalam satu item) dan OR (item terpisah):
# AND: Pod harus ada di namespace "monitoring" DAN berlabel app=prometheus
- from:
- namespaceSelector:
matchLabels:
name: monitoring
podSelector:
matchLabels:
app: prometheus
# OR: Pod dari namespace "monitoring" ATAU Pod berlabel app=prometheus (dari mana saja)
- from:
- namespaceSelector:
matchLabels:
name: monitoring
- podSelector:
matchLabels:
app: prometheus
Izinkan DNS dan Monitoring #
Dua hal yang hampir selalu perlu dibuka dalam policy restrictive:
egress:
# DNS: wajib untuk semua Pod yang butuh resolusi nama
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
# Monitoring: Prometheus perlu akses ke semua Pod untuk scrape metrics
# (ini biasanya dibuka via ingress policy di Pod target, bukan di Prometheus)
- to:
- podSelector:
matchLabels:
app: metrics-endpoint
ports:
- port: 9090
Jika kamu menerapkan default-deny-egress tapi lupa membuka port 53 (DNS), Pod tidak bisa melakukan name resolution sama sekali. Ini adalah penyebab paling umum dari aplikasi yang “tiba-tiba tidak bisa connect ke service apapun” setelah NetworkPolicy diterapkan.
Keterbatasan NetworkPolicy #
NetworkPolicy punya keterbatasan yang perlu dipahami:
Yang BISA dilakukan NetworkPolicy:
✓ Filter berdasarkan Pod label (podSelector)
✓ Filter berdasarkan namespace (namespaceSelector)
✓ Filter berdasarkan port dan protokol
✓ Filter berdasarkan CIDR range (ipBlock)
Yang TIDAK BISA dilakukan NetworkPolicy:
✗ Filter berdasarkan DNS name (tidak bisa blokir "api.external.com")
✗ Layer 7 filtering (tidak bisa filter berdasarkan HTTP path/method)
✗ Logging traffic yang diizinkan atau ditolak (butuh CNI khusus)
✗ Prioritas antar policy (semua policy di-OR, tidak ada ordering)
Untuk kebutuhan lebih canggih (Layer 7 filtering, logging, audit), gunakan service mesh (Istio, Cilium) atau tool khusus.
Ringkasan #
- Default: semua Pod bisa bicara dengan semua Pod — tanpa NetworkPolicy, tidak ada firewall antar Pod; ini risiko keamanan di cluster multi-tenant atau produksi.
- NetworkPolicy bersifat additive — beberapa policy untuk satu Pod di-OR; tidak ada saling menimpa atau prioritas.
- Default-deny dulu, buka yang perlu — pola paling aman: buat policy
podSelector: {}tanpa rules untuk deny semua, lalu tambahkan policy yang membuka traffic spesifik.- Selalu izinkan DNS (port 53) — lupa membuka DNS saat default-deny egress diterapkan adalah kesalahan paling umum; aplikasi tidak bisa connect ke apapun tanpa DNS.
- AND vs OR dalam from/to selector — gabungkan namespaceSelector dan podSelector dalam satu item untuk AND; pisahkan ke item berbeda untuk OR.
- NetworkPolicy butuh CNI yang mendukung — Calico, Cilium, Weave mendukung NetworkPolicy; Flannel saja tidak mendukung tanpa plugin tambahan.
← Sebelumnya: Ingress Berikutnya: Load Balancing & kube-proxy →