目录
1. 什么是 NetworkPolicy?
NetworkPolicy 是一种 Kubernetes 资源对象,它通过定义规则来控制 Pod 之间以及 Pod 与外部网络之间的网络流量(入站和出站),就像一个内置的、基于标签的防火墙。
核心思想:默认情况下,Kubernetes 集群内的所有 Pod 是可以相互通信的(“所有流量放行”)。NetworkPolicy 允许你实施 “最小权限原则” ,即只允许必要的通信,拒绝其他所有流量。
2. 为什么需要 NetworkPolicy?
想象一个典型的微服务应用:
- 前端(frontend) Pods 需要与 后端(backend) Pods 通信。
- 后端 Pods 需要与 数据库(database) Pods 通信。
- 但前端不应该直接访问数据库,并且可能没有任何服务需要主动连接前端。
如果没有 NetworkPolicy,如果一个 Pod 被攻击,攻击者可以以此为跳板,在集群内“横向移动”,访问任何其他服务。NetworkPolicy 可以严格限制这种横向移动,极大地提升集群的安全性。
3. 前提条件:网络插件支持
非常重要:NetworkPolicy 本身只是一个 API 定义,它需要由 Container Network Interface (CNI) 网络插件来具体实现其规则。
- 支持的 CNI 插件:Calico, Cilium, Weave Net, Antrea, Kube-router 等。
- 不支持的 CNI 插件:Flannel(默认的 host-gw 后端不支持)、Bridge 等。
如果你的网络插件不支持 NetworkPolicy,那么你创建的任何策略都不会生效。请先确认你的 Kubernetes 集群使用了正确的网络插件。
4. NetworkPolicy 核心工作模型
NetworkPolicy 不是通过在 Pod 上添加注解来实现的,而是通过选择器(Selectors)来定义规则:
- 选择一组 Pods:使用
podSelector
字段来选择此策略要应用到的目标 Pods(“防火墙要保护谁”)。 - 定义入站规则(Ingress):规定谁可以访问这些目标 Pods,以及可以访问哪些端口。
- 定义出站规则(Egress):规定这些目标 Pods 可以访问谁,以及可以访问哪些端口。
5. NetworkPolicy 资源定义剖析
下面是一个完整的 NetworkPolicy 示例:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default # NetworkPolicy 是命名空间范围的资源
spec:
# 1. 策略目标:此策略应用到哪里?
podSelector:
matchLabels:
role: db # 选择所有具有标签 `role=db` 的 Pods
# 2. 策略类型:定义此策略是管理入站、出站,还是两者都管。
policyTypes:
- Ingress
- Egress
# 3. 入站规则(白名单):谁可以访问上述 `role=db` 的 Pods?
ingress:
- from:
- podSelector: # (a) 来自集群内的 Pods
matchLabels:
role: api
- namespaceSelector: # (b) 来自特定命名空间的所有 Pods
matchLabels:
project: myproject
- ipBlock: # (c) 来自集群外部的特定 IP 段
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
ports:
- protocol: TCP
port: 6379
# 4. 出站规则(白名单):上述 `role=db` 的 Pods 可以访问谁?
egress:
- to:
- podSelector:
matchLabels:
role: cache
ports:
- protocol: TCP
port: 6379
- to: # 允许访问外部 DNS 服务器
- ipBlock:
cidr: 8.8.8.8/32
ports:
- protocol: UDP
port: 53
6. 常见场景示例
场景 1:拒绝所有入站流量(默认拒绝)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress
namespace: default
spec:
podSelector: {} # 匹配命名空间中的所有 Pods
policyTypes:
- Ingress
# 不指定任何 ingress 规则,意味着拒绝所有入站流量。
场景 2:允许来自特定 Pod 的访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
场景 3:允许访问外部网络和 DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
场景 4:跨命名空间访问
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-cross-namespace
namespace: backend
spec:
podSelector:
matchLabels:
app: api
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend
podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
给命名空间打上标签:
kubectl label namespace frontend name=frontend
7. 总结与最佳实践
- 默认拒绝:首先为每个命名空间创建
deny-all-ingress
策略,然后再创建允许特定流量的策略。 - 标签是关键:NetworkPolicy 严重依赖标签(
podSelector
和namespaceSelector
)来工作。为 Pod 和命名空间设计清晰的标签体系。 - 策略是叠加的:如果多个 NetworkPolicy 选择了同一个 Pod,则所有策略的规则会叠加(取并集)。
- 从简单开始:先从保护最关键的服务(如数据库)开始,逐步扩大范围。
- 测试策略:
然后使用kubectl describe networkpolicy <name> kubectl run -it --rm --image=nicolaka/netshoot testpod -- /bin/bash
curl
,dig
,nc
等工具测试连通性。
NetworkPolicy 是 Kubernetes 生产环境安全加固的必备工具,能够在容器层面实现网络隔离,防止攻击蔓延,是零信任网络架构在 K8s 中的具体实践。