Skip to content
Published on

Kubernetes Network Policy 与 Service Mesh 完全指南(Istio、Cilium、Calico 对比)

分享
Authors
Kubernetes Network Policy 与 Service Mesh 架构

前言

在 Kubernetes 集群中,Pod 之间的通信默认处于全部允许(allow-all)状态。也就是说,只要在同一个集群内,任何 Pod 都可以自由访问其他 Pod。在小规模的开发环境中这算不上什么问题,但如果是生产环境中运行着几十、几百个微服务的场景,这就会成为严重的安全威胁。

因为一旦攻击者攻陷了其中一个 Pod,就能在集群内向所有服务进行横向移动(lateral movement)。要防止这种情况,通过Network Policy实现网络分段,以及通过Service Mesh实现 mTLS 加密与零信任架构,都是必不可少的。

本文将从 Kubernetes Network Policy 的基础一直讲到进阶用法,并对比分析 Istio、Cilium、Calico 三种方案的 Service Mesh 架构。文中还包含实际运维中可能遇到的排障案例与性能基准测试,帮助你为自己的环境做出最合适的选择。

Kubernetes Network Policy 基础

什么是 Network Policy?

Network Policy 是 Kubernetes 原生资源,是在 Pod 层面控制入站(Ingress)与出站(Egress)流量的防火墙规则。它基于标签选择器工作,即使 Pod 重启或在节点之间迁移,也能应用一致的策略。

重要的前提条件:即使创建了 Network Policy 资源,如果没有实现它的 CNI 插件(Calico、Cilium、Antrea 等),策略也完全不会生效。默认的 kubenet 或 Flannel 并不支持 Network Policy。

Default Deny 策略

所有网络安全的起点都是Default Deny策略。先阻断全部流量,然后只显式放行必要的通信,采用白名单方式。

# default-deny-all.yaml
# 阻断命名空间内所有 Pod 的 Ingress/Egress 流量
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {} # 空选择器 = 命名空间内的所有 Pod
  policyTypes:
    - Ingress
    - Egress

这条策略生效后,production 命名空间中所有 Pod 的入站/出站流量都会被完全阻断。由于连 DNS 查询都无法进行,因此必须同时应用允许 DNS 的策略。

# allow-dns.yaml
# 允许访问 kube-dns(CoreDNS) 的策略
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53

放行 Pod 之间的特定通信

下面是在 Default Deny 状态下,允许前端访问后端 API 的示例。

# allow-frontend-to-backend.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend-api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

这条策略只允许带有 app: frontend 标签的 Pod 访问 app: backend-api Pod 的 TCP 8080 端口的入站流量。

Network Policy 进阶:Egress、CIDR 与端口控制

用 Egress 策略控制外部访问

当微服务需要访问外部 API 或数据库时,可以用 Egress 策略精细地限制放行对象。

# egress-external-api-and-db.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-egress-policy
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend-api
  policyTypes:
    - Egress
  egress:
    # 1. 允许访问同一命名空间的 Redis
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
    # 2. 访问外部 PostgreSQL RDS(基于 CIDR)
    - to:
        - ipBlock:
            cidr: 10.100.0.0/16
      ports:
        - protocol: TCP
          port: 5432
    # 3. 允许访问外部 HTTPS API
    - to:
        - ipBlock:
            cidr: 0.0.0.0/0
            except:
              - 10.0.0.0/8
              - 172.16.0.0/12
              - 192.168.0.0/16
      ports:
        - protocol: TCP
          port: 443
    # 4. 允许 DNS
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53

控制命名空间之间的通信

在多租户环境中,命名空间之间的隔离是必需的。下面是只允许特定命名空间访问的模式。

# cross-namespace-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-monitoring-access
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend-api
  policyTypes:
    - Ingress
  ingress:
    # 只允许 monitoring 命名空间的 Prometheus 抓取指标
    - from:
        - namespaceSelector:
            matchLabels:
              team: monitoring
          podSelector:
            matchLabels:
              app: prometheus
      ports:
        - protocol: TCP
          port: 9090

Network Policy 的局限

Kubernetes 内置的 Network Policy 只能做 L3/L4 层面(IP、端口、协议)的控制。以下需求靠内置的 Network Policy 无法满足:

  • 基于 L7(HTTP 路径、方法、请求头)的过滤
  • mTLS 加密与服务身份认证
  • 流量可观测性(Observability)与分布式追踪
  • 高级流量管理(金丝雀发布、熔断、重试)
  • 基于 FQDN(域名)的 Egress 控制

