NetworkPolicy详解
一、核心定位:为什么需要 NetworkPolicy?
Kubernetes 集群默认的网络模型是 “全通模式”—— 所有 Pod 之间可以自由通信,Pod 与外部网络也无默认限制。这种模式在生产环境中存在严重安全隐患(例如:恶意 Pod 可访问数据库 Pod、非授权外部流量可渗透到内部服务)。
NetworkPolicy 的核心价值就是解决这一问题:通过白名单 / 黑名单规则,明确 “哪些 Pod 可以和哪些 Pod 通信”“Pod 是否能访问外部网络”,从而构建安全的网络边界。
二、核心前提:NetworkPolicy 依赖的 “网络插件”
NetworkPolicy 本身只是 “规则定义”,无法直接执行流量控制 —— 它需要依赖支持 NetworkPolicy 功能的 Kubernetes 网络插件(CNI 插件) 来实现规则的落地。
常见的支持 NetworkPolicy 的 CNI 插件包括:
- Calico(最主流,功能强大,支持复杂策略)
- Flannel(需搭配
flannel-vxlan+policy
扩展才支持) - Cilium(基于 eBPF,性能优异,支持 Layer 3/4/7 策略)
- Weave Net(轻量,原生支持 NetworkPolicy)
注意:如果集群使用的 CNI 插件不支持 NetworkPolicy(如原生 Flannel),则创建的 NetworkPolicy 会处于 “空跑” 状态,无法生效。
三、核心概念:理解 NetworkPolicy 的 4 个关键要素
NetworkPolicy 的规则由 “策略作用对象”“流量方向”“访问源 / 目标”“端口协议” 四部分组成,所有规则都是围绕这四个要素定义的。
要素 | 作用 | 核心字段 / 说明 |
---|---|---|
策略作用对象 | 明确 “哪些 Pod 会被该策略管控”(即 “策略应用到谁身上”) | 通过 podSelector (标签选择器)匹配 Pod;若不指定 podSelector ,则作用于命名空间内所有 Pod |
流量方向(Ingress/Egress) | 明确策略管控的是 “入站流量” 还是 “出站流量” | - Ingress :入站流量(流向被管控 Pod 的流量,如外部请求进入服务 Pod)- Egress :出站流量(从被管控 Pod 流出的流量,如 Pod 访问数据库) |
访问源 / 目标 | 明确 “允许 / 拒绝哪些来源的流量进入”(Ingress)或 “允许 / 拒绝访问哪些目标”(Egress) | 支持通过 podSelector (匹配集群内 Pod)、namespaceSelector (匹配命名空间)、ipBlock (匹配 IP 段,如外部网段)定义 |
端口协议 | 明确管控的 “网络端口和协议”(如 TCP 80 端口、UDP 53 端口) | 通过 ports 字段定义,支持单端口、多端口,协议包括 TCP(默认)、UDP、SCTP |
四、策略类型:白名单优先原则
NetworkPolicy 遵循 “默认拒绝,显式允许” 的安全原则,即:
- 若某个命名空间下存在针对 Pod 的 Ingress 策略,则默认拒绝所有未被策略允许的入站流量;
- 若存在针对 Pod 的 Egress 策略,则默认拒绝所有未被策略允许的出站流量;
- 若没有任何 NetworkPolicy,则保持默认 “全通” 模式。
基于此,NetworkPolicy 可分为两类核心策略:
1. Ingress 策略(管控入站流量)
控制 “哪些来源可以访问被策略匹配的 Pod”。
例如:“只允许 namespace=backend
下的 Pod 访问 namespace=db
下 label=app=mysql
的 Pod 的 TCP 3306 端口”。
2. Egress 策略(管控出站流量)
控制 “被策略匹配的 Pod 可以访问哪些目标”。
例如:“namespace=frontend
下 label=app=web
的 Pod,只能访问 namespace=backend
下的 Pod 和外部 IP 段 10.0.0.0/8
的 TCP 8080 端口”。
3. 组合策略(同时管控 Ingress + Egress)
一个 NetworkPolicy 可以同时定义 Ingress 和 Egress 规则,实现对 Pod 入站和出站流量的全面管控。
五、完整示例:通过 YAML 定义 NetworkPolicy
Kubernetes 中通过 YAML 文件创建 NetworkPolicy,以下是 3 个典型场景的示例,帮助理解规则的编写逻辑。
示例 1:基础 Ingress 策略(限制数据库访问)
需求:db
命名空间下 label=app=mysql
的 Pod(数据库),只允许 backend
命名空间下 label=app=api
的 Pod 访问其 TCP 3306 端口(数据库端口)。
yaml
apiVersion: networking.k8s.io/v1 # NetworkPolicy 的 API 版本(固定为 v1)
kind: NetworkPolicy # 资源类型为 NetworkPolicy
metadata:name: mysql-ingress-policy # 策略名称namespace: db # 策略作用的命名空间(必须指定,仅对该命名空间生效)
spec:podSelector: # 策略作用对象:匹配 db 命名空间下 label=app=mysql 的 PodmatchLabels:app: mysqlpolicyTypes: [Ingress] # 策略类型:仅管控 Ingress(入站流量)ingress:- from: # 允许的访问源(白名单)- namespaceSelector: # 来源 1:匹配 backend 命名空间matchLabels:kubernetes.io/metadata.name: backend # 命名空间的标签(需确保 backend 命名空间有此标签)podSelector: # 来源 2:在 backend 命名空间下,匹配 label=app=api 的 PodmatchLabels:app: apiports: # 允许访问的端口协议- protocol: TCPport: 3306 # MySQL 默认端口
示例 2:基础 Egress 策略(限制前端 Pod 出站)
需求:frontend
命名空间下 label=app=web
的 Pod(前端服务),只能访问 backend
命名空间下的 Pod(TCP 8080 端口)和外部 DNS 服务(UDP 53 端口,IP 段 10.96.0.10
,K8s 集群默认 DNS 服务地址)。
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: web-egress-policynamespace: frontend
spec:podSelector:matchLabels:app: webpolicyTypes: [Egress] # 策略类型:仅管控 Egress(出站流量)egress:- to: # 允许访问的目标(白名单)- namespaceSelector: # 目标 1:backend 命名空间下的所有 PodmatchLabels:kubernetes.io/metadata.name: backendports:- protocol: TCPport: 8080 # 后端服务端口- to: # 目标 2:外部 DNS 服务(IP 段)- ipBlock:cidr: 10.96.0.10/32 # K8s 集群 DNS 服务的固定 IP(不同集群可能不同,需确认)ports:- protocol: UDPport: 53 # DNS 服务端口
示例 3:组合策略(同时管控 Ingress + Egress)
需求:app
命名空间下 label=app=payment
的 Pod(支付服务),入站仅允许 frontend
命名空间的 Pod 访问 TCP 80 端口,出站仅允许访问 db
命名空间的 MySQL(TCP 3306)和外部支付网关(IP 段 203.0.113.0/24
)。
yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:name: payment-combined-policynamespace: app
spec:podSelector:matchLabels:app: paymentpolicyTypes: [Ingress, Egress] # 同时管控 Ingress 和 Egress# Ingress 规则(入站)ingress:- from:- namespaceSelector:matchLabels:kubernetes.io/metadata.name: frontendports:- protocol: TCPport: 80# Egress 规则(出站)egress:- to:- namespaceSelector:matchLabels:kubernetes.io/metadata.name: dbpodSelector:matchLabels:app: mysqlports:- protocol: TCPport: 3306- to:- ipBlock:cidr: 203.0.113.0/24 # 外部支付网关 IP 段
六、关键特性与注意事项
1. 命名空间隔离
NetworkPolicy 是命名空间级别的资源(metadata.namespace
必须指定),仅对所在命名空间的 Pod 生效,无法跨命名空间管控 Pod(跨命名空间访问需通过 namespaceSelector
定义来源 / 目标)。
2. 策略叠加逻辑
若多个 NetworkPolicy 匹配同一个 Pod(即 podSelector
重叠),则:
- Ingress 规则:所有允许的来源会 “叠加”(即多个策略的
ingress.from
合并,只要满足任一策略的允许条件,流量就可进入); - Egress 规则:所有允许的目标会 “叠加”(同理,满足任一策略的
egress.to
条件,流量就可流出)。
3. IPBlock 的特殊限制
ipBlock
用于匹配 IP 段,但有两个关键限制:
- 无法直接匹配 Kubernetes 集群内的 Pod IP(因为 Pod IP 是动态分配的,且
ipBlock
不支持结合podSelector
); - 若集群使用 “网络地址转换(NAT)”,则
ipBlock
匹配的是 “Pod 看到的 IP”(而非外部真实 IP),需注意网络拓扑。
4. 不支持的场景
NetworkPolicy 目前仅支持 Layer 3(IP 层)和 Layer 4(端口层) 的流量控制,不直接支持 Layer 7(应用层,如 HTTP 路径、请求头)的策略。若需应用层控制,需结合 Cilium(基于 eBPF 支持 Layer 7)或 Istio(服务网格)等工具。
七、常用操作:管理 NetworkPolicy
通过 kubectl
命令可对 NetworkPolicy 进行日常管理:
- 创建策略:
kubectl apply -f network-policy.yaml
- 查看命名空间下的策略:
kubectl get networkpolicy -n <命名空间>
(简写:kubectl get netpol -n <命名空间>
) - 查看策略详情:
kubectl describe netpol <策略名称> -n <命名空间>
- 删除策略:
kubectl delete netpol <策略名称> -n <命名空间>
总结
NetworkPolicy 是 Kubernetes 集群网络安全的 “基石”,通过 “基于标签的 Pod 匹配”“Ingress/Egress 流量方向控制”“多维度来源 / 目标定义”,实现了从 “全通网络” 到 “精细化隔离” 的转变。在生产环境中,需结合业务场景(如 “前端→后端→数据库” 的服务调用链)设计分层的 NetworkPolicy,构建纵深防御的网络安全体系。