📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

适用版本: 7.x-8.x

1. 错误异常的基本描述 #

Verify failed because all ... provided JWKs were filtered. 表示 Elasticsearch 在 JWT/JWS 签名验证流程中,虽然成功获取到了 JWK(JSON Web Key)集合,但在按照 kid、算法、用途、密钥长度或曲线等条件进行过滤后,没有任何一把密钥能够满足校验条件,导致验签流程无法继续。

这个异常的本质是:不是签名验证失败,而是在进入真正验签之前,候选密钥就已经被全部过滤掉了。

常见现象 #

  • JWT、ID Token 或 JWS 校验失败,接口返回 401 Unauthorized403 Forbidden
  • Elasticsearch 日志中出现类似 Verify failed because all N provided JWKs were filtered. 的错误信息。
  • 使用 OpenID Connect、SAML 或自定义 JWT 认证时,用户无法正常登录。
  • 常见于密钥轮换、算法切换、安全策略升级或 OIDC Provider 配置变更之后。
  • 如果应用在重试,可能会看到大量相同错误,直到 JWK 配置被修正或缓存刷新。

典型报错与异常栈 #

常见日志形态通常类似下面这样:

ElasticsearchSecurityException: Verify failed because all 3 provided JWKs were filtered.
Caused by: java.lang.IllegalArgumentException
	at org.elasticsearch.xpack.security.authc.jwt.JwtSignatureValidator.validate(JwtSignatureValidator.java:XX)
	at org.elasticsearch.xpack.security.authc.jwt.JwtRealmAuthenticator.authenticate(JwtRealmAuthenticator.java:XX)

2. 为什么会发生这个错误 #

从 Elasticsearch 源码逻辑来看,JWT 签名验证流程大致是:获取 JWK Set → 按过滤条件筛选 → 用筛选后的密钥验签。该异常发生在第二步:筛选条件过于严格,导致没有密钥留下来。

常见原因通常包括:

  • kid 不匹配:Token Header 中的 kid(Key ID)与 JWK Set 中任何密钥的 kid 都不一致。这是最常见的原因,尤其是密钥轮换后新密钥使用了新的 kid,但 OIDC Provider 的 JWKS 端点还没更新或缓存未刷新。
  • 算法不匹配:Token Header 中的 alg 与 JWK 的 alg 或推导出的算法不一致。例如 Token 用 RS256 签名,但 JWK 声明的是 PS256 或未声明算法。
  • 密钥类型不匹配:JWK 的 kty(Key Type)与签名算法要求的密钥类型不同。例如 alg: ES256 需要 kty: EC,但 JWK 提供的是 kty: RSA
  • 密钥用途不匹配:JWK 的 use(Usage)字段不是 sig(签名),或者是 key_ops 不包含 verify,导致被过滤掉。
  • 安全强度限制过严:Elasticsearch 配置了最低密钥强度要求(如 RSA 密钥长度至少 2048 位),而 JWK Set 中的密钥强度不达标。
  • 曲线不匹配:对于椭圆曲线密钥(EC),JWK 的 crv(Curve)与算法要求的曲线不一致,例如 ES256 要求 P-256 曲线。
  • JWK Set 配置错误:JWK Set 本身配置有误,例如 keys 数组为空、JSON 格式错误、或者 JWK 字段缺失关键信息。

3. 如何排查和解决这个异常 #

