Home > Blog > tech

Kubernetes Network Policy คืออะไร? สอนสร้าง Firewall Rules ภายใน K8s Cluster 2026

kubernetes network policy guide
Kubernetes Network Policy Firewall Rules Guide 2026
2026-04-16 | tech | 3600 words

ใน Kubernetes Cluster แบบ Default ทุก Pod สามารถคุยกับทุก Pod ได้ ไม่ว่าจะอยู่ Namespace ไหนก็ตาม นี่คือปัญหาด้าน Security ที่ใหญ่มาก เพราะถ้า Attacker เจาะเข้า Pod เดียวได้ จะสามารถเข้าถึง Database, Internal APIs และ Service อื่น ๆ ทั้งหมดได้ทันที

Network Policy คือ Kubernetes Resource ที่ทำหน้าที่เป็น Firewall Rules ภายใน Cluster ควบคุมว่า Pod ไหนสามารถคุยกับ Pod ไหนได้ ทั้ง Ingress (ขาเข้า) และ Egress (ขาออก)

Network Policy Spec — โครงสร้างที่ต้องรู้

# โครงสร้าง Network Policy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: policy-name
  namespace: default
spec:
  # 1. podSelector: เลือก Pod ที่จะถูก Apply Policy นี้
  podSelector:
    matchLabels:
      app: backend

  # 2. policyTypes: ประเภท Policy (Ingress, Egress, หรือทั้งคู่)
  policyTypes:
    - Ingress
    - Egress

  # 3. ingress: กฎสำหรับ Traffic ขาเข้า
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

  # 4. egress: กฎสำหรับ Traffic ขาออก
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: database
      ports:
        - protocol: TCP
          port: 5432

Components สำคัญ

Componentหน้าที่ตัวอย่าง
podSelectorเลือก Pod ที่จะถูก Apply PolicymatchLabels: app: backend
policyTypesประเภท Policy[Ingress, Egress]
ingress.fromอนุญาต Traffic จากไหนpodSelector, namespaceSelector, ipBlock
egress.toอนุญาต Traffic ไปไหนpodSelector, namespaceSelector, ipBlock
portsPort ที่อนุญาตport: 8080, protocol: TCP

Default Deny Policy — ต้องมี!

สำคัญมาก: ถ้าไม่มี Network Policy ใน Namespace → ทุก Pod คุยกันได้หมด! ต้องสร้าง Default Deny Policy เป็นอันดับแรก

Default Deny All Ingress

# default-deny-ingress.yaml
# บล็อก Traffic ขาเข้าทั้งหมด (ยกเว้นที่ Allow ไว้)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: production
spec:
  podSelector: {}    # เลือกทุก Pod ใน namespace
  policyTypes:
    - Ingress
  # ไม่มี ingress rules = ปฏิเสธทุก ingress traffic

Default Deny All Egress

# default-deny-egress.yaml
# บล็อก Traffic ขาออกทั้งหมด
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress
  # ไม่มี egress rules = ปฏิเสธทุก egress traffic
  # ระวัง: DNS จะใช้ไม่ได้ด้วย!

Default Deny All (Ingress + Egress)

# default-deny-all.yaml
# บล็อกทั้ง Ingress และ Egress ทั้งหมด
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress

# Apply:
# kubectl apply -f default-deny-all.yaml
# ทุก Pod ใน namespace production จะไม่สามารถรับหรือส่ง traffic ได้เลย
# ต้องสร้าง Allow Policy เพิ่มสำหรับ traffic ที่ต้องการ

Allow Specific Ingress

Allow Frontend → Backend

# allow-frontend-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend           # Apply กับ Pod ที่มี label app=backend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend   # อนุญาตจาก Pod ที่มี label app=frontend
      ports:
        - protocol: TCP
          port: 8080          # เฉพาะ port 8080

# ผลลัพธ์:
# ✅ frontend → backend:8080   (ALLOW)
# ❌ redis → backend:8080      (DENY)
# ❌ frontend → backend:3000   (DENY - ผิด port)
# ❌ external → backend:8080   (DENY)

Allow Backend → Database

# allow-backend-to-database.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-to-database
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: backend
      ports:
        - protocol: TCP
          port: 5432          # PostgreSQL
        - protocol: TCP
          port: 3306          # MySQL

Allow Specific Egress

Allow DNS (จำเป็นเสมอ!)

# allow-dns-egress.yaml
# ถ้าใช้ Default Deny Egress ต้อง Allow DNS ด้วย!
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns-egress
  namespace: production
spec:
  podSelector: {}     # ทุก Pod
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector: {}      # ทุก Namespace
          podSelector:
            matchLabels:
              k8s-app: kube-dns       # CoreDNS
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

Allow Backend → External API