当需要这些高级能力时,Service Mesh 就登场了。

Service Mesh 架构对比(Istio vs Cilium vs Calico)

下面对三种主流方案的架构与功能进行对比。

项目Istio(Ambient Mode)Cilium Service MeshCalico(Enterprise)
数据平面ztunnel(L4) + Waypoint Proxy(L7)eBPF(L3/L4) + 每节点 Envoy(L7)iptables/eBPF + Envoy(L7)
Sidecar不需要(Ambient Mode)不需要可选
mTLS自动(HBONE 协议)WireGuard/IPsecWireGuard 手动配置
L7 策略AuthorizationPolicyCiliumNetworkPolicyGlobalNetworkPolicy
可观测性Kiali、Jaeger、PrometheusHubble(内置)Calico Enterprise UI
性能开销中(经由 ztunnel)低(内核层)
CPU 使用量一般少 30%(以 L4 为准)一般
QPS 性能高(低连接数时优秀)高(高连接数时优秀)一般
多集群支持(East-West Gateway)支持 Cluster Mesh支持 Federation
学习曲线中等中等
社区非常大(CNCF Graduated)大(CNCF Graduated)大(Tigera 主导)
Windows 节点不支持不支持支持
最佳使用场景大规模多集群、L7 精细控制高性能 L4、基于 eBPF 的可观测混合环境、企业合规要求

架构选型标准

  • 只需要纯粹的 L3/L4 网络安全:Kubernetes 内置 Network Policy + Calico/Cilium CNI
  • L7 流量管理 + mTLS 是核心诉求:Istio Ambient Mode
  • 高性能 + 内核层可观测性:Cilium Service Mesh
  • 企业合规要求 + 混合环境:Calico Enterprise

基于 Istio 构建 Service Mesh

安装 Istio Ambient Mode

从 Istio 1.24 起,Ambient Mode 正式 GA。相比传统 Sidecar 方式,它把 CPU/内存开销降低了 90% 以上,同时依然提供 mTLS 与 L7 流量管理能力。

# 安装 istioctl
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.24.2 sh -
export PATH="$HOME/istio-1.24.2/bin:$PATH"

# 以 Ambient profile 安装
istioctl install --set profile=ambient --skip-confirmation

# 确认安装结果
kubectl get pods -n istio-system
# NAME                                   READY   STATUS    RESTARTS   AGE
# istiod-7b69f4b6c-xxxxx                 1/1     Running   0          60s
# ztunnel-xxxxx                          1/1     Running   0          60s
# istio-cni-node-xxxxx                   1/1     Running   0          60s

# 为命名空间启用 Ambient 模式
kubectl label namespace production istio.io/dataplane-mode=ambient

部署 Waypoint Proxy(用于 L7 策略)

如果只需要 L4 层面的 mTLS,仅靠 ztunnel 就足够了。若需要 L7 层面的精细流量控制,则要额外部署 Waypoint Proxy。

# 创建 Waypoint Proxy
istioctl waypoint apply --namespace production --name backend-waypoint

# 把 Waypoint 关联到指定 Service
kubectl label service backend-api \
  istio.io/use-waypoint=backend-waypoint \
  -n production

配置 Istio AuthorizationPolicy

Istio 的 L7 策略通过 AuthorizationPolicy 控制到 HTTP 方法、路径、请求头级别。

# istio-auth-policy.yaml
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
  name: backend-api-policy
  namespace: production
spec:
  targetRefs:
    - kind: Service
      group: ''
      name: backend-api
  action: ALLOW
  rules:
    - from:
        - source:
            principals:
              - 'cluster.local/ns/production/sa/frontend'
      to:
        - operation:
            methods: ['GET', 'POST']
            paths: ['/api/v1/*']
    - from:
        - source:
            principals:
              - 'cluster.local/ns/monitoring/sa/prometheus'
      to:
        - operation:
            methods: ['GET']
            paths: ['/metrics']

这条策略只允许 frontend 服务账号对 /api/v1/ 路径发起 GET、POST 请求,只允许 Prometheus 对 /metrics 路径发起 GET 请求。其余所有请求都会被以 403 Forbidden 拒绝。

基于 Cilium 的 eBPF Service Mesh

安装 Cilium 并启用 Service Mesh

Cilium 利用 eBPF 在内核层处理网络。它不需要 Sidecar 代理即可处理 L4 流量,只有在需要 L7 处理时才使用每个节点共享的 Envoy 代理。

