痛点:K8s 集群内网络"裸奔"是常态
默认情况下,Kubernetes 集群内所有 Pod 可以互相访问——不分 Namespace、不分业务。这意味着一旦某个 Pod 被攻破(比如一个有 RCE 漏洞的应用),攻击者可以横向移动到数据库、缓存、内部 API 等关键服务。
真实场景:某电商平台线上环境,测试团队的 debug Pod 部署在同集群,因未做网络隔离,直接访问到了生产 Redis,误执行 FLUSHALL,导致缓存全量失效、数据库瞬间被打满。
K8s 原生的 NetworkPolicy 就是解决这个问题的,但实际用的团队不到 30%——原因很简单:文档抽象、配置容易写错、不知道怎么验证生效。今天用 3 步把它落地。
前提:确认 CNI 插件支持 NetworkPolicy
NetworkPolicy 是 K8s API 对象,但执行靠 CNI 插件。先确认你的 CNI 支持:
| CNI 插件 | 支持 NetworkPolicy | 备注 |
|---|---|---|
| Calico | ✅ 完整支持 | 生产首选,还支持 GlobalNetworkPolicy |
| Cilium | ✅ 完整支持 | 基于 eBPF,性能更优 |
| Weave Net | ✅ 支持 | 社区活跃度下降 |
| Flannel | ❌ 不支持 | 需配合 Calico 使用(Canal 模式) |
检查当前 CNI:
# 查看 CNI 配置目录
ls /etc/cni/net.d/
# 查看 CNI Pod
kubectl get pods -n kube-system | grep -E 'calico|cilium|weave|flannel'
如果是 Flannel,建议迁移到 Calico 或 Cilium,否则 NetworkPolicy 写了也不生效(这是最常见的坑之一)。
第 1 步:Default Deny — 先封死,再按需放行
零信任的核心思路:默认拒绝所有流量,再逐条开白名单。
对 production Namespace 启用默认拒绝所有入站流量:
# default-deny-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: production
spec:
podSelector: {} # 匹配该 Namespace 下所有 Pod
policyTypes:
- Ingress # 拒绝所有入站
应用并验证:
kubectl apply -f default-deny-ingress.yaml
# 验证:从其他 Namespace 尝试访问 production 下的服务
kubectl run test-curl --rm -it --image=curlimages/curl \
-n testing -- curl -s --max-time 3 http://api-service.production.svc:8080
# 预期:超时,无法连接
同理,出站流量也建议默认拒绝:
# default-deny-egress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
注意:Egress Deny 会阻断 DNS 解析(CoreDNS 在
kube-system),需要在下一步显式放行。
第 2 步:按需放行 — 精准开白名单
放行 DNS(必须优先做)
# allow-dns.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
放行前端到后端 API 的流量
假设前端 Pod 标签为 app: frontend,后端 API 标签为 app: api:
# allow-frontend-to-api.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
放行 API 到数据库
# allow-api-to-db.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-to-db
namespace: production
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
这样形成了一条清晰的调用链:frontend → api:8080 → postgres:5432,其他路径全部拒绝。
第 3 步:验证与可视化 — 确认策略真正生效
策略写完不验证等于没写。推荐两种方式:
方式 1:手动验证(快速)
# 测试允许的路径(frontend → api)
kubectl exec -n production deploy/frontend -- \
curl -s --max-time 3 http://api-service:8080/health
# 预期:200 OK
# 测试拒绝的路径(frontend → postgres)
kubectl exec -n production deploy/frontend -- \
curl -s --max-time 3 http://postgres-service:5432
# 预期:超时/拒绝
# 测试跨 Namespace 隔离
kubectl exec -n testing deploy/debug-tools -- \
curl -s --max-time 3 http://api-service.production.svc:8080
# 预期:超时/拒绝
方式 2:kubectl 查看策略覆盖
# 查看 Namespace 下所有 NetworkPolicy
kubectl get networkpolicy -n production
# 查看具体策略的详细规则
kubectl describe networkpolicy allow-frontend-to-api -n production
方式 3:Cilium 用户可用 Hubble 可视化
# 安装 Hubble CLI
hubble observe -n production --verdict DROPPED
# 实时查看被拒绝的流量,快速定位策略是否误杀
3 个常见坑
坑 1:Flannel 不支持 NetworkPolicy
写了 YAML、apply 成功、但流量照样通——因为 Flannel 不执行 NetworkPolicy。解决:换 Calico 或 Cilium。用 kubectl get pods -n kube-system 确认 CNI 类型。
坑 2:忘记放行 DNS
Default Deny Egress 后 Pod 无法解析域名,所有 Service 调用全挂。表现为 curl: Could not resolve host。解决:永远在 Deny Egress 后第一时间加 DNS 白名单。
坑 3:podSelector 为空和不写的区别
podSelector: {} 表示匹配当前 Namespace 下所有 Pod;而 podSelector 字段完全不写会报错。另外 namespaceSelector: {} 匹配所有 Namespace,千万别搞混——写错等于全局放行。
总结
| 步骤 | 动作 | 效果 |
|---|---|---|
| 1 | Default Deny Ingress + Egress | 封死所有流量 |
| 2 | 按需 Allow(DNS → 业务链路) | 最小权限放行 |
| 3 | 手动验证 + 持续监控 | 确认策略生效 |
K8s NetworkPolicy 是集群内零信任网络的第一道防线,成本为零、效果立竿见影。落地建议:先在非生产环境验证,再逐个 Namespace 推到生产。如果需要更细粒度的控制(如 L7 HTTP 路径匹配),可以进阶到 Cilium 的 CiliumNetworkPolicy。
网络隔离不是可选项,是生产环境的底线配置。今天就开始给你的集群加上这道锁。