# allow-backend-external-api.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-external-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
    - Egress
  egress:
    # Allow DNS
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
    # Allow HTTPS ไปยัง External API
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0    # ทุก IP ภายนอก
            except:
              - 10.0.0.0/8     # ยกเว้น Private IP
              - 172.16.0.0/12
              - 192.168.0.0/16
      ports:
        - protocol: TCP
          port: 443            # HTTPS only

Namespace Isolation

# namespace-isolation.yaml
# แยก Namespace ออกจากกัน (Production ↔ Staging ไม่คุยกัน)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-other-namespaces
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        # อนุญาตเฉพาะ Pod ใน Namespace เดียวกัน
        - podSelector: {}

---
# Allow จาก Namespace ที่กำหนด (เช่น monitoring)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-monitoring
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Ingress
  ingress:
    - from:
        # อนุญาตจาก monitoring namespace
        - namespaceSelector:
            matchLabels:
              name: monitoring
      ports:
        - protocol: TCP
          port: 9090           # Prometheus metrics

Label-based Policies

# ใช้ Labels เพื่อควบคุมการเข้าถึงแบบยืดหยุ่น
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-by-tier
  namespace: production
spec:
  podSelector:
    matchLabels:
      tier: backend           # Apply กับทุก Pod ที่เป็น tier=backend
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              tier: frontend  # อนุญาตจากทุก Pod ที่เป็น tier=frontend
        - podSelector:
            matchLabels:
              tier: api-gateway  # และจาก api-gateway
      ports:
        - protocol: TCP
          port: 8080

# Labels ที่แนะนำ:
# tier: frontend / backend / database / cache
# env: production / staging / development
# team: platform / backend / frontend
# app: web / api / worker / scheduler

CIDR-based Policies

# allow-specific-cidr.yaml
# อนุญาตเฉพาะ IP Range ที่กำหนด
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-office-ingress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: admin-panel
  policyTypes:
    - Ingress
  ingress:
    - from:
        - ipBlock:
            cidr: 203.150.100.0/24    # Office IP range
        - ipBlock:
            cidr: 110.164.200.0/24    # VPN IP range
      ports:
        - protocol: TCP
          port: 443

Network Policy กับ Calico (Advanced)

Calico GlobalNetworkPolicy

# Calico GlobalNetworkPolicy — Apply ทุก Namespace!
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: deny-all-external
spec:
  selector: all()
  types:
    - Ingress
    - Egress
  ingress:
    - action: Allow
      source:
        selector: all()
  egress:
    - action: Allow
      destination:
        selector: all()
    # Allow DNS
    - action: Allow
      protocol: UDP
      destination:
        ports: [53]
    - action: Allow
      protocol: TCP
      destination:
        ports: [53]
  # ผลลัพธ์: Pod คุยกัน ภายใน Cluster ได้
  # แต่ไม่สามารถ connect ออก internet ได้

Calico DNS Policy

# calico-dns-policy.yaml
# ควบคุม DNS queries (Calico Only!)
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-specific-dns
  namespace: production
spec:
  selector: app == 'backend'
  egress:
    - action: Allow
      protocol: UDP
      destination:
        selector: k8s-app == 'kube-dns'
        ports: [53]
    - action: Allow
      protocol: TCP
      destination:
        selector: k8s-app == 'kube-dns'
        ports: [53]
  types:
    - Egress

Testing Network Policies — ด้วย netshoot Pod

# สร้าง Test Pod ด้วย netshoot (มี Tools ครบ)
kubectl run netshoot --rm -it --image=nicolaka/netshoot   --labels="app=test" -- bash

# ภายใน netshoot pod:

# 1. ทดสอบ TCP connection
nc -zv backend-service 8080
# Connection to backend-service 8080 port [tcp/*] succeeded!

# 2. ทดสอบ HTTP
curl -v http://backend-service:8080/health
# → ถ้าถูก Block จะ timeout

# 3. ทดสอบ DNS
nslookup backend-service.production.svc.cluster.local

# 4. ทดสอบ External connectivity
curl -v https://api.example.com
# → ถ้า Egress ถูก Block จะ timeout

# 5. ทดสอบจาก Namespace อื่น
kubectl run netshoot -n staging --rm -it   --image=nicolaka/netshoot --labels="app=test" --   curl -v http://backend-service.production:8080
# → ถ้า Namespace isolation ทำงาน จะ timeout

# 6. Traceroute
traceroute backend-service

# 7. ดู Network Policy ที่ Apply อยู่
kubectl get networkpolicies -n production
kubectl describe networkpolicy allow-frontend-to-backend -n production

Common Patterns — Frontend → Backend → DB

# Complete 3-Tier Network Policy Setup
#
# Architecture:
# Internet → Ingress Controller → Frontend → Backend → Database
#
# Rules:
# 1. Default Deny ทุกอย่าง
# 2. Allow Ingress Controller → Frontend (port 3000)
# 3. Allow Frontend → Backend (port 8080)
# 4. Allow Backend → Database (port 5432)
# 5. Allow DNS สำหรับทุก Pod
# 6. Deny everything else

