title: K8s 系列 | 第 12 天:NetworkPolicy:K8s 网络安全策略与微隔离
tags:
– Kubernetes
– K8s系列
– DevOps
– NetworkPolicy
– 网络安全
– 微隔离
– 容器网络
第 12/30 天
引言
在 Kubernetes 集群中,默认情况下所有 Pod 之间是可以相互通信的——这是一个扁平的、全连通网络模型。虽然这降低了服务发现的复杂度,但在生产环境中却带来了严重的安全隐患:一旦某个 Pod 被攻陷,攻击者可以自由横向移动,访问集群中的任意其他服务。
NetworkPolicy 是 Kubernetes 原生的网络安全控制机制,它允许你通过声明式规则来控制 Pod 层面的入站(Ingress)和出站(Egress)流量,实现微隔离(Micro-segmentation),将零信任安全模型落地到容器化环境中。
本文将深入解析 NetworkPolicy 的核心原理、实战配置以及生产最佳实践。
一、核心概念
1.1 什么是 NetworkPolicy?
NetworkPolicy 是 Kubernetes 的命名空间级别资源,它通过标签选择器(Label Selector)来定义哪些 Pod 允许与哪些端点通信。其本质是一组有状态防火墙规则,工作在 OSI 模型第 3/4 层(IP + 端口)。
1.2 关键特性
| 特性 | 说明 |
|---|---|
| 命名空间范围 | NetworkPolicy 仅作用于同一命名空间中的 Pod |
| 标签驱动 | 通过 Pod 标签选择目标,而非 IP 地址 |
| 双向控制 | 支持 Ingress(入站)和 Egress(出站)流量控制 |
| 白名单模型 | 默认拒绝所有流量,仅允许显式放行的流量 |
| 需要 CNI 支持 | 非所有 CNI 插件都实现 NetworkPolicy |
1.3 先决条件:CNI 插件支持
并非所有集群都支持 NetworkPolicy! 它需要 CNI 网络插件具备 NetworkPolicy 引擎。以下是常见 CNI 的支持情况:
| CNI 插件 | 支持 NetworkPolicy | 备注 |
|---|---|---|
| Calico | ✅ | 企业级策略引擎,支持全局网络策略 |
| Cilium | ✅ | 基于 eBPF,支持 L3-L7 策略 |
| Weave Net | ✅ | 内置策略控制器 |
| Flannel | ❌ | 极简网络模型,无策略引擎 |
| Antrea | ✅ | VMware 出品,支持 K8s 原生策略 |
关键提示:如果使用 Flannel,你需要额外部署 Calico 的 NetworkPolicy 组件(以策略-only 模式运行),或直接切换为 Calico / Cilium。
二、NetworkPolicy 资源定义详解
2.1 资源结构
一个完整的 NetworkPolicy 包含以下核心字段:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: demo-network-policy
namespace: default
spec:
# 1. 目标 Pod 选择器(必选)
podSelector:
matchLabels:
app: web
# 2. 策略类型(可选,默认为 Ingress)
policyTypes:
- Ingress
- Egress
# 3. 入站规则
ingress:
- from:
- ipBlock:
cidr: 10.0.0.0/24
except:
- 10.0.0.5/32
- namespaceSelector:
matchLabels:
project: production
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
# 4. 出站规则
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.100.0.0/16
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
2.2 字段详解
podSelector(目标选择)
{}空选择器匹配命名空间中所有 Pod- 这是策略作用的目标 Pod(被保护的 Pod)
policyTypes
- 如果不指定,默认仅启用
Ingress - 一旦显式指定了
Egress,必须同时为 Egress 流量配置出站规则 - 强烈建议始终显式声明
policyTypes
ingress 规则
from来源匹配(三者之间是或关系):podSelector:同一命名空间中的 PodnamespaceSelector:其他命名空间中的 PodipBlock:集群外部的 CIDR 地址段ports目标端口- 多个
from条目之间是或关系 - 同一个
from内的podSelector和namespaceSelector之间是与关系
egress 规则
to目标匹配,结构与from相同ports目标端口
2.3 关键行为语义
多条 ingress/egress 规则 → OR(任一匹配即放行)
同一规则内的多个来源 → AND(必须同时满足)
podSelector + namespaceSelector 在同一 from/to 条目内 → AND
多个 from/to 条目 → OR
三、实战配置案例
3.1 场景:三层微服务架构
我们有经典的 Web → API → DB 三层架构,需要实现以下安全策略:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Web │────▶│ API │────▶│ DB │
│ app=web │ │ app=api │ │ app=db │
└─────────┘ └─────────┘ └─────────┘
port 80 port 8080 port 3306
安全要求:
1. Web Pod:仅允许从 Ingress Controller 访问 80 端口
2. API Pod:仅允许 Web Pod 访问 8080 端口
3. DB Pod:仅允许 API Pod 访问 3306 端口,且自身不能发起对外连接
4. 所有 Pod 可以访问 kube-dns(UDP 53)用于服务发现
部署测试应用
# 创建命名空间
kubectl create namespace network-demo
# 部署 Web 服务
kubectl create deployment web --image=nginx -n network-demo
kubectl expose deployment web --port=80 --target-port=80 -n network-demo
# 部署 API 服务
kubectl create deployment api --image=nginx -n network-demo
kubectl expose deployment api --port=8080 --target-port=80 -n network-demo
# 部署 DB 服务
kubectl create deployment db --image=mysql:8.0 -n network-demo
kubectl expose deployment db --port=3306 -n network-demo
策略 1:DB 层隔离——仅允许 API 访问 3306
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-ingress-policy
namespace: network-demo
spec:
podSelector:
matchLabels:
app: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 3306
egress:
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
策略 2:API 层隔离——仅允许 Web 访问 8080
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-ingress-policy
namespace: network-demo
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: web
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- to:
- podSelector:
matchLabels:
app: db
ports:
- protocol: TCP
port: 3306
策略 3:Web 层隔离——仅允许 Ingress 流量
实际生产环境中,Web 层应该只允许从 Ingress Controller 过来的流量:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: web-ingress-policy
namespace: network-demo
spec:
podSelector:
matchLabels:
app: web
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 80
egress:
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- to:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 8080
3.2 验证网络策略
# 部署测试客户端
kubectl run test-pod --image=busybox -n network-demo -- sleep 3600
# 测试连接 DB(应该被拒绝——test-pod 没有 app=api 标签)
kubectl exec -it test-pod -n network-demo -- wget -q --timeout=3 db:3306
# 测试 DNS 解析(应该成功——所有 Pod 允许访问 kube-dns)
kubectl exec -it test-pod -n network-demo -- nslookup kubernetes.default
# 检查 NetworkPolicy 状态
kubectl describe networkpolicy -n network-demo
四、高级场景
4.1 默认拒绝所有流量
这是生产环境的推荐起点:先封锁一切,再逐步放行必要流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
应用此策略后,命名空间中所有 Pod 只能通过显式创建的其他 NetworkPolicy 来放行流量。
4.2 白名单——仅允许特定命名空间
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090
注意:
kubernetes.io/metadata.name是 K8s 1.22+ 自动添加的标签,值为命名空间名称。
4.3 跨命名空间通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-frontend-ns
namespace: backend
spec:
podSelector:
matchLabels:
app: payment-service
ingress:
# 来自 frontend 命名空间中标签为 tier=web 的 Pod
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: frontend
podSelector:
matchLabels:
tier: web
ports:
- protocol: TCP
port: 8080
这里的 namespaceSelector 和 podSelector 在同一个 from 条目中,它们是与关系:必须同时满足来自 frontend 命名空间且 Pod 标签为 tier=web。
4.4 允许来自集群外部的 IP
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-external-monitoring
namespace: production
spec:
podSelector:
matchLabels:
app: metrics-exporter
ingress:
- from:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- protocol: TCP
port: 9100
五、常见问题与陷阱
5.1 “我创建了 NetworkPolicy,但流量没被拦截?”
可能原因:
1. CNI 插件不支持:运行 kubectl describe pod <pod-name> 查看网络插件,Flannel 不支持
2. 策略未正确选择 Pod:检查 podSelector 的标签是否匹配目标 Pod
3. 缺少 policyTypes: [Egress]:默认只控制 Ingress,出站不受影响
4. Pod 在 istio-proxy sidecar 模式下:Envoy 会绕过底层 NetworkPolicy
5.2 “我只想允许访问 kube-dns,但写了一天规则”
# 正确做法:使用命名空间选择器匹配 kube-system
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
5.3 “NetworkPolicy 性能会受影响吗?”
- 每个命名空间创建大量 NetworkPolicy 会增加 CNI 的策略计算开销
- Cilium 基于 eBPF 的实现性能最优,适合大规模集群
- 建议:单个命名空间不超过 20 条 NetworkPolicy
- 使用
kubectl get networkpolicy -A | wc -l监控总数
5.4 调试 NetworkPolicy
# 1. 查看当前策略
kubectl get networkpolicy -n <namespace>
kubectl describe networkpolicy <name> -n <namespace>
# 2. 使用 netshoot 诊断工具
kubectl run netshoot --image=nicolaka/netshoot -n <namespace> -- sleep 3600
kubectl exec -it netshoot -n <namespace> -- curl -v http://target-service:port
# 3. 查看 iptables 规则(Calico 下)
kubectl exec <calico-node-pod> -n kube-system -- iptables -L -n -t filter | grep <namespace>
六、生产最佳实践
6.1 推荐策略模板
# 1. 默认拒绝所有
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
# 2. 允许 DNS 解析
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
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
6.2 实施策略
- 先审计再实施:使用
kubectl trace或 Cilium Hubble 观察现有流量模式 - 渐进式封锁:先只启用 Ingress 策略,确认无误后再启用 Egress
- 使用 namespace 标签命名规范:为每个命名空间打上清晰的元数据标签
- 配合 Service Mesh:Cilium + NetworkPolicy 可实现 L7 层策略控制
- 启用审计日志:通过 CNI 插件的策略审计日志监控被拒绝的流量
6.3 使用 CiliumNetworkPolicy 实现 L7 策略
对于更细粒度的控制(HTTP 路径、方法等),可以升级到 Cilium:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-api-routes
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
- fromEndpoints:
- matchLabels:
app: web
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: GET
path: "/api/v1/users/.*"
- method: POST
path: "/api/v1/orders"
CiliumNetworkPolicy 是自定义资源(CRD),需要预先安装 Cilium CNI 插件。
总结
NetworkPolicy 是 Kubernetes 生产环境中不可或缺的安全组件。通过本文的实战演练,你已经掌握了:
- ✅ NetworkPolicy 的核心概念与工作原理
- ✅ 三层微服务架构的完整 NetworkPolicy 配置
- ✅ 默认拒绝 + 白名单放行的安全最佳实践
- ✅ 各种常见使用场景(命名空间隔离、IP 白名单、DNS 放行)
- ✅ 调试与故障排查方法
记住三条黄金法则:
– 先拒绝一切,再显式放行
– 始终同时声明 Ingress 和 Egress
– 测试、测试、再测试——用调试 Pod 验证每条策略
安全无小事,每一层隔离都是生产环境中防御纵深的关键一环。
下期预告:第 13 天我们将继续深入 K8s 服务发现领域,全面解析 Headless Service 与服务发现机制——为什么有时候你不需要 ClusterIP?StatefulSet 如何与 Headless Service 配合实现稳定的网络标识?敬请期待!
系列目录:K8s 30 天系列文章目录















暂无评论内容