目标
验证在 Istio 金丝雀升级期间,不同 sidecar 版本 + 不同 mTLS 策略(STRICT / PERMISSIVE)下,服务间的双向互通性。
mTLS 背景
| 概念 |
说明 |
PeerAuthentication |
Istio namespace 级别的 CRD,控制入站 mTLS 策略 |
STRICT 模式 |
仅接受 mTLS 连接,拒绝明文流量 |
PERMISSIVE 模式 |
同时接受 mTLS 和明文(未设置 PA 时的默认行为) |
| Auto mTLS(出站) |
调用方 sidecar 检测到目标有 sidecar 时,自动升级为 mTLS,与调用方自身 PA 设置无关 |
| XFCC 头 |
X-Forwarded-Client-Cert,Envoy 在 mTLS 激活时注入,可在应用层验证 mTLS 是否生效 |
跨版本升级的风险点
- 新旧 Envoy 版本间的证书格式 / TLS 协商不兼容
- TLS 协议版本差异
- 不同版本 istiod 对 STRICT 策略的执行行为差异
测试架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ┌──────────────────────────────────────────────────┐ │ release namespace (helm test pods) │ │ │ │ test-1 test-2 test-3 ... test-8 │ │ (pod-level istio.io/rev 控制 sidecar 版本) │ └────┬────────┬────────┬──────────────┬───────────┘ │ │ │ │ ┌──────────────┼────────┼────────┼──────────────┼──────────────┐ │ ▼ │ ▼ │ │ │ ┌─────────────────┐ │ ┌─────────────────┐ │ │ │ │ ns: old-strict │ │ │ ns: new-strict │ │ │ │ │ rev: old │ │ │ rev: new │ │ │ │ │ PA: STRICT │ │ │ PA: STRICT │ │ │ │ │ httpbin ────────│ │ │ httpbin ────────│ │ │ │ └─────────────────┘ │ └─────────────────┘ │ │ │ ▲ ▼ ▲ ▼ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ ns: old-permissive│ │ ns: new-permissive│ │ │ │ rev: old │ │ rev: new │ │ │ │ PA: (默认) │ │ PA: (默认) │ │ │ │ httpbin ─────── │ │ httpbin ─────── │ │ │ └──────────────────┘ └──────────────────┘ │ └─────────────────────────────────────────────────────────────┘
|
测试场景矩阵
共 8 个场景,每场景 5 项断言 = 40 项检查。
| # |
调用方 Sidecar |
被调方 Namespace |
被调方 mTLS 模式 |
说明 |
对应用户需求 |
| 1 |
旧版 |
新版 + STRICT |
STRICT |
旧 sidecar → 新版 STRICT 服务 |
需求 #1 |
| 2 |
新版 |
旧版 + STRICT |
STRICT |
新 sidecar → 旧版 STRICT 服务 |
需求 #2 |
| 3 |
旧版 |
新版 + PERMISSIVE |
PERMISSIVE |
旧 sidecar → 新版宽松模式服务 |
需求 #3 |
| 4 |
旧版 |
旧版 + STRICT |
STRICT |
同版本 STRICT 基线 |
补充 |
| 5 |
新版 |
新版 + STRICT |
STRICT |
同版本 STRICT 基线 |
补充 |
| 6 |
新版 |
旧版 + PERMISSIVE |
PERMISSIVE |
场景 #3 的反向 |
补充 |
| 7 |
旧版 |
旧版 + PERMISSIVE |
PERMISSIVE |
同版本宽松基线 |
补充 |
| 8 |
新版 |
新版 + PERMISSIVE |
PERMISSIVE |
同版本宽松基线 |
补充 |
关于用户需求 #4(未启用 mTLS 的旧版服务 → 启用 mTLS 的新版服务):
在 Istio 中调用方自身的 PeerAuthentication 不影响出站调用,auto-mTLS 会在目标有 sidecar 时自动升级为 mTLS。因此需求 #4 在网络层等价于场景 #1。场景 #1 + #3 已完整覆盖。
每场景 5 项断言
| # |
断言 |
目的 |
| 1 |
HTTP 200 可达 |
mTLS 下基本连通性 |
| 2 |
X-Forwarded-Client-Cert 头存在 |
证明 mTLS 真正生效(核心检查) |
| 3 |
x-envoy-upstream-service-time 头存在 |
被调方 sidecar 存在性 |
| 4 |
自定义请求头 X-Cross-Version 转发 |
端到端数据完整性 |
| 5 |
POST body 往返 |
非 GET 方法在跨版本 mTLS 下正常工作 |
实施步骤
阶段一 — Chart 脚手架
| 步骤 |
文件 |
说明 |
| 1 |
Chart.yaml |
命名 istio-mtls-cross-version-test,复用现有结构 |
| 2 |
values.yaml |
4 个 namespace 名、revision 配置、镜像/资源/测试参数 |
阶段二 — Kubernetes 资源模板(可并行)
| 步骤 |
文件 |
说明 |
| 3 |
templates/namespaces.yaml |
4 个 namespace,分别标记 istio.io/rev |
| 4 |
templates/peer-authentication.yaml |
2 个 PeerAuthentication(API security.istio.io/v1,STRICT 模式),仅用于 *-strict namespace |
| 5 |
templates/httpbin.yaml |
4 组 httpbin Deployment + Service |
| 6 |
templates/test-mtls-cross-version.yaml |
8 个测试 Pod(Helm test hooks),Pod 级 istio.io/rev 标签、holdApplicationUntilProxyStarts、就绪等待、check() 函数、quitquitquit |
阶段三 — 自动化脚本
| 步骤 |
文件 |
说明 |
| 7 |
run.sh |
4 命令结构:install | test | uninstall | all,复制 secret 到 4 个 ns,等待 4 个 httpbin 就绪 |
阶段四 — 文档
| 步骤 |
文件 |
说明 |
| 8 |
README.md |
测试目标、场景矩阵、前置条件、使用说明 |
参考文件
| 文件 |
用途 |
istio-cross-version-test/Chart.yaml |
Chart 脚手架参考 |
istio-cross-version-test/values.yaml |
配置结构参考 |
istio-cross-version-test/run.sh |
自动化脚本参考 |
istio-cross-version-test/templates/namespaces.yaml |
namespace 创建模式(istio.io/rev 标签) |
istio-cross-version-test/templates/httpbin-old.yaml |
httpbin Deployment+Service 模式 |
istio-cross-version-test/templates/test-cross-version.yaml |
测试 Pod 模式(Helm hooks、check()、就绪等待) |
验证方式
| # |
验证 |
命令 / 方法 |
| 1 |
Lint 检查 |
helm lint istio-mtls-cross-version-test/ |
| 2 |
模板渲染 |
helm template test istio-mtls-cross-version-test/ — 确认 4 ns、2 PA、4 httpbin、8 test pod |
| 3 |
Dry run |
helm install --dry-run test istio-mtls-cross-version-test/ |
| 4 |
集群实测 |
./run.sh all(需两个 istiod 版本同时运行)— 40/40 通过 |
| 5 |
mTLS 验证 |
场景 1 & 2 日志中包含 XFCC 头 |
| 6 |
负面测试(手动) |
无 sidecar Pod → STRICT httpbin → 连接被拒 |
设计决策
| 决策 |
理由 |
| 独立 Chart(不扩展现有测试) |
避免回归风险,可独立运行 |
| 8 场景全矩阵 |
2(版本) × 2(版本) × 2(mTLS模式) = 8,无盲区 |
| 不单独测试调用方 PA |
PA 仅影响入站,不影响出站连通性 |
API security.istio.io/v1 |
稳定版,Istio 1.25+ / 1.27+ 均支持 |
待讨论
- DestinationRule 交互 — 是否需要测试显式
DestinationRule tls.mode: ISTIO_MUTUAL?建议初期不需要,auto-mTLS 已覆盖。
- 全网格 STRICT PA —
istio-system 中的全局 STRICT PA 属运维范畴,不在跨版本测试范围内。
环境变量(运行时可覆盖)
| 变量 |
默认值 |
说明 |
OLD_REV |
1-25-0 |
旧版 Istio revision |
NEW_REV |
1-27-7 |
新版 Istio revision |
REGISTRY |
artifactory.cloud.ingka-system.cn/cn-digital-hub-docker-virtual |
镜像仓库 |
SECRET_NS |
kong |
imagePullSecret 来源 namespace |
SECRET_NAME |
artifactory-read |
imagePullSecret 名称 |
使用示例
1 2 3 4 5 6 7 8 9 10
| ./run.sh all
OLD_REV=1-25-0 NEW_REV=1-28-5 ./run.sh all
./run.sh install ./run.sh test ./run.sh uninstall
|
故障排查
常见失败场景
| 失败现象 |
可能原因 |
排查命令 |
| 连接被拒绝 |
被调方 PA 为 STRICT 但调用方无 sidecar |
kubectl get peerauthentication -A |
| TLS 握手失败 |
新旧 Envoy 版本间证书/协议不兼容 |
istioctl proxy-config secret <pod> -n <ns> |
| 超时 |
网络策略阻断或服务发现问题 |
istioctl proxy-status |
| XFCC 头缺失 |
mTLS 未生效,可能 PA 未正确应用 |
istioctl authn tls-check <pod> <svc> |
调试命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| kubectl get peerauthentication -n istio-mtls-old-strict -o yaml kubectl get peerauthentication -n istio-mtls-new-strict -o yaml
istioctl proxy-config listeners <pod> -n <namespace>
istioctl proxy-config routes <pod> -n <namespace>
istioctl proxy-config secret <pod> -n <namespace>
kubectl exec -it <caller-pod> -n <namespace> -- \ curl -sv http://httpbin.<callee-ns>.svc.cluster.local/status/200
kubectl logs <pod> -n <namespace> -c istio-proxy --tail=50
|