Trong k8s, việc kiểm soát luồng traffic giữa các pod rất quan trọng để đảm bảo an toàn và hiệu suất của ứng dụng. Network Policies là một công cụ giúp bạn định nghĩa các quy tắc mạng để kiểm soát việc trao đổi dữ liệu giữa các pod. Trong bài viết này, chúng ta sẽ tìm hiểu về cách hoạt động của network Policies trong kubernetes, cách áp dụng chúng và một số ví dụ cụ thể.
1. Luồng traffic và quy tắc
Khi bạn triển khai các dịch vụ như web server, API server, và database server trong Kubernetes, mỗi dịch vụ cần có các quy tắc mạng riêng để đảm bảo chỉ những dịch vụ được phép giao tiếp với nhau.
Ví dụ về các quy tắc mạng giữa các server:
- Ingress (Traffic đến): Quy tắc cho phép web server nhận traffic HTTP trên cổng 80.
- Egress (Traffic đi): Quy tắc cho phép web server gửi traffic tới API server trên cổng 5000.
- Ingress cho API server: Cho phép API server nhận traffic trên cổng 5000.
- Egress cho API server: Cho phép API server gửi traffic tới database server trên cổng 3306.
- Ingress cho database server: Cho phép database server nhận traffic trên cổng 3306.