# 安装 Cilium CLI
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
curl -L --fail --remote-name-all \
  "https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-${GOOS}-${GOARCH}.tar.gz"
sudo tar xzvfC "cilium-${GOOS}-${GOARCH}.tar.gz" /usr/local/bin

# 用 Helm 安装 Cilium(启用 Service Mesh + Hubble)
helm repo add cilium https://helm.cilium.io/
helm repo update

helm install cilium cilium/cilium --version 1.17.0 \
  --namespace kube-system \
  --set kubeProxyReplacement=true \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set envoy.enabled=true \
  --set encryption.enabled=true \
  --set encryption.type=wireguard

# 确认安装结果
cilium status --wait
cilium connectivity test

用 CiliumNetworkPolicy 应用 L7 策略

Cilium 通过自有 CRD CiliumNetworkPolicy,支持 HTTP、gRPC、Kafka 等 L7 协议级别的精细策略。

# cilium-l7-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: backend-l7-policy
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: backend-api
  ingress:
    - fromEndpoints:
        - matchLabels:
            app: frontend
      toPorts:
        - ports:
            - port: '8080'
              protocol: TCP
          rules:
            http:
              - method: 'GET'
                path: '/api/v1/products'
              - method: 'POST'
                path: '/api/v1/orders'
              - method: 'GET'
                path: '/healthz'
    - fromEndpoints:
        - matchLabels:
            app: prometheus
      toPorts:
        - ports:
            - port: '9090'
              protocol: TCP
          rules:
            http:
              - method: 'GET'
                path: '/metrics'

用 Hubble 做网络观测

Cilium 的 Hubble 基于 eBPF,可以实时监控所有网络流量。

# 安装 Hubble CLI 后进行观测
hubble observe --namespace production --follow

# 只过滤特定 Pod 的流量
hubble observe --namespace production \
  --to-label app=backend-api \
  --verdict DROPPED

# 观测 HTTP 请求(L7)
hubble observe --namespace production \
  --protocol http \
  --http-status 5xx

# 网络流量可视化(Hubble UI)
cilium hubble port-forward &
# 在浏览器中访问 http://localhost:12000

Hubble 的输出示例:

TIMESTAMP             SOURCE                  DESTINATION             TYPE      VERDICT   SUMMARY
Mar 14 10:23:01.123   production/frontend     production/backend-api  L7/HTTP   FORWARDED GET /api/v1/products => 200
Mar 14 10:23:01.456   production/attacker     production/backend-api  L7/HTTP   DROPPED   POST /api/v1/admin => Policy denied
Mar 14 10:23:02.789   production/backend-api  production/redis        L4/TCP    FORWARDED TCP 6379

mTLS 与零信任网络

什么是零信任?

零信任(Zero Trust)是一种“不信任任何东西,验证所有东西”的安全模型。它要求集群内部通信也必须加密,并在所有服务间调用中验证身份。由于仅靠 Network Policy 无法加密流量,因此需要提供 mTLS(mutual TLS)的 Service Mesh。

Istio Ambient Mode 的 mTLS

Istio Ambient Mode 使用HBONE(HTTP-Based Overlay Network Environment)协议,把所有流量自动进行 mTLS 加密。ztunnel 在节点层面管理证书,并为每个 Pod 签发唯一的、基于 SPIFFE 的工作负载 ID。

# istio-peer-auth.yaml
# STRICT 模式:拒绝非 mTLS 的明文流量
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: strict-mtls
  namespace: production
spec:
  mtls:
    mode: STRICT

设置为 STRICT 模式后,该命名空间内的所有服务只接受 mTLS 连接。来自网格之外服务的明文请求会被全部拒绝。

Cilium 基于 WireGuard 的加密

Cilium 使用内核自带的 WireGuard 自动加密节点之间的流量。与 Istio 的 mTLS 不同,它工作在内核层而非应用层,因此性能开销更小。

# 确认 WireGuard 加密状态
cilium encrypt status

# 输出示例:
# Encryption:  Wireguard
# Keys in use: 2
# Errors:      0
# Interfaces:  cilium_wg0

# 查看加密密钥列表
cilium encrypt get

WireGuard 与 mTLS 的差异:

  • WireGuard:节点之间的 L3 层加密,内核层处理,不为每个 Pod 分配单独身份
  • mTLS(Istio):服务之间的 L7 层加密,基于 SPIFFE 的工作负载 ID,可做精细的授权策略

