16.4.5 网络策略与安全隔离
5. 网络策略与安全隔离#
网络策略用于在 Kubernetes 中实现命名空间级与 Pod 级的精细化流量控制,依赖支持 NetworkPolicy 的 CNI(如 Calico、Cilium)。其核心目标是最小权限通信、分区隔离、限制横向移动,并与组织安全基线保持一致。
原理草图(流量与策略关系)
网络策略基础模型
- 选择器:通过 podSelector 与 namespaceSelector 匹配对象范围。
- 方向:Ingress 与 Egress,分别控制入向与出向流量。
- 默认行为:被策略选中的 Pod 未匹配到允许规则的流量会被拒绝;未被选中 Pod 仍是默认放行。
- 端口与协议:支持 TCP/UDP/ICMP(依 CNI 实现)。
1) 安装支持 NetworkPolicy 的 CNI(以 Calico 为例)#
若集群已安装支持 NetworkPolicy 的 CNI,可跳过本节。
安装
# 1) 安装 Calico
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
# 2) 查看组件状态
kubectl -n kube-system get pods -l k8s-app=calico-node
kubectl -n kube-system get pods -l k8s-app=calico-kube-controllers
预期效果
- calico-node、calico-kube-controllers 处于 Running 状态。
命令解释
- kubectl apply -f:应用 CNI 清单。
- -n kube-system:在系统命名空间查看 CNI 组件。
2) 场景化示例:命名空间隔离 + 服务放行#
2.1 创建命名空间与示例应用#
# 创建命名空间
kubectl create ns app
kubectl create ns db
# 部署 web/api/mysql 示例(这里用 busybox 模拟)
kubectl -n app run web --image=busybox --labels=app=web -- sleep 3600
kubectl -n app run api --image=busybox --labels=app=api -- sleep 3600
kubectl -n db run mysql --image=busybox --labels=app=mysql -- sleep 3600
命令解释
- kubectl run ... -- sleep 3600:启动长时间运行的容器便于测试。
- --labels=app=xxx:为策略选择器提供匹配标签。
2.2 先加默认拒绝策略#
# /etc/k8s/netpol/deny-all-app.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: app
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
kubectl apply -f /etc/k8s/netpol/deny-all-app.yaml
预期效果
- app 命名空间内所有 Pod 的入站/出站默认拒绝。
2.3 放行 app 内 web -> api#
# /etc/k8s/netpol/allow-web-to-api.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-web-to-api
namespace: app
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
kubectl apply -f /etc/k8s/netpol/allow-web-to-api.yaml
2.4 放行 api -> db/mysql(跨命名空间)#
# /etc/k8s/netpol/allow-api-to-mysql.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-to-mysql
namespace: db
spec:
podSelector:
matchLabels:
app: mysql
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: app
podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 3306
# 给 app 命名空间打标签,便于 namespaceSelector 匹配
kubectl label ns app name=app
kubectl apply -f /etc/k8s/netpol/allow-api-to-mysql.yaml
2.5 放行 DNS(否则 Pod 无法解析)#
# /etc/k8s/netpol/allow-dns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: app
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
kubectl apply -f /etc/k8s/netpol/allow-dns.yaml
2.6 测试连通性#
# 在 web 中测试访问 api:8080(此处仅演示端口探测)
kubectl -n app exec web -- sh -c "nc -zv api 8080"
# 在 api 中测试访问 mysql:3306(跨命名空间)
kubectl -n app exec api -- sh -c "nc -zv mysql.db.svc.cluster.local 3306"
# 测试外网访问(应被拒绝)
kubectl -n app exec web -- sh -c "wget -qO- http://example.com || echo blocked"
预期效果
- web -> api 8080 允许。
- api -> mysql 3306 允许。
- 外网访问被拒绝(无 Egress 放行规则)。
3) 出站控制:仅允许访问特定外部服务#
# /etc/k8s/netpol/allow-egress-to-external.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-external
namespace: app
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 203.0.113.10/32
ports:
- protocol: TCP
port: 443
kubectl apply -f /etc/k8s/netpol/allow-egress-to-external.yaml
命令解释
- ipBlock:仅允许访问指定 CIDR。
- policyTypes: Egress:只控制出站。
4) 常见故障与排查#
1) 策略不生效
# 确认 CNI 支持 NetworkPolicy
kubectl get nodes -o jsonpath='{.items[0].status.nodeInfo.containerRuntimeVersion}{"\n"}'
kubectl -n kube-system get ds | grep -E 'calico|cilium|weave'
# 检查策略是否应用成功
kubectl -n app get netpol
kubectl -n app describe netpol deny-all
- 若无支持 NetworkPolicy 的 CNI,策略不会生效。
2) DNS 解析失败
kubectl -n app exec web -- nslookup kubernetes.default.svc.cluster.local
kubectl -n app get netpol | grep dns
- 确保放行 kube-system 的
kube-dns/coredns访问。
3) 通信中断
# 检查标签与选择器
kubectl -n app get pods --show-labels
kubectl -n app describe netpol allow-web-to-api
- 标签不匹配会导致策略无效或误拦截。
5) 设计要点清单#
- 先默认拒绝:对关键命名空间统一加 deny-all。
- 逐步放行:按依赖关系逐条放行端口与来源。
- 标签治理:保持标签一致性,避免策略漂移。
- 与 Service/Ingress 协同:NetworkPolicy 负责 L3/L4,Ingress 负责 L7。
6) 练习#
- 在
db命名空间新增redisPod,仅允许app命名空间api访问 6379。 - 为
app命名空间启用默认拒绝后,补齐 DNS 放行与api->mysql放行策略。 - 限制
web只能访问api:8080,禁止web直接访问mysql:3306,并验证测试结果。