2. Mạng trong Kubernetes
Trong Kubernetes, mạng được cấu thành bởi các thành phần như node, pod, và service. Mỗi node, pod, và service đều có địa chỉ IP riêng biệt. Các pod giao tiếp với nhau thông qua một mạng riêng ảo (Virtual Private Network) mà không cần cấu hình thêm.
Mặc định, Kubernetes cho phép tất cả traffic giữa các pod và service mà không có bất kỳ hạn chế nào (tất cả đều được phép).
3. Network Policies trong Kubernetes
Network Policies là các đối tượng trong Kubernetes cho phép người dùng kiểm soát luồng traffic giữa các pod. Ví dụ, bạn có thể tạo một chính sách mạng để chặn web server truy cập trực tiếp vào database server.
3.1 Cách hoạt động của Network Policies
Một Network Policy sẽ được tạo trong một namespace cụ thể trong Kubernetes, tương tự như pod, replica set, hay service.
- Nhãn (Label) và Bộ chọn (Selector) được sử dụng để liên kết chính sách mạng với các pod.
- Network Policies cho phép người dùng định nghĩa các quy tắc, ví dụ: chỉ cho phép ingress traffic từ API server đến database server trên cổng 3306.
- Sau khi tạo, Network Policy sẽ chặn tất cả traffic không hợp lệ, chỉ cho phép traffic đáp ứng các quy tắc đã được định nghĩa.
3.2 Cách áp dụng Network Policies
- Nhãn và Bộ chọn: Network Policy có thể liên kết với pod qua nhãn và bộ chọn để xác định các pod cụ thể mà chính sách sẽ áp dụng.
- Quy Tắc (Rules): Các quy tắc trong Network Policy có thể bao gồm ingress (traffic đến), egress (traffic đi), và port (cổng giao tiếp).
Ví dụ: Bảo vệ Pod Database
Giả sử chúng ta muốn bảo vệ database pod, chỉ cho phép API pod truy cập vào cổng 3306 của nó. Cách thực hiện như sau:
- Tạo Network Policy với tên
db-policy. - Liên kết Network Policy với database pod thông qua nhãn
role=dbvà bộ chọnmatchLabels. - Thêm Ingress:
- Quy tắc ingress trong Network Policy sẽ định nghĩa từ pod nào (sử dụng
podSelectorcho API pod) và cổng nào (port 3306 với giao thức TCP) được phép truy cập.
- Quy tắc ingress trong Network Policy sẽ định nghĩa từ pod nào (sử dụng
Các Loại Selector trong from:
Có ba loại selector trong trường from của ingress:
- podSelector: Chọn pod dựa trên nhãn.
- namespaceSelector: Chọn namespace dựa trên nhãn.
- ipBlock: Chọn dải IP.
Những selector này có thể được sử dụng riêng lẻ hoặc kết hợp để tạo các quy tắc chi tiết hơn.
4. Network Policies và các giải pháp mạng
Các giải pháp mạng trong Kubernetes, như Calico, Cube Router, Romana, và WaveNet, hỗ trợ Network Policies, giúp triển khai và áp dụng các chính sách này. Tuy nhiên, một số giải pháp mạng như Flannel không hỗ trợ Network Policies.
Lưu ý: Bạn vẫn có thể tạo Network Policies ngay cả khi giải pháp mạng không hỗ trợ, nhưng chúng sẽ không được áp dụng. Việc cấu hình các chính sách mạng cần thận trọng để không ảnh hưởng đến kết nối và chức năng của ứng dụng.
Ví dụ về Network Policy:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: internal-policy
namespace: default
spec:
podSelector:
matchLabels:
name: internal
policyTypes:
- Egress
- Ingress
ingress:
- {}
egress:
- to:
- podSelector:
matchLabels:
name: mysql
ports:
- protocol: TCP
port: 3306
- to:
- podSelector:
matchLabels:
name: payroll
ports:
- protocol: TCP
port: 8080
- ports:
- port: 53
protocol: UDP
- port: 53
protocol: TCP
5. Hand-On Network Policy
Kịch bản
Giả sử chúng ta đang có một hệ thống gồm:
- Namespace
frontendchạy Nginx (web server). - Namespace
backendchạy MongoDB (database). - Namespace
defaultdùng để test.

Theo mặc định, nếu không cấu hình Network Policy thì tất cả các Pod trong tất cả namespace đều có thể giao tiếp với nhau. Điều này tiềm ẩn rủi ro bảo mật.
Mục tiêu của bài này là:
- Chỉ cho phép Pod trong frontend (Nginx) truy cập vào backend (MongoDB).
- Chặn toàn bộ các Pod từ namespace khác (như default) truy cập vào backend.
- Namespace default vẫn có thể truy cập frontend (ví dụ truy cập web).
Hướng dẫn chi tiết
Bước 1: Tạo namespace
Chúng ta chia môi trường Kubernetes thành 2 không gian riêng biệt là frontend và backend.
kubectl create namespace frontend
kubectl create namespace backend
truongnt@masternode:~$ kubectl create namespace frontend namespace/frontend created truongnt@masternode:~$ kubectl create namespace backend namespace/backend created
Bước 2: Gắn nhãn cho namespace frontend
Gắn nhãn cho namespace giúp chúng ta sau này lọc hoặc áp dụng policy dễ dàng hơn.
kubectl label namespace frontend name=frontend
truongnt@masternode:~$ kubectl label namespace frontend namspace=frontend namespace/frontend labeled
Bước 3: Tạo deployment cho frontend (nginx)
Triển khai nginx trong namespace frontend
kubectl -n frontend create deployment frontend --image=nginx --port=80
kubectl -n frontend get deployments.apps
kubectl -n frontend get pods --watch
truongnt@masternode:~$ kubectl -n frontend create deployment frontend --image nginx --port 80 deployment.apps/frontend created truongnt@masternode:~$ kubectl -n frontend get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE frontend 1/1 1 1 19s truongnt@masternode:~$ kubectl -n frontend get pods --watch NAME READY STATUS RESTARTS AGE frontend-6df94c895b-5dh6f 1/1 Running 0 41s
Bước 4: Tạo deployment cho backend (MongoDB)
kubectl -n backend create deployment backend --image=mongo --port=27017
kubectl -n backend get deployments.apps
kubectl -n backend get pods --watch
truongnt@masternode:~$ kubectl -n backend create deployment backend --image mongo --port 27017 deployment.apps/backend created truongnt@masternode:~$ kubectl -n backend get deployments.apps NAME READY UP-TO-DATE AVAILABLE AGE backend 1/1 1 1 18s truongnt@masternode:~$ kubectl -n backend get pods NAME READY STATUS RESTARTS AGE backend-5fc6bb6f65-sdwft 1/1 Running 0 32s
Bước 5: Lấy tên và IP của các Pod
FRONTENDPODNAME=`kubectl -n frontend get pods -o jsonpath='{.items[0].metadata.name}'`
echo $FRONTENDPODNAME
BACKENDPODNAME=`kubectl -n backend get pods -o jsonpath='{.items[0].metadata.name}'`
echo $BACKENDPODNAME
FRONTENDPODIP=`kubectl -n frontend get pods -o jsonpath='{.items[0].status.podIP}'`
echo $FRONTENDPODIP
BACKENDPODIP=`kubectl -n backend get pods -o jsonpath='{.items[0].status.podIP}'`
echo $BACKENDPODIP
truongnt@masternode:~$ FRONTENDPODNAME=`kubectl -n frontend get pods -o jsonpath='{.items[0].metadata.name}'`
truongnt@masternode:~$ echo $FRONTENDPODNAME
frontend-6df94c895b-5dh6f
truongnt@masternode:~$ BACKENDPODNAME=`kubectl -n backend get pods -o jsonpath='{.items[0].metadata.name}'`
truongnt@masternode:~$ echo $BACKENDPODNAME
backend-5fc6bb6f65-sdwft
truongnt@masternode:~$ FRONTENDPODIP=`kubectl -n frontend get pods -o jsonpath='{.items[0].status.podIP}'`
truongnt@masternode:~$ echo $FRONTENDPODIP
192.168.166.129
truongnt@masternode:~$ BACKENDPODIP=`kubectl -n backend get pods -o jsonpath='{.items[0].status.podIP}'`
truongnt@masternode:~$ echo $BACKENDPODIP
192.168.104.1
Bước 7: Cài mongo shell trong frontend pod
kubectl -n frontend exec $FRONTENDPODNAME --stdin --tty -- sh
curl -O https://downloads.mongodb.com/compass/mongosh-2.5.3-linux-x64.tgz
tar -xvzf mongosh-2.5.3-linux-x64.tgz
cd mongosh-2.5.3-linux-x64
cp bin/mongosh /usr/local/bin/
mongosh --version
exit
truongnt@masternode:~$ kubectl -n frontend exec $FRONTENDPODNAME --stdin --tty -- sh # mongosh --version
Bước 8: Kết nối thử từ các pod
kubectl run nginx --image=nginx
kubectl -n frontend exec $FRONTENDPODNAME --stdin --tty -- mongosh $BACKENDPODIP
exit
kubectl exec nginx --stdin --tty -- mongosh $BACKENDPODIP
exit
Bước 9: Tạo file NetworkPolicy
Tạo file tên networkpolicy-ingress.yaml với nội dung sau:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: backend
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
podSelector:
matchLabels:
app: frontend
Bước 10: Áp dụng NetworkPolicy
kubectl create -f networkpolicy-ingress.yaml
kubectl get netpol -A
Bước 11: Kiểm tra kết nối sau khi áp dụng policy
kubectl -n frontend exec $FRONTENDPODNAME --stdin --tty -- mongosh $BACKENDPODIP
kubectl exec nginx --stdin --tty -- mongosh $BACKENDPODIP
kubectl exec nginx --stdin --tty -- curl $FRONTENDPODIP
Sau bước này bạn sẽ thấy chỉ có Pod frontend mới truy cập được backend, còn nginx (nằm ngoài namespace frontend) sẽ bị chặn — chính là nhờ NetworkPolicy đó!