在生产环境中,也有团队采用双重安全策略:先用 Cilium WireGuard 做节点间加密,再叠加 Istio mTLS 实现工作负载级别的身份认证。

运维注意事项与排障

1. 注意 Network Policy 的叠加方式

Network Policy 以并集(additive)方式工作。当多条策略作用于同一个 Pod 时,放行规则会被合并。存在冲突的策略时,并不是拒绝规则优先,而是只要有任意一条放行,流量就会通过。

# 确认作用于特定 Pod 的所有 Network Policy
kubectl get networkpolicy -n production -o wide

# 确认 Pod 标签(验证策略选择器是否匹配)
kubectl get pods -n production --show-labels

# 使用 Calico 时确认策略匹配情况
calicoctl get networkpolicy -n production -o yaml

2. 未安装 CNI 插件时 Network Policy 被忽略

这是最常见的失误。即使创建了 Network Policy 资源,只要没有实现它的 CNI 插件,策略就完全不会生效。

# 确认 CNI 插件
kubectl get pods -n kube-system | grep -E 'calico|cilium|antrea'

# 验证 Network Policy 是否真的生效的测试
# 1. 应用 Default Deny
kubectl apply -f default-deny-all.yaml

# 2. 通信测试(被阻断才是正常)
kubectl exec -n production deploy/frontend -- \
  curl -s --connect-timeout 3 http://backend-api:8080/healthz
# 出现超时就说明策略已经正确生效

3. DNS 解析失败

应用 Default Deny 策略后如果漏掉了 DNS 放行,所有服务发现都会中断。

# 诊断 DNS 问题
kubectl exec -n production deploy/frontend -- nslookup backend-api
# ;; connection timed out; no servers could be reached

# 确认 CoreDNS Pod
kubectl get pods -n kube-system -l k8s-app=kube-dns

# 应用 DNS 策略后重新测试
kubectl apply -f allow-dns.yaml
kubectl exec -n production deploy/frontend -- nslookup backend-api
# Server:    10.96.0.10
# Name:      backend-api.production.svc.cluster.local

4. 应对 Istio ztunnel 故障

ztunnel 以每节点 DaemonSet 的形式运行,一旦发生故障,该节点上所有 Ambient Mesh 流量都会中断。

# 确认 ztunnel 状态
kubectl get pods -n istio-system -l app=ztunnel

# 确认 ztunnel 日志(诊断证书问题)
kubectl logs -n istio-system -l app=ztunnel --tail=50

# 重启 ztunnel
kubectl rollout restart daemonset/ztunnel -n istio-system

# 确认与 Istiod 的 xDS 连接状态
istioctl proxy-status

5. Cilium eBPF map 容量超限

在大规模集群中,Cilium eBPF map 的默认大小可能不够用。

# 确认 eBPF map 使用量
cilium bpf ct list global | wc -l
cilium bpf policy get --all

# 增大 map 大小(修改 Helm values)
# bpf.ctGlobalTCPMax: 524288  (比默认值更大)
# bpf.ctGlobalAnyMax: 262144
# bpf.policyMapMax: 65536

# 应用变更
helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --reuse-values \
  --set bpf.ctGlobalTCPMax=524288

故障案例与恢复流程

案例 1:错误的 Egress 策略导致全站服务中断

状况:运维团队为了加强安全应用了 Default Deny Egress,却漏掉了 DNS 放行策略,导致所有服务之间的通信中断。

症状:所有 Pod 通过服务名访问都失败。直接指定 IP 时则可以通信。

恢复流程

# 1. 立即确认问题
kubectl get networkpolicy -n production

# 2. 紧急应用 DNS 放行策略
kubectl apply -f - <<'POLICY'
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: emergency-allow-dns
  namespace: production
spec:
  podSelector: {}
  policyTypes:
    - Egress
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53
        - protocol: TCP
          port: 53
POLICY

# 3. 确认服务已恢复
kubectl exec -n production deploy/frontend -- nslookup backend-api

教训:Default Deny 策略必须与 DNS 放行策略一起应用。变更策略前一定要在预发环境测试,并准备好回滚方案。

案例 2:Istio 升级过程中的 mTLS 不匹配

状况:在 Istio 版本升级过程中,旧版本 Sidecar 与新版本 ztunnel 之间的 mTLS 握手失败。

症状:部分服务之间出现 503 错误以及“upstream connect error”消息。

恢复流程

# 1. 把 mTLS 模式临时改为 PERMISSIVE(明文和 mTLS 都允许)
kubectl apply -f - <<'POLICY'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: permissive-during-upgrade
  namespace: production
