服务网格 21:认证成功为何仍会被拒绝
证明“是谁”不等于证明“能做什么”
orders 以正确工作负载证书连接库存,只说明对端代理能够验证它的工作负载身份;一名最终用户带有效 JWT,也只说明令牌在指定签发者、密钥、受众及有效期等规则下通过校验。业务是否放行,还要看作用于 inventory 的授权策略与请求属性。对等身份来自 mTLS,最终用户身份来自请求令牌;两者不能互相替代,更不能把客户端自填的 X-Request-ID 当作认证结果。
Istio 的 RequestAuthentication 有一个很容易写错的边界:携带了不合法的令牌会被拒绝;没有携带令牌的请求默认仍能进入后续处理。如果业务要求“必须提供有效 JWT”,还需增加匹配 requestPrincipals 的 AuthorizationPolicy。在 HTTP 路由中,拒绝可能发生于请求认证、授权、TLS 握手,甚至应用自身;只有确认策略作用域、代理记录和应用是否收到该请求,才能说清拒绝位置。
把两种身份与两阶段策略拆开测试
仍使用 orders → inventory-v1。先为两个工作负载配置不同 ServiceAccount,确认目标确实启用入站 mTLS;为隔离的测试 JWT 签发者配置 RequestAuthentication,固定 issuer、JWKS、audience,并禁止日志或证据目录保存令牌本身。第一阶段不施加要求令牌的 ALLOW 规则,让带有效令牌、不带令牌、带坏签名令牌的三种请求分别经过库存入站代理。按官方示例的认证语义,前两种可以继续处理,坏令牌会在请求认证处被拒绝;结果若不同,先检查资源是否选中了正确目标。
第二阶段再给同一库存工作负载配置限定来源为 orders 对等身份、且要求有效 requestPrincipals 的 ALLOW 策略。分别发来自正确 ServiceAccount+有效令牌、错误 ServiceAccount+有效令牌、正确 ServiceAccount+无令牌、正确 ServiceAccount+坏令牌四组请求。每组用不同请求 ID 关联入站代理和库存应用日志:期望第一组允许,第二组因对等身份不符拒绝,第三组因缺少用户主体拒绝,第四组在 JWT 校验阶段拒绝。JWT 校验失败常在 HTTP 层表现为 401,授权拒绝常表现为 403,但应以实际代理详情为准;mTLS 失败可能根本没有 HTTP 响应。
需要比较 DENY 与 ALLOW 时,单独加入一条只针对实验路径的 DENY,证明即使已有 ALLOW 也不会覆盖它;结束前撤回策略,避免后续章节误把遗留规则当新故障。策略声明要连同其命名空间、selector、匹配路径、目标代理当前配置一起保存。对裸 TCP 不要套用要求 HTTP 路径/JWT 的断言。
| 用例 | 预期判断依据 | 实际 HTTP/连接、拒绝位置和应用记录 |
|---|---|---|
| 正确对等身份+合法 JWT | 入站身份、用户主体均匹配 | NOT_RUN:无 Istio 集群 |
| 错误对等身份+合法 JWT | mTLS 已认证但授权来源不匹配 | NOT_RUN |
| 正确对等身份+无 JWT | 仅配置请求认证时可通过;要求主体后拒绝 | NOT_RUN |
| 正确对等身份+坏 JWT | 认证失败,不等同于授权拒绝 | NOT_RUN |
用本机临时签名密钥执行四组身份对照
以下命令在 examples/service-mesh 目录执行,使用 04 章 Kubernetes 1.33.4 / Istio 1.27.0 sidecar 基线,应用容器名 app。先清理前章授权、故障与出口策略;下列预期值尚不是集群实测结果。
1 | |
mainline/21/issue.py 用 OpenSSL 生成临时 RSA 密钥和 1 小时有效期的 RS256 JWT,受众固定 inventory;一个令牌签名正确,另一个只损坏签名字节。生成器同时验证这两个签名的正反例。公钥以内联 JWKS 放入 RequestAuthentication,实验不依赖公网 JWKS 服务。目录权限为 0700,令牌和私钥不进入证据目录或 Git。本地签名正反例记录见 examples/service-mesh/evidence/verification/mainline-13-25/jwt.log 与 jwt.exit;它只证明生成器能识别坏签名,不证明代理已经执行 JWT 准入。
1 | |
随后删除 mainline/19/alternate.yaml、mainline/20/strict.yaml 和临时 JWT_DIR。命令通过 stdin 传令牌,避免将令牌展开到 kubectl 命令参数或输出日志;不要启用 shell tracing。allow.yaml 在同一个 source 条件中同时要求 orders 的 mTLS principal 与 issuer/alice 的 requestPrincipal,二者是 AND。DENY 加入后即使令牌与身份正确也应拒绝,删除后恢复,再撤回全部实验策略。
此处 curl 从 orders 身份探针直接请求库存,应用链未自动转发 Authorization;不能拿 frontend 未传令牌导致的失败误判成 JWT 校验故障。内联 JWKS 不验证远程密钥抓取、缓存和轮换,那些仍需独立实验。
固定源码入口:Istio 1.27.0 pilot/pkg/networking/plugin/authz/authorization.go。该链接用于核对配置生成或执行机制;完整资源和命令保存在 examples/service-mesh/mainline/21/。静态检查通过不等于集群实验通过。
练习与参考解答
- 给库存服务加了
RequestAuthentication,匿名请求仍成功,是否说明 JWT 策略失效?参考解答:不一定;该资源验证已携带的令牌,要求必带需要单独的授权条件。 - 有效 JWT 的请求被拒绝,能否直接换一张 JWT 重试?参考解答:先检查 mTLS 来源、授权策略作用域、请求路径、受众和代理拒绝详情;有效用户令牌并不保证工作负载有权限。
官方资料与系列导航
- Istio 认证任务:无令牌、坏令牌及要求令牌的区别。
- RequestAuthentication 与 AuthorizationPolicy:身份提取、策略作用域和 CUSTOM/DENY/ALLOW 顺序。
- Istio Security:代理作为认证与授权执行点。
系列导航:20 mTLS 开启后哪些连接受到保护 → 21 认证成功为何仍会被拒绝(本文)→ 22 访问日志怎样区分代理失败和业务失败。
