Istio 1.30.5 修复详解:Ambient 重定向、JWKS HTTP/2 与多集群 kubeconfig 安全

2026-09-21 20 预计阅读时间: 1 分钟
来源: istio.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:12 分钟

Istio 1.30.5 是一次以稳健性为核心的补丁发布。它没有引入醒目的新功能,而是集中解决 1.30.4 中可能导致流量重定向规则重复、JWKS 获取失败、工作负载元数据反复推送、Envoy 无法启动以及本地凭据插件被意外执行的问题。对正在运行 Ambient、多网络网关、外部认证或多集群环境的团队来说,这些修复值得尽快评估。

Ambient 与工作负载发现:减少重复规则和无效推送

Ambient 模式下,CNI 节点代理会自动判断节点使用的是 legacy iptables 还是 nft 后端。此前,这个自动检测结果可能在代理重启后发生变化,导致代理向已经纳管的 Pod 再次写入重定向规则。重复规则不一定立刻表现为故障,但会增加排障难度,也可能造成流量路径与预期不一致。

1.30.5 修复了后端选择在重启间发生翻转的问题。升级后,建议重点观察发生过 CNI 重启或节点维护的集群,而不是只验证新建 Pod。

这次发布还修复了几类工作负载发现问题:

  • istiod 向 Envoy 推送工作负载元数据时,不再反复序列化同一个工作负载。
  • 开启默认的 AMBIENT_SCOPED_ADDRESS_PUSHES 时,仅地址发生变化的工作负载也能通过 MDS 获得增量更新。
  • 一个网络配置多个网关时,网关选择不再因随机顺序而变化,避免每次重新计算都触发不必要的 WDS 推送,也避免工作负载的网关地址来回切换。

这些变化的直接价值不是“增加吞吐量”这么简单,而是减少无意义的控制面计算和配置分发,让代理最终看到的地址与网关选择更加稳定。

升级后可以这样检查 CNI 和控制面的基本状态。执行前请确保当前 kubectl 上下文指向目标集群,并使用 1.30.5 版本的 istioctl

set -euo pipefail

export ISTIO_NAMESPACE=istio-system

kubectl config current-context
istioctl version
istioctl x precheck
istioctl analyze --all-namespaces

kubectl -n "$ISTIO_NAMESPACE" get pods -o wide
kubectl -n "$ISTIO_NAMESPACE" get daemonset -l k8s-app=istio-cni-node
kubectl -n "$ISTIO_NAMESPACE" rollout status deployment/istiod --timeout=5m

如果使用 Ambient 模式,还应在升级前后各做一次节点级验证:重启一个 CNI Pod,确认既有业务 Pod 的连接没有异常,同时观察 CNI 日志中是否出现重复写入或清理重定向规则的迹象。生产环境不要一次重启全部 CNI Pod。

JWKS 再次正确使用 HTTP/2

Istio 的 JWKS resolver 需要从身份提供方获取用于验证 JWT 的公钥。此前,为了实现 TLS 固定和 CIDR 阻断而设置的自定义 TLSClientConfigDialContext,会让 Go 的 net/http 停止自动启用 HTTP/2。由于 ALPN 无法协商出 h2,所有公钥请求都被迫使用 HTTP/1.1。

多数服务器同时支持 HTTP/1.1,因此问题可能长期隐藏。但在某些 HTTP CONNECT 代理链路中,JWKS 请求通过 HTTP/1.1 会失败。1.30.5 重新启用了与 http.DefaultTransport 一致的 HTTP/2 行为,使这些环境能够正常协商 h2

升级验证不应只看 istiod 是否 Ready。更有效的方式是发起一条真实的 JWT 认证请求,并同时检查控制面日志:

# 按实际环境修改命名空间、测试地址和令牌。
export ISTIO_NAMESPACE=istio-system
export APP_URL='https://app.example.com/protected'
export JWT_TOKEN='replace-with-a-valid-test-token'

curl --fail-with-body --verbose \
  -H "Authorization: Bearer ${JWT_TOKEN}" \
  "$APP_URL"

kubectl -n "$ISTIO_NAMESPACE" logs deployment/istiod \
  --since=10m | grep -Ei 'jwks|openid|oauth|http2|error' || true

这个测试应从真实经过企业代理或出口代理的网络路径执行。直接从开发机访问身份提供方成功,并不能证明 istiod 所在网络中的 HTTP CONNECT 路径正常。

配置与状态修复:小字段也会阻断代理启动

1.30.5 修复了两个与 Sidecar 统计周期相关的问题:

  • sidecar.istio.io/statsFlushInterval 使用一分钟及以上,或者使用亚秒值时,不再生成无效的 Envoy bootstrap。
  • sidecar.istio.io/statsEvictionInterval 不再静默截断亚秒精度。

在需要调整统计刷新和淘汰节奏时,可以这样实践。下面的 Deployment 仅用于演示注解位置;请替换镜像和业务端口后再应用:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: stats-interval-demo
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: stats-interval-demo
  template:
    metadata:
      labels:
        app: stats-interval-demo
      annotations:
        sidecar.istio.io/statsFlushInterval: "1m"
        sidecar.istio.io/statsEvictionInterval: "750ms"
    spec:
      containers:
        - name: app
          image: nginx:1.27-alpine
          ports:
            - containerPort: 80

