Cilium 网络策略实战:用 eBPF 打造 Kubernetes Zero-Trust 安全

当微服务在 Kubernetes 里横向扩散,传统 kube-proxy 的 iptables 规则只能做服务发现和负载均衡,却对”谁可以访问谁”一无所知。Cilium 网络策略基于 eBPF 在内核层实现细粒度访问控制,让 Zero-Trust(零信任)不再是一句口号。本文从安装到 L7 策略,带你用 Cilium 给集群装上”看得见的防火墙”。

一、iptables 为什么管不了”信任”

默认情况下,Kubernetes 的 Pod 网络是扁平的:任何 Pod 都能访问任何 Pod。kube-proxy 用 iptables 做 NAT 和转发,但它工作在 L3/L4 且只关心”怎么把包送到后端”,不关心”该不该送”。CNI 插件如 Calico 可以补 NetworkPolicy,但传统实现仍依赖 iptables 链式匹配,规则一多就线性扫描、性能陡降。

更深层的问题是:在 Kubernetes 里 Pod IP 是临时的,每次调度、扩缩容都会换一批新地址。你写在云安全组或宿主机 iptables 里的”放行 10.244.3.0/24″几乎一上线就过时。传统基于 IP 的防火墙,本质是给一个时刻在变形的对象画固定边界,天然失效。这也是为什么零信任架构强调”以身份为中心”而非”以网络位置为中心”。

Cilium 的思路完全不同:它用 eBPF 程序直接挂载在内核的网络栈钩子上,绕过 iptables 的繁冗链条,在 socket 层就能识别身份(基于 Pod 标签、ServiceAccount 乃至 HTTP 路径),既快又细。这与我们之前在 eBPF 内核观测 中用到的高效数据面思路一脉相承。

二、用 Helm 安装 Cilium(替换 kube-proxy)

最干净的方式是让 Cilium 以 kube-proxy 替代模式运行,连 iptables 规则都省了。下面是一组生产可用的安装参数:

helm repo add cilium https://helm.cilium.io/
helm repo update

helm install cilium cilium/cilium --version 1.16.0 \
  --namespace kube-system \
  --set kubeProxyReplacement=true \
  --set k8sServiceHost=$KUBERNETES_SERVICE_HOST \
  --set k8sServicePort=$KUBERNETES_SERVICE_PORT \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set securityContext.privileged=true

安装后,用自带的健康检查确认数据面就绪:

cilium status --wait
# ✓ Encapsulation: Disabled
# ✓ Controller Status:  34/34 healthy
# ✓ KubeProxyReplacement: Proxy replacement enabled

切换到 kube-proxy 替代模式后,服务负载均衡从 iptables 的随机匹配升级为 eBPF 的 Maglev 一致性哈希,连接跟踪不再依赖全局 conntrack 表,在大连接数下能显著降低内核开销与尾延迟。对高并发入口服务而言,这是性能与安全的双重收益。

三、Cilium 的身份模型:用标签而非 IP 寻址

Cilium 的核心抽象是”端点身份(Endpoint Identity)”。每个 Pod 启动时被分配一个基于标签推导出的数字身份,策略匹配的是这个身份,而不是随时会变的 IP。换句话说,后端扩容到 20 个 Pod、IP 全换,只要标签不变,网络策略完全不用动。这恰好补上了传统防火墙在动态环境下的短板。

也正因为身份与 IP 解耦,微分段(micro-segmentation)才真正可行:你可以把”订单服务””支付服务””用户服务”按业务语义隔离,而不是按”10.244.5.0/24 这个网段”隔离。安全策略第一次变得和架构图一致。

四、默认拒绝:先给命名空间上锁

Zero-Trust 的第一步是”默认什么都不信”。先对一个命名空间下发 deny-all 策略,把东西向流量全部切断,再按需放行:

apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
  name: default-deny-ingress
spec:
  endpointSelector: {}
  ingress: []

这条 Clusterwide 策略对所有端点生效(endpointSelector: {}),ingress: [] 表示不放行任何入向流量。此时 Pod 之间彻底隔离,连通性测试会全部超时——这正是我们想要的底色。

五、L3/L4 策略:按标签放行

现在放行”前端可以访问后端的 8080 端口”。Cilium 用标签选择器表达意图,比原生 NetworkPolicy 更直观:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: frontend-to-backend
  namespace: shop
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
        io.kubernetes.pod.namespace: shop
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP

