说明:本文由 Codex 根据作者提供的主题、素材与公开资料辅助生成,属于 AI 生成/整理内容,非作者原创。请读者自行甄别并交叉验证。
NetworkPolicy 是什么#
NetworkPolicy 是 Kubernetes 里用于控制 Pod 网络访问的资源对象。
它主要工作在三层和四层:
IP 地址
端口
协议:TCP / UDP / SCTP它回答的问题是:
哪些来源可以访问这些 Pod?
这些 Pod 可以访问哪些目标?
允许访问哪些端口?一个常见理解是:
Service 负责“怎么找到后端”;
NetworkPolicy 负责“找到以后能不能访问”。需要特别注意:NetworkPolicy 本身只是 Kubernetes API 对象。真正执行规则的是网络插件,例如 Calico、Cilium、Antrea、kube-router 等。集群如果没有安装支持 NetworkPolicy 的 CNI,创建策略对象也不会产生实际隔离效果。
默认行为#
Kubernetes 默认不是零信任网络。
如果一个 Pod 没有被任何 NetworkPolicy 选中,那么它默认是:
Ingress:允许所有入站连接
Egress:允许所有出站连接也就是说,默认情况下 Pod 之间通常可以互相访问。
当一个 Pod 被某条策略选中,并且该策略声明了 Ingress,这个 Pod 才会进入入站隔离状态。
当一个 Pod 被某条策略选中,并且该策略声明了 Egress,这个 Pod 才会进入出站隔离状态。
可以把它理解成:
没有策略命中:默认放行
有策略命中:只放行策略允许的流量两个方向:Ingress 和 Egress#
Ingress 是进入 Pod 的流量。
Client Pod -> Server Pod
^^^^^^^^^^
IngressEgress 是从 Pod 发出去的流量。
Client Pod -> Server Pod
^^^^^^^^^^
Egress一次 Pod 到 Pod 的访问要成功,需要同时满足两个方向:
源 Pod 的 egress 策略允许出去;
目标 Pod 的 ingress 策略允许进来。如果任意一边不允许,连接就不会成功。
策略是叠加的,不是覆盖的#
多条 NetworkPolicy 同时选中一个 Pod 时,规则是叠加关系。
它们不会互相覆盖,也没有先后顺序。
可以理解成:
最终允许集合 = 所有命中策略允许流量的并集所以 Kubernetes 原生 NetworkPolicy 没有显式 deny 规则。
如果想拒绝某类流量,通常做法是:
先 default deny;
再逐步 allow 需要的来源、目标和端口。基本结构#
一个 NetworkPolicy 的基本结构如下:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-api
namespace: default
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080含义是:
选中 default namespace 下 app=api 的 Pod;
限制这些 Pod 的入站流量;
只允许 app=frontend 的 Pod 访问 TCP 8080。几个关键字段:
| 字段 | 含义 |
|---|---|
metadata.namespace | 策略所在 namespace |
spec.podSelector | 这条策略选中哪些 Pod |
policyTypes | 策略作用方向:Ingress、Egress |
ingress[].from | 允许哪些来源进入 |
egress[].to | 允许访问哪些目标 |
ports | 允许哪些协议和端口 |
podSelector: {} 表示选中当前 namespace 下所有 Pod。
default deny#
安全基线里最常见的是 default deny。
拒绝所有入站#
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
namespace: app
spec:
podSelector: {}
policyTypes:
- Ingress这表示:app namespace 里的所有 Pod 默认不允许任何入站连接,除非其他策略显式放行。
拒绝所有出站#
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
namespace: app
spec:
podSelector: {}
policyTypes:
- Egress这表示:app namespace 里的所有 Pod 默认不允许出站连接。
如果启用了 egress default deny,通常要记得放行 DNS,否则应用可能连服务名都解析不了。
放行 DNS#
常见 DNS 放行示例:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: app
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这里有一个细节:
- namespaceSelector: ...
podSelector: ...写在同一个列表项里,表示同时满足 namespace 和 pod 条件。
如果写成两个列表项:
- namespaceSelector: ...
- podSelector: ...含义就变成二选一:满足 namespace 条件的所有 Pod,或者当前 namespace 里满足 pod 条件的 Pod。
这是很多 NetworkPolicy 写错的地方。
namespaceSelector#
NetworkPolicy 不能直接通过 namespace 名称字段选择 namespace,但 Kubernetes 会给 namespace 自动加上标准标签:
kubernetes.io/metadata.name=<namespace-name>所以可以这样允许某个 namespace 访问:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-gateway
namespace: app
spec:
podSelector:
matchLabels:
app: api
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: gateway
ports:
- protocol: TCP
port: 8080这表示:允许 gateway namespace 中的 Pod 访问 app namespace 下 app=api 的 Pod 的 8080 端口。
ipBlock#
ipBlock 用于匹配 CIDR。
例如允许访问外部网段:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-egress-to-external-api
namespace: app
spec:
podSelector:
matchLabels:
app: worker
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 203.0.113.0/24
except:
- 203.0.113.10/32
ports:
- protocol: TCP
port: 443这表示:app=worker 的 Pod 可以访问 203.0.113.0/24 的 443 端口,但排除 203.0.113.10。
需要注意的是,ipBlock 适合外部地址或明确的 CIDR,不适合直接拿来描述动态变化的 Pod 集合。Pod 之间访问优先使用 podSelector 和 namespaceSelector。
常见使用场景#
多租户 namespace 隔离#
每个团队一个 namespace,默认拒绝跨 namespace 访问,只开放公共入口。
team-a namespace
team-b namespace
shared-gateway namespace策略思路:
- 每个业务 namespace 默认 deny ingress。
- 只允许网关、监控、必要的共享服务访问。
- 业务间调用显式开白名单。
数据库只允许应用访问#
数据库 Pod 不应该被整个集群随便访问。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-api-to-postgres
namespace: app
spec:
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: api
ports:
- protocol: TCP
port: 5432控制出站访问#
一些环境要求应用只能访问固定外部服务。
可以用 egress 策略把出站限制在:
- DNS。
- 内部 Service。
- 指定外部 CIDR 和端口。
这类场景要小心依赖方是否使用动态 IP。如果目标是域名,Kubernetes 原生 NetworkPolicy 不能直接按 FQDN 匹配,通常要依赖 CNI 扩展能力或通过固定出口代理收敛。
排查命令#
查看策略:
kubectl get networkpolicy -A
kubectl describe networkpolicy -n app
kubectl get networkpolicy -n app -o yaml查看 Pod 标签:
kubectl get pod -n app --show-labels
kubectl get ns --show-labels临时起一个测试 Pod:
kubectl run -n app -it --rm netshoot --image=nicolaka/netshoot -- bash测试访问:
curl -v http://api.app.svc.cluster.local:8080
nc -vz postgres.app.svc.cluster.local 5432
nslookup kubernetes.default.svc.cluster.local排查顺序:
1. CNI 是否支持 NetworkPolicy
2. 策略是否在正确 namespace
3. podSelector 是否真的选中了目标 Pod
4. policyTypes 是否包含方向
5. ingress/egress 是否同时满足
6. namespaceSelector 和 podSelector 是否写在了正确层级
7. DNS egress 是否被误拦截
8. 是否存在 CNI 自己的扩展策略影响结果常见误区#
创建策略就一定生效#
不一定。必须有支持 NetworkPolicy 的 CNI 插件执行规则。
NetworkPolicy 是显式 deny 规则#
不是。Kubernetes 原生 NetworkPolicy 是 allow-list 模型,多条策略之间是加法并集。
只写 ingress 就能限制 Pod 访问外部#
不能。限制出站要写 Egress。
Service 被允许就等于后端 Pod 被允许#
NetworkPolicy 最终还是作用在 Pod 连接上。访问 Service 时,流量最终会到后端 Pod,仍要看目标 Pod 的 ingress 策略和源 Pod 的 egress 策略。
可以按域名写策略#
Kubernetes 原生 NetworkPolicy 不支持按 FQDN 写规则。按域名控制通常依赖 CNI 扩展或出口代理。
小结#
NetworkPolicy 的关键点可以压缩成几句话:
默认全通;
被策略选中后,进入指定方向的隔离状态;
策略只做 allow,不做显式 deny;
多条策略叠加取并集;
Pod 到 Pod 成功访问需要源 egress 和目标 ingress 都允许;
实际执行依赖支持 NetworkPolicy 的 CNI。理解这几个规则,再看 YAML 就不会被 podSelector、namespaceSelector、policyTypes 绕进去。