Network Policy
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”โดย default ทุก Pod ใน cluster คุยกับ Pod อื่นได้หมด และ NetworkPolicy คือสิ่งที่ให้คุณจำกัดให้เหลือแค่ traffic ที่อนุญาตไว้อย่างชัดเจนเท่านั้น
ค่า default: network แบบแบนราบและเปิดหมด
หัวข้อที่มีชื่อว่า “ค่า default: network แบบแบนราบและเปิดหมด”ตั้งแต่แกะกล่องมา networking ของ Kubernetes ไม่มี isolation เลย Pod ไหนก็ส่ง traffic ไปหา Pod อื่นได้หมด ไม่ว่าจะอยู่ namespace ไหน และแล้วแต่วิธี expose Service Pod ก็มักถูกเข้าถึงจากนอก cluster ได้ด้วย ไม่มี default-deny อยู่ที่ไหนเลย เรื่องนี้เข้าใจง่ายแต่หมายความว่า Pod ที่ถูก compromise หรือ config ผิดสามารถเข้าถึงส่วนอื่นของ cluster ได้มากกว่าที่ควรต้องการเยอะ
NetworkPolicy: เลือก Pod ก่อน แล้วค่อยอนุญาต traffic
หัวข้อที่มีชื่อว่า “NetworkPolicy: เลือก Pod ก่อน แล้วค่อยอนุญาต traffic”NetworkPolicy (API group networking.k8s.io/v1) เลือกกลุ่ม Pod ด้วย podSelector แล้วกำหนด rule ingress และ/หรือ egress ที่อนุญาตให้เฉพาะ Pod พวกนั้น
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-frontend-to-api namespace: shopspec: podSelector: matchLabels: app: api policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080policy นี้มีผลแค่กับ Pod ที่ label app: api ใน namespace shop และอนุญาต inbound traffic แค่จาก Pod ที่ label app: frontend เท่านั้น บน TCP port 8080 เท่านั้น อย่างอื่นทั้งหมดที่ยิงเข้า Pod พวกนี้ถูก deny โดยปริยายทันทีที่มีอย่างน้อยหนึ่ง policy เลือก Pod เหล่านั้น
kubectl get networkpolicy -n shopkubectl describe networkpolicy allow-frontend-to-api -n shopNetworkPolicy จะทำงานก็ต่อเมื่อ CNI บังคับใช้จริง
หัวข้อที่มีชื่อว่า “NetworkPolicy จะทำงานก็ต่อเมื่อ CNI บังคับใช้จริง”นี่คือข้อควรระวังที่สำคัญที่สุด NetworkPolicy object เฉย ๆ ไม่มีผลอะไรเลยถ้า CNI plugin ของ cluster ไม่ได้ implement การบังคับใช้ NetworkPolicy จริง Kubernetes รับและเก็บ object นี้ได้เสมอ kubectl apply จะสำเร็จ แต่ถ้า CNI ไม่บังคับใช้ policy traffic จริงก็ไม่เปลี่ยนอะไรเลย ต้องเช็คก่อนเสมอว่า CNI ที่ติดตั้งอยู่รองรับ NetworkPolicy ก่อนจะพึ่ง NetworkPolicy เพื่อทำ isolation
รูปแบบ default-deny
หัวข้อที่มีชื่อว่า “รูปแบบ default-deny”จุดที่คนสับสนกันบ่อย Pod ที่ไม่มี NetworkPolicy ตัวไหนเลือกเลย จะยังคงเปิดเต็มที่ (allow-all) สำหรับทิศทาง traffic นั้น isolation เป็นแบบ opt-in ต่อ Pod ไม่ใช่ทั้ง cluster ถ้าจะปิด namespace หนึ่งให้แน่นหนา ต้องสร้าง policy ที่เลือก Pod ทุกตัวแต่ไม่อนุญาตอะไรเลยโดยตั้งใจ
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-ingress namespace: shopspec: podSelector: {} policyTypes: - Ingress ingress: []podSelector: {} match ทุก Pod ใน namespace และ ingress: [] ที่ว่างเปล่าไม่อนุญาตอะไรเข้ามาเลย พอ policy นี้มีอยู่ ทุก Pod ใน shop จะถูก isolate ด้าน ingress โดย default แล้วคุณค่อยเพิ่ม NetworkPolicy object อื่นเข้าไปเพื่ออนุญาต traffic ที่ต้องการจริง ๆ แบบเจาะจง เช่นตัวอย่าง allow-frontend-to-api ด้านบน
รวม podSelector กับ namespaceSelector เข้าด้วยกัน
หัวข้อที่มีชื่อว่า “รวม podSelector กับ namespaceSelector เข้าด้วยกัน”การใส่ทั้ง podSelector และ namespaceSelector ไว้ใน entry from เดียวกัน จะจำกัด rule ให้แคบลงเหลือแค่ Pod เจาะจงใน namespace เจาะจงเท่านั้น ไม่ใช่ “Pod ไหนก็ได้ใน namespace นี้” หรือ “label นี้ที่ไหนก็ได้ในทั้ง cluster”
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-monitoring-scrape namespace: shopspec: podSelector: matchLabels: app: api policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: monitoring podSelector: matchLabels: app: prometheus ports: - protocol: TCP port: 9090rule นั้นอนุญาต traffic เฉพาะจาก Pod ที่ label app: prometheus และรันอยู่ใน namespace monitoring เท่านั้น เป็น rule ควบคุมการเข้าถึงข้าม namespace ที่เจาะจงมาก
flowchart LR
subgraph before["Before: default flat network"]
a1["Pod A"] --- a2["Pod B"]
a2 --- a3["Pod C"]
a1 --- a3
end
subgraph after["After: NetworkPolicy applied"]
b1["frontend"] -->|"allowed"| b2["api"]
b3["random Pod"] -.->|"blocked"| b2
end