建议按"先定位 Token 与 JWK 的不匹配点,再修正配置"的顺序处理:

  1. 解码 JWT Token Header:使用 jwt.io 或命令行工具解码 Token 的 Header 部分,记录 kidalg 字段的值。

    echo "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9..." | cut -d'.' -f1 | base64 -d | jq .
    

    输出示例:

    {
      "alg": "RS256",
      "kid": "abc123",
      "typ": "JWT"
    }
    
  2. 获取并检查 JWK Set:访问 OIDC Provider 的 JWKS 端点(通常是 /.well-known/jwks.json/oauth2/certs),检查返回的 JWK Set。

    curl -s https://your-oidc-provider/.well-known/jwks.json | jq .
    

    确认返回中是否有 kidabc123ktyRSAalgRS256(或兼容)的密钥。

  3. 检查密钥元数据匹配情况:逐一比对以下字段:

    • kid:必须完全匹配(区分大小写)
    • kty:RSA Token 需要 RSA,EC Token 需要 EC
    • alg:如果 JWK 声明了 alg,必须与 Token Header 的 alg 兼容
    • use:应为 sig(签名用途)
    • crv(仅 EC 密钥):必须与算法匹配(如 ES256P-256
  4. 检查 Elasticsearch 的 JWT Realm 配置:查看 elasticsearch.yml 或相关安全配置中 JWT Realm 的 allowed_jwkspemtrustedcas_filepath 等设置,确认没有额外限制条件。

  5. 确认 JWK 缓存是否刷新:Elasticsearch 会缓存 JWK Set,如果刚做过密钥轮换,等待缓存过期(通常 1-24 小时,取决于 OIDC Provider 的 Cache-Control 头)或重启节点强制刷新。

排查时需要注意的问题 #

  • 不要只看 JWK Set 的首次返回结果,某些 OIDC Provider 会根据请求头或负载返回不同的 JWK Set,需要确认 Elasticsearch 实际获取到的内容。
  • 如果生产环境使用了多个 JWT Realm 或多种认证方式,要确认请求走的是预期的 Realm。
  • 密钥轮换期间,新旧密钥可能同时存在,但 Token 可能只使用新密钥签名,需确认 JWK Set 已包含新密钥。

4. 如何解决这个错误 #

常用修复思路 #

  • 确保 JWK Set 包含匹配的密钥:在 OIDC Provider 侧确认 JWK Set 已发布包含正确 kid、算法和用途的密钥。如果刚完成密钥轮换,确认新密钥已发布到 JWKS 端点。
  • 保持 Token Header 和 JWK 元数据一致:修正 Token 签发配置,确保 kidalg 与 JWK Set 中的元数据匹配。如果无法修改 Token 签发方,则调整 JWK Set 以兼容现有 Token。
  • 调整不合理的安全策略:如果错误是因为密钥强度不达标,可以升级密钥(如 RSA 2048 → 4096),或适当调整 Elasticsearch 的密钥强度要求(不推荐降低安全要求)。
  • 修正 JWK Set 配置错误:检查 JWK Set JSON 是否格式正确、keys 数组是否非空、各字段是否完整。

示例:一个正确的 JWK Set 片段

{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "kid": "abc123",
      "alg": "RS256",
      "n": "0vx7agoebGcQ...",
      "e": "AQAB"
    }
  ]
}

后续注意事项与推荐建议 #

  • 在 OIDC Provider 侧建立密钥轮换机制,并确保新密钥在旧密钥停用前就已发布到 JWKS 端点,避免轮换间隙验签失败。
  • 为 JWT 认证配置监控,当验签失败率上升时及时告警,便于在密钥轮换或配置变更后快速发现问题。
  • 在测试环境验证密钥轮换流程,确认 Elasticsearch 能正确获取并缓存新的 JWK Set,再在生产环境执行轮换。

借助 INFINI 产品提升排障效率 #

  • INFINI Console 适合查看 Elasticsearch 安全日志、认证失败趋势和请求画像,帮助快速判断是 JWK 配置问题还是 Token 签发问题。
  • INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测、JWT 校验和流量治理,可以在网关层提前拦截不合法的 Token,减少后端集群的验签压力。
  • 如果需要长期治理,建议把 JWT 认证日志、JWK 获取记录、验签失败原因统一接入监控面板,缩短从"发现问题"到"定位根因"的时间。

5. 小结 #

Verify failed because all ... provided JWKs were filtered. 这个异常说明候选密钥在"筛选阶段"就全部失效,而非签名值本身不对。排查时要同时关注 Token Header 的 kidalg、JWK Set 的元数据完整性,以及 Elasticsearch 当前的校验策略。只要按 Token → JWK → 配置链路逐一核对,大多数密钥不匹配问题都可以快速定位并修复。

相关错误 #

附:日志上下文 #

下面保留当前页面中的源码或日志片段,便于继续结合异常调用栈定位问题:

throw new ElasticsearchSecurityException(
    "Verify failed because all {} provided JWKs were filtered.",
    providedJwks.size()
);