在真实多租户场景里,这一步还能叠加命名空间级隔离:不同租户的前端即便都叫 frontend,只要 io.kubernetes.pod.namespace 不同,就互不可达。身份维度的组合让”同标签跨租户”这类经典越权被天然阻断。

下表对比了三类主流网络策略方案的落地差异:

方案数据面L7 支持可观测性
原生 NetworkPolicy + iptablesiptables 链式无弱
Calicoiptables / eBPF 可选部分(需 Istio)中
CiliumeBPF原生 HTTP/gRPC/Kafka强(Hubble)

六、L7 策略:在 HTTP 层精细管控

真正的零信任要能识别”方法 + 路径”。比如只允许 GET /api/products,拒绝 POST /api/admin。Cilium 通过 Envoy 代理注入实现 L7 过滤:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: backend-l7
  namespace: shop
spec:
  endpointSelector:
    matchLabels:
      app: backend
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/api/products"

加上 L7 规则后,不匹配的 HTTP 请求会直接被 Cilium 在内核层拒绝,后端根本收不到报文。下面是 Cilium 与传统方案的对比要点:

维度Cilium传统 iptables CNI
规则匹配位置内核 eBPF 钩子netfilter 链
大规模规则性能接近 O(1)线性扫描
身份来源标签 / SA / L7 头仅 IP/端口
运维复杂度中低

七、可观测性:用 Hubble 看清每一个连接

策略生效后是黑盒?Cilium 内置的 Hubble 把每个连接的五元组、策略判决、延迟都导出成流日志。本地排障一条命令即可:

hubble observe --namespace shop --follow \
  --protocol http \
  --to-pod backend
# Oct 01 10:22:31.123  frontend  backend  http-request  GET /api/products   -> 200
# Oct 01 10:22:33.456  frontend  backend  http-request  POST /api/admin     -> FORWARDED (dropped by policy)

Hubble UI 还能画出服务依赖拓扑图,配合 Prometheus + Grafana 监控 可以把策略拒绝数做成告警,让零信任策略的每一次拦截都看得见。

八、常见误区与排障

落地时最容易踩的坑有几个。第一,DNS 被拦:开了 deny-all 却忘了放行到 kube-dns 的 53 端口,结果所有解析超时,业务”假死”。务必单独加一条放行进 CoreDNS 的策略。第二,L7 代理资源:Envoy sidecar 要吃掉 CPU 和内存,如果不设 requests/limits,高峰期可能 OOM 把 Pod 拖垮。第三,hostPort / 节点本地流量:Cilium 默认不管宿主机网络命名空间,节点级暴露的服务要单独用 host policy 处理。第四,升级顺序:Cilium 自身升级建议先升控制面再升数据面,并利用其滚动重启能力,避免一次性把所有节点 eBPF 程序清空。

排障时优先用 cilium policy get 看哪些端点匹配了哪条规则,再用 hubble observe 确认报文是在哪一层被 drop 的。绝大多数”连不通”都是 deny-all 太狠或标签写错,而不是 Cilium 本身的问题。

九、生产落地检查清单

检查项建议
渐进启用先单命名空间 deny-all,验证业务后再全集群
DNS 放行务必加放行进 kube-dns 的 53 端口,否则解析全挂
L7 代理资源Envoy 需预留 CPU/内存,避免 OOM
策略即代码策略随 Git 入库,走 GitHub Actions 评审发布
灰度验证用 Hubble observe 先观察再收紧,防止误杀

十、与 Nginx / Caddy 的边界

注意分工:Nginx 反向代理 管的是”南北向”入口流量(外部用户 → 集群),而 Cilium 管的是”东西向”Pod 间流量(集群内部)。二者互补,不互相替代。若需要七层入口能力,可叠加 Caddy 或 Gateway API 处理 TLS 终止。纵深防御,才是 Zero-Trust 的本意。

Cilium 把 eBPF 的工程红利真正落到了网络安全上:默认拒绝打底、标签身份寻址、L7 精细管控、Hubble 全程可视。当你的集群规模上来、合规要求变严,这套组合拳会比”全通 + 祈祷”稳得多。它不只是一个网络插件,而是把零信任从 PPT 里的原则,变成了集群里可验证、可观测、可审计的真实防线。

上一篇 vLLM 部署大模型:高吞吐推理服务实战
下一篇 Redis 缓存雪崩、击穿、穿透:三大故障排查与防护
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]