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 →

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