升级 Cilium 后 MySQL 突然拒绝连接全网 5.3 万人围观过的 Masquerading 大坑【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium深夜升级集群helm upgrade cilium一切绿灯第二天业务方报障应用 Pod 连不上 MySQL报Access denied for user授权错误。明明代码没改、账号没删、密码没换数据库日志里显示的却是一个陌生的 client IP——不是你业务 Pod 的地址。这是 2022 年在 Cilium 社区被 5.3 万人围观过的真实事故juejin 上 5.3 万浏览量它的根因正是 Cilium 的Masquerading源地址伪装行为在版本升级后发生了静默改变。本文结合官方文档与仓库源码把这条链路完整拆开表象、根因、排查手段以及升级前必须核对的那几个开关。事故复现升级后 MySQL 授权报错的表象事故的典型场景是这样的集群原本运行 Cilium v1.8.x某个业务 PodIP 如10.244.1.15访问集群外或同 VPC 内的 MySQL 实例升级到 Cilium v1.11.x 后业务 Pod 突然报 MySQL 授权失败ERROR 1045 (28000): Access denied for user app10.0.0.5检查 MySQL 侧的授权表app10.244.1.15是存在的但 MySQL 收到的来源 IP 却变成了节点 IP10.0.0.5于是按新来源 IP匹配授权规则直接拒绝。MySQL 会基于 client IP 做主机维度授权这是最常见的中招点同理任何依赖源 IP 做鉴权/白名单/风控的服务Redis ACL、对象存储桶策略、防火墙规则、审计系统都可能出现类似症状。表象千奇百怪本质只有一个升级前后到达 MySQL 的数据包源地址变了。定位clientIP 被 Masquerading 伪装的根因Cilium 为什么要做 MasqueradingPod 的 IPv4 地址通常从 RFC1918 私网段分配默认不可公网路由。Cilium 会把离开集群的所有流量的源 IP 自动伪装成节点 IP因为节点 IP 在网络上是可路由的。官方文档对默认行为描述得很直接见 Documentation/network/concepts/masquerading.rstCilium will automatically masquerade the source IP address of all traffic that is leaving the cluster to the IPv4 address of the node。换句话说Pod → 集群外 MySQL 的连接源地址被换成节点 IP是 Cilium 的默认设计不是 bug。问题出在什么算集群外/什么算集群内的判定边界在升级后变了。判定边界的两个关键 CIDRCilium 判定是否需要伪装的核心是看目的地址是否落在SNAT 排除 CIDR内。仓库源码pkg/datapath/iptables/iptables.go中remoteSNATDstAddrExclusionCIDR的逻辑非常直白func (m *manager) remoteSNATDstAddrExclusionCIDR(nativeRoutingCIDR, allocCIDR netip.Prefix) netip.Prefix { if nativeRoutingCIDR.IsValid() { // ip{v4,v6}-native-routing-cidr is set, so use it return nativeRoutingCIDR } return allocCIDR }也就是说如果配置了ipv4-native-routing-cidr排除 CIDR 就是它目的地址落在该 CIDR 内的流量不做SNATPod 源 IP 原样送达如果没有配置则退回到本节点 Pod 分配 CIDRallocCIDR。iptables 模式下最终下发的规则链是cilium masquerade non-cluster见同一文件中的allEgressMasqueradeCmds-t nat -A CILIUM_POST_nat -! -d snatDstExclusionCIDR -s allocRange ! -o cilium_ -j MASQUERADE翻译成人话只要目的地址不在排除 CIDR 里且来源是 Pod 地址、出口不是 cilium_ 隧道口一律 MASQUERADE 成节点 IP。升级为什么会让 MySQL 中招结合 v1.8 → v1.11 这个具体区间升级前后最容易踩的坑有三个ipv4-native-routing-cidr未显式配置老版本里原生路由/排除伪装的判定依赖集群 Pod CIDR 等默认推断升级后推断逻辑、IPAM 模式如从 cluster-pool 切换为 ENI/Azure IPAM或节点 CIDR 划分发生变化导致原本被当作集群内可直达、不伪装的 MySQL 地址在新版本里被划到了需要伪装的一侧。于是 Pod 源 IP 消失MySQL 收到的是节点 IP。BPF Masquerading 与 iptables 模式的判定差异文档明确警告见 Documentation/network/concepts/masquerading.rst 与 kubeproxy-free.rsteBPF 实现与 iptables 实现存在行为差异。典型例子是Pod → 节点 External IP 的流量在 eBPF masquerading 下不会被伪装而 iptables 模式会伪装反过来eBPF 模式下 pod-to-remote-node 在 overlay 路由里默认要伪装代码注释里专门提到了 cilium/cilium#12624 这个坑见bpf/lib/nat.h。升级时如果顺手把bpf.masqueradetrue打开了伪装判定边界就整体换了实现行为自然漂移。enable-remote-node-masquerade默认值变化该选项控制发往远端节点地址的流量是否伪装。升级后若被显式/隐式打开Pod → 节点 InternalIP 的流量也会被 SNAT。官方文档还特别提示这会削弱对 Pod → Node 流量的 ingress host firewall 管控建议默认关闭、谨慎开启。BPF 数据路径的判定顺序在bpf/lib/nat.h的__snat_v4_needs_masquerade里写得很清楚先看是否是回包回包不 SNAT→ 看是否命中 egress gateway 策略 → 再看目的地址是否落在ipv4_snat_exclusionCIDR 内命中则放行不 SNAT→ 再看是否命中 ip-masq-agent 的cilium_ipmasq_v4表 → 再判断远端节点/overlay 场景。任何一个边界条件在升级前后的配置差异都可能改变 MySQL 连接最终呈现的源 IP。规避方案与升级前检查清单现场快速止血确认是伪装导致的授权失败后最快的止血手段是在 MySQL/目标服务侧把节点 IP 也加入授权白名单——但这只是临时方案会引入来源不可信的安全问题必须尽快回到正轨。更根本的止血显式配置ipv4-native-routing-cidr把 MySQL 所在网段纳入原生路由、不做伪装的 CIDR。文档给出的语义是ipv4-native-routing-cidr: 10.0.0.0/8或 IPv6 用ipv6-native-routing-cidr该 CIDR 内的所有目的地址不会被伪装。配置后 Pod 源 IP 会原样到达 MySQL授权表无需改动。注意原生路由 CIDR 意味着 Cilium 依赖底层网络栈直接路由这些包需要确保节点间路由/云 VPC 路由真的可达自建集群需配合auto-direct-node-routes或手工路由。利用 ip-masq-agent 做精细豁免如果不想全局放宽native-routing-cidrCilium 还内置了 eBPF 版 ip-masq-agentHelm 选项ipMasqAgent.enabledtrue可以按目的 CIDR 白名单豁免伪装。仓库自带示例 examples/kubernetes-ip-masq-agent/rfc1918.yamlapiVersion: v1 kind: ConfigMap metadata: name: ip-masq-agent data: config: | nonMasqueradeCIDRs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 masqLinkLocal: true默认空配置时agent 会内置 RFC1918 全段、100.64.0.0/10、192.0.0.0/24等一批非伪装 CIDR。把 MySQL 网段加进nonMasqueradeCIDRs就能在不改变整体伪装策略的前提下恢复源 IP。下发后可用cilium-dbg bpf ipmasq list验证豁免表是否生效。升级前检查清单把这次事故沉淀成清单升级 Cilium 前逐项核对记录升级前基线先跑cilium-dbg status | grep Masquerading记下当前 Masquerading 模式BPF 还是 iptables、生效设备与排除 CIDR升级后对比同一输出。命令行参考见 Documentation/network/concepts/masquerading.rst。锁定 masquerading 相关配置在 Helm values 里显式写明bpf.masquerade、enableIPv4Masquerade、enableIPv6Masquerade、ipv4NativeRoutingCIDR、enableRemoteNodeMasquerade、egress-masquerade-interfaces不要依赖默认值漂移。相关选项定义可查 pkg/option/config.go。核对 IPAM 模式与 CIDR升级常伴随 IPAM 模式调整cluster-pool / ENI / Azure / GKE确认ipv4NativeRoutingCIDR与云厂商 VPC CIDR 一致。云环境下若不配置Cilium 会自动探测 VPC CIDR 作为原生路由范围见 masquerading 文档务必确认探测结果符合预期。盘点依赖源 IP 鉴权的服务升级前梳理所有按 client IP 做授权的目标MySQL、Redis、云数据库白名单、防火墙、审计在升级窗口内对它们的连接做抓包对比tcpdump -n host mysql-ip and port 3306即可看到源 IP 是否被替换。灰度与回滚预案先在非核心节点灰度升级用上述抓包/cilium-dbg bpf ipmasq list验证 Pod 源 IP 是否原样到达目标服务保留上一版本 Helm values 快照便于快速回滚或 diff。写在最后这次事故的本质不是 Cilium坏了而是伪装边界的默认判定在版本演进中发生了变化而大多数集群没有显式锁定这些配置导致升级这个动作本身成了变量。Masquerading 是 Cilium 面向公网出口的必要设计但对集群内/同 VPC 内的伪公网流量如云数据库它反而会改写源 IP、破坏基于 IP 的授权模型。升级 Cilium 之前把ipv4-native-routing-cidr、bpf.masquerade、enable-remote-node-masquerade这几个开关逐一显式化比事后在 MySQL 里加一百条白名单更省心——毕竟下一个被 5 万人围观的可能是你的集群。【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考