适用版本: 7.x-8.x
1. 错误异常的基本描述 #
Verify failed using X of Y provided JWKs. 表示 Elasticsearch 从全部 JWK 中筛出了一部分候选密钥,但逐个尝试后仍然没有一把能成功完成签名验证。
与"所有 JWK 都被过滤掉"不同,这里的筛选阶段已经通过,说明 kid、use、kty 等字段是匹配的,问题出在真正的密码学验签阶段。
常见现象 #
- 日志中会出现类似
Verify failed using 0 of 3 provided JWKs.的提示,其中第一个数字为实际验签成功的密钥数(通常为 0),第二个数字为参与验签的候选密钥总数。 - Elasticsearch 安全日志中会伴随
security-token或authentication相关警告,提示 JWT 令牌验证失败。 - 使用 JWT 认证的客户端会收到
401 Unauthorized响应,HTTP 返回头中常包含WWW-Authenticate: Bearer realm="..."信息。 - Kibana 或自定义客户端在刷新 Token 后仍无法访问集群 API。
典型报错与异常栈 #
ElasticsearchSecurityException: Verify failed using 0 of 3 provided JWKs.
at org.elasticsearch.xpack.security.authc.jwt.JwtRealm.verifySignature(JwtRealm.java:...)
at org.elasticsearch.xpack.security.authc.jwt.JwtRealm.authenticate(JwtRealm.java:...)
Caused by: java.security.SignatureException: Signature length not correct
at java.base/sun.security.rsa.RSASignature.engineVerify(...)
2. 为什么会发生这个错误 #
从异常语义看,筛选阶段已经通过,但真正调用验签逻辑时全部候选都失败了。这说明问题更可能出在签名与公钥本身不匹配,而不是过滤条件。
常见原因包括:
- 公钥与私钥不匹配:JWK Set 中包含的公钥并非当前 Token 签发所用私钥对应的公钥,例如使用了过期的密钥对或错误的密钥文件。
- 签名算法不一致:Token Header 中声明的
alg(如RS256)与 JWK 中隐含的算法能力不符,或 Elasticsearch 配置中指定的allowed_signature_algorithms与实际情况冲突。 - Token 内容被篡改:Token 的 Payload 或 Signature 部分在传输过程中被修改,导致任何合法公钥都无法通过验签。
- JWK 格式不完整:JWK 缺少验签所需的关键字段(如 RSA 公钥缺少
n或e),虽然能通过过滤阶段,但在实际验签时失败。 - 密钥轮换不同步:身份提供商(IdP)已轮换签名密钥,但 Elasticsearch 侧配置的 JWK Set 尚未更新,导致新旧密钥不匹配。
- JWK 来源混合错误:配置了多个 JWK 来源(如同时配置
pem和jwkset_file),导致实际参与验签的密钥集合与预期不符。
3. 如何排查和解决这个异常 #
建议按"先解码 Token、再核对密钥、最后检查配置"的顺序处理:
解码 JWT Token:使用 jwt.io 或命令行工具解码 Token 的 Header 和 Payload,记录
alg、kid、iss、aud等关键字段。echo "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9..." | base64 -d | jq .检查 JWK 候选集:确认 Elasticsearch 实际加载的 JWK Set 中是否包含与 Token
kid匹配且alg一致的密钥。curl -s -X GET "https://es-host:9200/_security/realm/<realm-name>/_jwks" | jq .比对公钥与私钥:使用 OpenSSL 提取 JWK 中的公钥信息,与签发侧的私钥进行配对验证。
# 将 JWK 中的 n 和 e 转换为 PEM 格式公钥,与签发侧证书比对 openssl rsa -pubin -text -noout < public_key.pem验证 Token 完整性:确认 Token 在传输过程中未被网关、代理或日志脱敏组件改写(注意检查是否有
=填充被截断的情况)。查看完整安全日志:在 Elasticsearch 中搜索相关时间点的安全审计日志,确认是否有更多上下文信息。
grep -i "jwt\|jwk\|verify" /var/log/elasticsearch/security-audit.log
排查时需要注意的问题 #
- 不要只看
X of Y中的数字,需要结合具体 JWK 的kid和alg逐一核对,确认是哪一把密钥实际参与了验签。 - 如果使用了 JWK 远程获取(
jwkset_path),需要确认网络可达性以及返回内容是否是最新版本,而非缓存的旧数据。 - 注意 Elasticsearch 的 JWT Realm 配置中
allowed_issuer和allowed_audiences是否与 Token 中的声明一致,虽然这不直接导致验签失败,但会掩盖真正的问题。
4. 如何解决这个错误 #
常用修复思路 #
- 更新 JWK Set:确保
jwkset_file或jwkset_path指向的 JWK 包含与当前签发私钥对应的公钥,必要时重新从 IdP 下载最新的 JWK Set。 - 修正签名算法配置:在 JWT Realm 配置中明确指定
allowed_signature_algorithms,避免签发侧与校验侧算法不一致。xpack.security.authc.realms.jwt.realm_name: order: 1 allowed_signature_algorithms: [RS256, RS384, RS512] jwkset_file: path: "/path/to/jwks.json" - 保护 Token 传输链路:在网关或代理中配置不修改请求头,避免对
Authorization头进行 base64 解码重组或截断处理。 - 启用 JWK 缓存刷新:如果 JWK 会定期轮换,配置合理的缓存刷新策略,避免本地缓存中的 JWK 过期后仍被使用。
后续注意事项与推荐建议 #
- 建立 JWK 轮换的监控机制,在 IdP 轮换密钥后及时收到通知并更新 Elasticsearch 配置。
- 为 JWT 认证配置多个 JWK 来源或使用
jwkset_path指向 IdP 的动态端点,减少手动更新带来的滞后。 - 在测试环境中使用已知的 JWK 对 Token 签发和验证做端到端验证,确保整个链路在密钥轮换前后均可正常工作。
借助 INFINI 产品提升排障效率 #
- INFINI Console 适合查看集群安全配置、认证日志和请求画像,帮助快速判断 JWT 验证失败的影响范围。
- INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测和流量治理,可以在 Token 到达 Elasticsearch 之前捕获并解码 JWT,辅助定位验签失败的根本原因。
5. 小结 #
Verify failed using X of Y provided JWKs. 说明 Elasticsearch 确实尝试过用候选密钥验签,但都失败了。与"全部被过滤"相比,它更接近公钥不匹配、签名算法不一致或 Token 被改动的问题。排查时应优先核对 JWK 内容与 Token 的 kid/alg 是否完全匹配,并确认密钥对的配对关系正确无误。
相关错误 #
附:日志上下文 #
throw new ElasticsearchSecurityException(
"Verify failed using {} of {} provided JWKs.",
jwksStrength.size(),
providedJwks.size()
);





