NetworkPolicy 实战:K8s Pod 微隔离配置指南

适用场景

NetworkPolicy 微隔离适用于以下典型场景:

  • 多团队共用一个 Kubernetes 集群,需要限制不同命名空间之间的互访;
  • 数据库、Redis 等敏感服务只允许特定后端 Pod 访问,避免集群内任意 Pod 都能连接;
  • 降低攻击面:一旦某个 Pod 被入侵,阻止攻击者向集群内其他服务横向移动;
  • 替换传统防火墙思路,实现以标签为中心的 Pod 级访问控制。

前置条件

  • Kubernetes 1.25+ 集群,且 CNI 插件支持 NetworkPolicy(Calico、Cilium、Weave Net 均支持;Flannel 不支持,策略会创建成功但不生效);
  • 本地已安装 kubectl 并具备集群管理员权限;
  • 测试用镜像:busybox、nginx 等;
  • 执行以下命令确认网络策略能力:kubectl get pods -n kube-system | grep -E "calico|cilium|weave"

原理说明

NetworkPolicy 是 Kubernetes 原生的网络访问控制 API。它的核心规则是:一旦某个 Pod 被 NetworkPolicy 选中,该 Pod 就进入”默认拒绝”状态——所有未被策略显式放行的 ingress(入站)和 egress(出站)流量都会被丢弃。策略通过三种选择器划定范围:

  • podSelector:按标签选择同命名空间内的目标 Pod;
  • namespaceSelector:按标签选择允许互访的命名空间;
  • ipBlock:按 CIDR 网段放行或排除外部 IP。

策略由 CNI 插件在节点层面转化为 iptables/eBPF 规则执行,因此不依赖 Pod 内任何进程,容器无法绕过。

操作步骤

1. 部署演示应用

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  labels:
    app: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: nginx
        image: nginx:1.27
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: backend
spec:
  selector:
    app: backend
  ports:
  - port: 80

2. 默认拒绝所有出入流量

先对 demo 命名空间实施全量默认拒绝,作为安全基线:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: demo
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

podSelector 为空({})表示选中命名空间内全部 Pod,policyTypes 同时包含 Ingress 和 Egress。

3. 放行 DNS 解析

默认拒绝会切断所有出站流量,必须先放行 DNS,否则服务无法解析域名:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: demo
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: kube-system
    ports:
    - protocol: UDP
      port: 53
    - protocol: TCP
      port: 53

4. 仅允许 frontend 访问 backend

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: demo
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - protocol: TCP
      port: 80

5. 按网段放行外部来源(可选)

如需允许办公网段访问某个服务,使用 ipBlock

  ingress:
  - from:
    - ipBlock:
        cidr: 10.20.0.0/16
        except:
        - 10.20.5.0/24

except 字段用于在 CIDR 内排除例外网段。

配置验证

# 前端 Pod 访问 backend:应返回 nginx 欢迎页
kubectl -n demo run test-front --image=busybox -l app=frontend --rm -it --restart=Never -- wget -qO- --timeout=3 http://backend

# 未打 frontend 标签的 Pod 访问:应超时失败
kubectl -n demo run test-other --image=busybox --rm -it --restart=Never -- wget -qO- --timeout=3 http://backend

第一条命令返回 HTML 内容、第二条超时,即说明策略生效。也可用 kubectl -n demo describe networkpolicy allow-frontend-to-backend 检查策略解析结果。

常见问题

FAQ 1:策略创建成功但完全不生效?

最常见原因是 CNI 插件不支持 NetworkPolicy(如 Flannel)。用 kubectl get pods -n kube-system 确认插件类型;不支持时需更换为 Calico 或 Cilium。此外检查标签拼写是否与 podSelector 完全一致。

FAQ 2:应用 DNS 解析失败、健康检查被切断?

默认拒绝策略会拦截所有出站流量。务必保留 allow-dns 策略放行 kube-system 的 53 端口;若使用 kubelet 探针,探针流量不受 NetworkPolicy 影响,但应用访问外部 API 需要单独放行 egress 规则。

总结

NetworkPolicy 通过”默认拒绝 + 白名单放行”的模型,为 Kubernetes 集群提供了原生、声明式的微隔离能力。落地时的关键顺序是:先部署 default-deny-all 基线,再逐条放行 DNS 与业务互访,最后用真实 Pod 验证正反两个方向的连通性。策略随 Pod 标签动态匹配,扩缩容无需额外维护规则,是云原生环境中最经济的东西向流量防护手段。