16.4.5 网络策略与安全隔离

5. 网络策略与安全隔离#

网络策略用于在 Kubernetes 中实现命名空间级与 Pod 级的精细化流量控制,依赖支持 NetworkPolicy 的 CNI(如 Calico、Cilium)。其核心目标是最小权限通信、分区隔离、限制横向移动,并与组织安全基线保持一致。

原理草图(流量与策略关系)

文章图片

网络策略基础模型
- 选择器:通过 podSelectornamespaceSelector 匹配对象范围。
- 方向IngressEgress,分别控制入向与出向流量。
- 默认行为:被策略选中的 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-nodecalico-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) 练习#

  1. db 命名空间新增 redis Pod,仅允许 app 命名空间 api 访问 6379。
  2. app 命名空间启用默认拒绝后,补齐 DNS 放行与 api->mysql 放行策略。
  3. 限制 web 只能访问 api:8080,禁止 web 直接访问 mysql:3306,并验证测试结果。