K8s 預設網路全通 — 這是個 bug 不是 feature
你做完 RBAC,覺得自己很安全。直到某次 Pen Test 報告:
「滲透測試發現,從 \marketing\namespace 的容器可直接連到 \prod\的 MySQL Pod。」
你打開查看:
\\\bash
# 在 marketing namespace 隨便找個 Pod
kubectl exec -it any-pod -n marketing -- sh
# 直接連得到 prod 的 MySQL!
mysql -h mysql.prod.svc.cluster.local -uroot -p
\\
\
原因:K8s 預設所有 Pod 之間網路全通。這是 K8s 設計上的選擇——簡化網路。但對生產環境,這是個災難。
解法:NetworkPolicy(Pod 等級的防火牆)。
NetworkPolicy 的邏輯
\\\yaml\
spec:
podSelector: # 這條規則套用在「誰」身上
matchLabels: {role: db}
policyTypes:
- Ingress # 管進來的流量
- Egress # 管出去的流量
ingress: # 允許進來的清單
- from: [...]
ports: [...]
egress: # 允許出去的清單
- to: [...]
ports: [...]
\\
關鍵法則:
只要對某個 Pod 套用了 NetworkPolicy,所有沒明確允許的流量都會被拒絕——白名單機制。
名詞警告:跟 Ingress Controller 不一樣
NetworkPolicy 的 \ingress\ 跟第六堂的 \Ingress Controller\ 完全不同!
| NetworkPolicy ingress | Ingress Controller | |
|---|---|---|
| 層級 | L3/L4(IP/Port) | L7(HTTP) |
| 管什麼 | Pod 之間的網路 | 從外面來的 HTTP 請求 |
實作:「只有 API 能連 DB」
最常見的需求:API Pod 可連 DB,但前端 Pod 不能直連。
\\\yaml\
# networkpolicy-db.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-allow-api
namespace: default
spec:
podSelector:
matchLabels:
role: database # 套用在 DB Pod 上
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
role: api # 只允許帶 role=api 的 Pod
ports:
- protocol: TCP
port: 3306
\\
意思是:
我(DB Pod)只接受帶 \role=api\ 的 Pod 連到 TCP 3306。其他通通擋。
驗證流程
\\\bash
kubectl apply -f networkpolicy-db.yaml
# 1. 從 API Pod 連 DB → 應該成功
kubectl exec -it api-xxx -- nc -zv db-svc 3306
# Connection to db-svc 3306 port [tcp/*] succeeded! ✅
# 2. 從前端 Pod 連 DB → 應該失敗
kubectl exec -it frontend-xxx -- nc -zv db-svc 3306
# (timeout 卡住... 表示被擋了) ✅
\\\
三層架構的標準寫法
生產環境最常見的需求:
[Ingress] → [Frontend] → [API] → [DB]
對應的 NetworkPolicy:
| 層 | 規則 |
|---|---|
| Frontend | 只接受來自 Ingress Controller |
| API | 只接受來自 Frontend |
| DB | 只接受來自 API(port 3306) |
常見搭配:先擋全部,再開特定
進階做法是先 \default deny all\:
\\\yaml\
# 先擋掉這個 namespace 所有 ingress
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: prod
spec:
podSelector: {} # 空的 = 全部 Pod
policyTypes:
- Ingress
\\
接著再用獨立的 NetworkPolicy 一個一個放行——白名單最安全。
跨 namespace 的 NetworkPolicy
要允許 \monitoring\ namespace 的 Prometheus 抓 metrics:
\\\yaml\
ingress:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
podSelector:
matchLabels:
app: prometheus
ports:
- protocol: TCP
port: 9090
\\
\namespaceSelector\ + \podSelector\ 並用,限定「monitoring 命名空間裡,只有 Prometheus 那組 Pod」可進。
注意:NetworkPolicy 需要 CNI 支援
NetworkPolicy 是 規範,但實際執行靠 CNI 外掛:
| CNI | 支援 NetworkPolicy |
|---|---|
| Calico | ✅ |
| Cilium | ✅(甚至支援 L7) |
| k3s 預設 | ✅(內建 network policy controller) |
| Flannel(純) | ❌ |
| AWS VPC CNI(基本版) | ❌(要加 Calico) |
重點整理
- K8s 預設全通——這是設計而不是 bug,但生產環境必須補
- NetworkPolicy = Pod 等級防火牆,白名單機制
- podSelector + policyTypes + ingress/egress 三段式
- 名字陷阱:NetworkPolicy 的 ingress ≠ Ingress Controller
- CNI 必須支援——k3s / Calico / Cilium 都行
- 實務做法:先 default-deny-all,再獨立放行
下一步
到目前為止,你學了 K8s 八大概念加上生產維運的 5 個技巧。但是全部串起來呢?
下一篇開始 2 篇實戰:從零部署一套完整服務(上)— 12 步流程的前 6 步
📅 下一篇:從零部署一套完整服務(上)— 12 步流程的前 6 步
把這 40 篇學的全部串起來——前端 + 後端 + DB 完整微服務,12 步從零到生產級。
📚 完整系列總覽:K8s 系列教學首頁(共 40 課,按學習路徑順序排)