bigywater.tech
Kubernetes · 75

NetworkPolicy:默认拒绝和选择器语义

NetworkPolicy 的 default-deny 到底拒绝了什么?from 里 podSelector 和 namespaceSelector 写在一起和分开写有什么区别?为什么加了 egress 限制之后域名解析就坏了?这篇用 3 个客户端、2 个命名空间的连通性矩阵一项项验证。

超时而不是拒绝
被 NetworkPolicy 拒绝的连接,客户端看到的是 wget 超时(包被 DROP)
且 vs 或
同一个 from 条目里写两种选择器是“且”,分成两个条目是“或”
DNS 一起被拦
egress default-deny 后,用 IP 访问和用 Service 名访问都超时

没有策略:全通

实测 · 本机执行输出
  连通性:{'同命名空间 role=frontend': 'ok', '同命名空间 role=other': 'ok', 'k69b 命名空间 role=frontend': 'ok'}

kind 默认的 CNI kindnet 自带 NetworkPolicy 实现。server(命名空间 k69,label team=blue)没有任何策略时,同命名空间的 role=frontend、role=other 和另一个命名空间 k69b(team=red)的 role=frontend 都能连上。NetworkPolicy 是由 CNI 插件执行的,没有支持它的 CNI 就是一个没有效果的对象。

default-deny

实测 · 本机执行输出
  应用策略后,第一次探测到 frontend 连不上用了 1.1 秒(探测本身每次最多等 1 秒)
  连通性:{'同命名空间 role=frontend': '超时', '同命名空间 role=other': '超时', 'k69b 命名空间 role=frontend': '超时'}
  被拒的连接表现为“超时”(wget -T 3 用时 3.1 秒)——包被 DROP,没有 RST,客户端只能等超时
  default-deny ingress 只管进来的:front 自己往外查 DNS 仍然成功(退出码 0)→ 'Address: 10.96.0.1'

应用 podSelector: {} + policyTypes: [Ingress] 且不写任何 ingress 规则:第一次探测到 frontend 连不上用了 1.1 秒;三个客户端全部超时。被拒的连接不是 Connection refused 而是 wget 等了 3.1 秒超时——包被直接 DROP,没有 RST。这条策略只管进来的方向:front 自己往外查 DNS 仍然成功。

且与或

实测 · 本机执行输出
  只写 podSelector(role=frontend):{'同命名空间 role=frontend': 'ok', '同命名空间 role=other': '超时', 'k69b 命名空间 role=frontend': '超时'}(podSelector 不带 namespaceSelector 时只匹配策略所在命名空间的 Pod)
  同一个 from 条目里 namespaceSelector(team=red)+ podSelector(role=frontend)= 且:{'同命名空间 role=frontend': '超时', '同命名空间 role=other': '超时', 'k69b 命名空间 role=frontend': 'ok'}
  拆成两个 from 条目(多了一个短横线)= 或:{'同命名空间 role=frontend': 'ok', '同命名空间 role=other': '超时', 'k69b 命名空间 role=frontend': 'ok'}(team=red 的所有 Pod + 本命名空间的 frontend)

放行规则的写法决定结果。只写 podSelector: {role: frontend}:只匹配策略所在命名空间的 Pod,同命名空间 frontend 通,k69b 的 frontend 超时。同一个 from 条目里同时写 namespaceSelector: {team: red} 和 podSelector: {role: frontend} 是“且”,只有 k69b 的 frontend 能连。拆成两个条目(两个短横线)就是“或”:同命名空间 frontend 和 k69b 的 frontend 都能连,role=other 始终不行。少写一个短横线,放行范围就完全不同。

并集与 egress

实测 · 本机执行输出
  再加一条 allow-other(放行 role=other):{'同命名空间 role=frontend': 'ok', '同命名空间 role=other': 'ok', 'k69b 命名空间 role=frontend': 'ok'}(多条策略取并集,没有“拒绝”规则)
  先删掉所有策略,front 用 Service 名访问:ok
  对 role=frontend 加 default-deny egress:用 IP 访问 超时;用 Service 名访问 超时(DNS 查询也走 egress,被一起拦了)
    nslookup server:;; connection timed out; no servers could be reached
  放行到 kube-system:53 和到 server:80 之后:用 IP ok;用 Service 名 ok

再加一条放行 role=other 的策略,三个客户端全部变成 ok:多条策略取并集,只能“放行”,不存在“拒绝”规则。对 role=frontend 设 egress 的 default-deny 后,用 IP 访问 server 超时,用 Service 名访问也超时,nslookup server 报 connection timed out——DNS 查询同样走 egress。放行到 kube-system 的 53(UDP 和 TCP)以及到 server 的 80 之后,两种访问方式都恢复。

分步演示

NetworkPolicy
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0),CNI 是 kind 默认的 kindnet(自带 NetworkPolicy);server 是 nginx:1.27-alpine,客户端是 busybox 的 wget(-T 2 或 -T 3);“超时”指耗时接近 -T 的失败;每种情形各一次
    • 没有验证:其他 CNI(Calico、Cilium)的行为差异;ipBlock 与 SCTP / 端口范围(endPort);策略对已建立连接的影响;hostNetwork Pod 与节点自身流量是否受策略约束;NodePort / Service 流量在策略检查前后是否已 DNAT;AdminNetworkPolicy;日志与审计
    京ICP备2026067502号-1京公网安备11010502063487号