应用并确认代理成功启动:

kubectl apply -f stats-interval-demo.yaml
kubectl rollout status deployment/stats-interval-demo --timeout=3m
kubectl get pod -l app=stats-interval-demo \
  -o jsonpath='{range .items[*].status.containerStatuses[*]}{.name}{" ready="}{.ready}{" restarts="}{.restartCount}{"\n"}{end}'
istioctl proxy-status

此外,本次发布还修复了几项容易误导自动化系统的状态问题:

  • 没有任何有效监听器的 ListenerSet,现在会将 AcceptedProgrammed 设为 False,原因是 ListenersNotValid,而不是保留看似成功的状态。
  • 当旧状态写入仍在队列中、资源又被修改时,observedGeneration 不再停留在过期值。
  • 带有“存在但为空”的 workload selector 的 ServiceEntry,不再错误匹配命名空间中的全部工作负载。

最后一项尤其需要注意:不要依赖旧版本的错误行为。需要选择工作负载时,应使用明确标签,例如:

apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
  name: selected-database
  namespace: default
spec:
  hosts:
    - database.internal.example
  ports:
    - number: 5432
      name: tcp-postgres
      protocol: TCP
  resolution: STATIC
  workloadSelector:
    labels:
      app: database
      role: primary

升级前可以搜索现有的 ServiceEntry,人工检查是否存在空选择器以及是否有人依赖其错误的全匹配效果:

kubectl get serviceentry --all-namespaces -o yaml \
  | grep -n -A4 -B2 'workloadSelector:' || true

多集群 secret:修补 istioctl analyze 的本地执行风险

本次发布中最值得安全团队关注的修复发生在 istioctl analyze。此前,该命令会直接根据 istio-system 中的多集群 secret 构建 Kubernetes 客户端,但没有先清理其中的 kubeconfig。

如果攻击者能够制作或修改这类 secret,就可能植入 exec 凭据插件,或者利用其他不安全的认证字段读取本地文件。当工程师在工作站或 CI Runner 上执行 istioctl analyze 时,这些内容可能在运行命令的机器上生效。

1.30.5 现在会像 istiod 一样清理这类 kubeconfig。即使完成升级,也仍应收紧 secret 的写权限,并审计多集群凭据的来源。下面的命令只列出元数据,不会解码或执行 secret 中的 kubeconfig:

kubectl -n istio-system get secrets \
  -l istio/multiCluster=true \
  -o custom-columns='NAME:.metadata.name,CREATED:.metadata.creationTimestamp,TYPE:.type'

kubectl auth can-i create secrets -n istio-system
kubectl auth can-i patch secrets -n istio-system
kubectl auth can-i update secrets -n istio-system

如果普通开发者或非预期的 CI ServiceAccount 能够修改 istio-system 中的 secret,应优先修正 RBAC,而不是把 1.30.5 当成唯一防线。升级前,也不要用旧版 istioctl analyze 检查来源不可信的多集群 secret。

升级建议:按故障面设计验证

使用原地升级的环境,可以在保留现有 profile 和 values 的前提下,先执行预检查,再通过团队既有的发布流程升级。下面是一组可改造的操作顺序:

set -euo pipefail

export ISTIO_NAMESPACE=istio-system

# 确认这里显示的客户端版本为 1.30.5。
istioctl version

# 升级前检查。
istioctl x precheck
istioctl analyze --all-namespaces
kubectl -n "$ISTIO_NAMESPACE" get pods

# 原地升级;运行前确认它会沿用团队要求的安装配置。
istioctl upgrade

# 控制面与配置收敛检查。
kubectl -n "$ISTIO_NAMESPACE" rollout status deployment/istiod --timeout=5m
istioctl proxy-status
istioctl analyze --all-namespaces

使用 revision/canary 模式的团队不应直接照搬原地升级命令,而应部署新的 1.30.5 revision,迁移测试命名空间,再逐步切换业务。

验收清单可以围绕本次实际修复展开:

  • 重启单个 CNI 节点代理后,已纳管 Pod 没有出现重复重定向或连接异常。
  • 真实代理链路上的 JWKS 获取和 JWT 验证成功。
  • 使用分钟级和亚秒级统计注解的 Sidecar 能正常生成 bootstrap 并启动。
  • 多网关网络中的工作负载地址保持稳定,WDS 推送没有无故持续抖动。
  • ListenerSetobservedGenerationServiceEntry 的状态符合实际配置。
  • 执行多集群分析的工作站和 CI 已使用 1.30.5 istioctl,相关 secret 的写权限也经过审计。

这不是一次需要重新设计网格的升级,但它修复的恰好都是容易演变成间歇性故障或安全事故的边界问题。越依赖 Ambient、多网络、外部身份提供方和多集群分析,升级优先级就越高。


相关推荐