spec:
  mtls:
    mode: PERMISSIVE
POLICY

# 2. 重启所有工作负载以应用最新代理
kubectl rollout restart deployment -n production

# 3. 所有 Pod 都替换为新版本后恢复 STRICT
kubectl rollout status deployment -n production --timeout=300s
kubectl apply -f - <<'POLICY'
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
  name: strict-mtls
  namespace: production
spec:
  mtls:
    mode: STRICT
POLICY

案例 3:Cilium Agent 重启导致瞬时流量丢弃

状况:在更新 Cilium DaemonSet 的过程中,节点上的 eBPF 程序被短暂卸载,导致该节点上 Pod 之间的通信中断了数秒。

恢复与预防

# 采用 Rolling Update 策略逐个节点更新
helm upgrade cilium cilium/cilium \
  --namespace kube-system \
  --reuse-values \
  --set upgradeCompatibility=1.16 \
  --set rollOutCiliumPods=true

# 确认 PodDisruptionBudget
kubectl get pdb -n kube-system

# 监控更新进度
kubectl rollout status daemonset/cilium -n kube-system --timeout=600s

性能基准与选型指南

实测基准结果(2025 年)

下面汇总近期在大规模企业环境中的对比测试结果。

指标Network Policy OnlyIstio AmbientCilium Service Mesh
P99 延迟(ms)1.23.82.1
QPS(请求/秒)45,00038,00042,000
QPS per Core-2,1781,815
CPU 开销基准+15%+8%
内存开销基准+120MB/节点+80MB/节点
低连接数性能-优秀一般
高连接数性能-一般优秀

注意:Istio 的 QPS per Core 较高,是因为该数值包含了 L7 处理能力;而 Cilium 的 CPU 测量中未计入内核内 WireGuard 加密的开销,这一点需要纳入考量。

选型指南流程图

  1. 是否只需要 L3/L4 网络隔离?

    • 是:Kubernetes Network Policy + Calico 或 Cilium CNI 就足够
    • 否:进入第 2 步
  2. 是否需要 L7 流量管理(金丝雀、重试、熔断)?

    • 是:Istio Ambient Mode 或 Cilium + Envoy
    • 否:进入第 3 步
  3. 基于 mTLS 的零信任是否为硬性要求?

    • 是:Istio Ambient Mode(基于 SPIFFE 的工作负载 ID)
    • 否:用 Cilium WireGuard 做节点间加密
  4. 是否优先考虑高性能 + 内核层可观测性?

    • 是:Cilium Service Mesh + Hubble
    • 否:Istio(L7 功能更丰富)
  5. 是否混用 Windows 节点或属于混合环境?

    • 是:Calico Enterprise
    • 否:Istio 或 Cilium

按运维规模给出的建议

  • 小规模集群(10 个节点以下):Cilium CNI + 基础 Network Policy。引入 Service Mesh 的收益不足以抵消其开销。
  • 中等规模集群(10~100 个节点):Cilium Service Mesh 或 Istio Ambient,按 L7 需求来选。
  • 大规模集群(100 个节点以上):Istio Ambient Mode,多集群支持成熟、生态丰富、稳定性好。
  • 混合云/多云:Calico Enterprise 或 Cilium Cluster Mesh。

结语

Kubernetes 网络安全不只是应用 Network Policy 那么简单,还需要一套契合应用特性与安全要求的整体策略。

核心要点:

  • Network Policy 是基础中的基础:请务必从 Default Deny 开始,采用只放行必要通信的白名单方式。不要忘记 DNS 放行策略。
  • Service Mesh 要在需要时才引入:请在确实需要 mTLS、L7 策略、高级流量管理的时点再引入。不必要的复杂度反而会加重运维负担。
  • Istio 与 Cilium 之间是权衡取舍:Istio 的 L7 功能与生态更丰富,Cilium 的强项是内核层性能与可观测性。请结合需求来选择。
  • 循序渐进是关键:从 Default Deny 策略开始,充分验证 Network Policy 之后,再按需要追加 Service Mesh,这样的分阶段推进最为稳妥。
  • 自动化与测试:策略变更一定要通过 CI/CD 流水线先在预发环境验证,并始终备好回滚方案。

网络安全不是设置一次就一劳永逸的事情。随着服务的演进,策略也需要持续复查和更新。建议每季度做一次策略审计,并利用 Hubble 或 Kiali 这类观测工具,基于真实流量模式来优化策略。

参考资料