---
# 1. Default Deny All
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes: [Ingress, Egress]

---
# 2. Allow DNS (ทุก Pod)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes: [Egress]
  egress:
    - to:
        - namespaceSelector: {}
          podSelector:
            matchLabels:
              k8s-app: kube-dns
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

---
# 3. Allow Ingress → Frontend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-ingress-to-frontend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes: [Ingress]
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              name: ingress-nginx
      ports:
        - protocol: TCP
          port: 3000

---
# 4. Allow Frontend → Backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

---
# 5. Allow Backend → Frontend (egress)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-egress
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: frontend
  policyTypes: [Egress]
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: backend
      ports:
        - protocol: TCP
          port: 8080

---
# 6. Allow Backend → Database
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-to-db
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes: [Ingress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: backend
      ports:
        - protocol: TCP
          port: 5432

---
# 7. Allow Backend Egress to DB
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-backend-egress-db
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes: [Egress]
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: database
      ports:
        - protocol: TCP
          port: 5432

Troubleshooting Network Policy

ปัญหาสาเหตุที่พบบ่อยวิธีแก้
Pod ไม่สามารถ resolve DNSEgress deny block DNSเพิ่ม Allow DNS egress policy (port 53)
Policy ไม่มีผลCNI ไม่รองรับ Network Policyใช้ Calico, Cilium, Weave Net (ไม่ใช่ Flannel)
Pod timeout เมื่อ connectIngress/Egress ถูก denyตรวจ labels ว่าตรงกับ selector ไหม
Cross-namespace ไม่ได้ต้องใช้ namespaceSelectorเพิ่ม namespaceSelector ใน policy
ทุกอย่างถูก blockDefault deny แต่ไม่มี allowสร้าง allow policy ก่อน apply deny
Policy apply แล้วไม่เห็นผลLabels ไม่ตรงkubectl get pods --show-labels
# Debugging Commands:
# ดู Network Policies
kubectl get networkpolicies -n production -o wide
kubectl describe networkpolicy POLICY_NAME -n production

# ดู Pod Labels
kubectl get pods -n production --show-labels

# ดู Namespace Labels
kubectl get namespaces --show-labels

# ทดสอบ Connection
kubectl run test --rm -it --image=busybox -- wget -qO- --timeout=5 http://SERVICE:PORT

# Calico: ดู Policy ที่ Apply กับ Pod
calicoctl get workloadendpoint -n production
calicoctl get networkpolicy -n production -o yaml

Network Policy Limitations

ข้อจำกัดรายละเอียดทางเลือก
L3/L4 เท่านั้นควบคุมได้แค่ IP + Port ไม่ได้ดู HTTP Path/Headerใช้ Cilium L7 Policy หรือ Service Mesh (Istio)
ไม่มี Deny Ruleมีแค่ Allow (default deny ผ่าน empty selector)Calico มี Action: Deny
ไม่ Log Trafficไม่มี Logging built-inCalico/Cilium มี Flow Logs
CNI Supportไม่ทุก CNI รองรับ (Flannel ไม่รองรับ)ใช้ Calico หรือ Cilium
No DNS Filteringไม่สามารถ filter DNS domainCilium มี DNS-aware Policy

Cilium NetworkPolicy Extensions

# Cilium L7 Policy — ควบคุมระดับ HTTP!
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-api-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: "8080"
              protocol: TCP
          rules:
            http:
              - method: "GET"
                path: "/api/v1/.*"    # Allow GET /api/v1/*
              - method: "POST"
                path: "/api/v1/orders" # Allow POST /api/v1/orders
              # ทุก method/path อื่น → DENY!

---
# Cilium DNS-aware Policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: dns-aware-egress
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: backend
  egress:
    - toEndpoints:
        - matchLabels:
            k8s:io.kubernetes.pod.namespace: kube-system
            k8s-app: kube-dns
      toPorts:
        - ports:
            - port: "53"
              protocol: ANY
          rules:
            dns:
              - matchPattern: "*.example.com"  # Allow DNS query เฉพาะ *.example.com
    - toFQDNs:
        - matchName: "api.example.com"
      toPorts:
        - ports:
            - port: "443"
              protocol: TCP

สรุป

Network Policy เป็นสิ่งที่ ทุก Production Kubernetes Cluster ต้องมี เริ่มจาก Default Deny ทั้ง Ingress และ Egress แล้วค่อย ๆ เปิด Allow เฉพาะ Traffic ที่จำเป็น อย่าลืม Allow DNS Egress (port 53) เพราะถ้าไม่มี Pod จะ resolve DNS ไม่ได้เลย

สำหรับ Advanced use case ที่ต้องการ L7 Policy (HTTP Path/Method), DNS-aware filtering หรือ Flow Logging ให้ใช้ Calico หรือ Cilium แทน Built-in Network Policy ของ Kubernetes ที่รองรับแค่ L3/L4


Back to Blog | iCafe Forex | SiamLanCard | Siam2R