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

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

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

Verify requires a non-empty JWK list 表示 Elasticsearch 在执行 JWT 签名验证时,没有拿到任何可用的 JWK(JSON Web Key)。这是 Elasticsearch 安全模块在验签流程入口处做的前置校验:如果传入的 JWK 列表为空,验签根本无法开始,因此直接抛出异常,终止当前认证或签名校验流程。

常见现象 #

  • 使用 JWT 认证时,所有携带 Token 的请求均返回 401 Unauthorized,且服务端日志中出现该异常。
  • Elasticsearch 启动或安全配置重载后,JWT 相关认证立即失败,无法建立任何基于 JWT 的信任关系。
  • 如果配置了远程 JWK Set URL,则在网络不通、JWK 端点返回空响应或 HTTP 状态码异常时,该错误会频繁出现。
  • 在 Kibana 或自定义客户端通过 JWT 访问集群时,用户会收到认证失败提示,但难以从客户端侧直接判断是密钥问题还是 Token 本身问题。

典型报错与异常栈 #

该异常通常以 ElasticsearchSecurityException 的形式抛出,常见日志形态类似下面这样:

ElasticsearchSecurityException: Verify requires a non-empty JWK list
    at org.elasticsearch.xpack.security.authc.jwt.JwtUtil.failVerifyRequiresNonEmptyJwkList(JwtUtil.java:...)
    at org.elasticsearch.xpack.security.authc.jwt.JwtSignatureValidator.validate(JwtSignatureValidator.java:...)
    at org.elasticsearch.xpack.security.authc.jwt.JwtAuthenticator.authenticate(JwtAuthenticator.java:...)

结合上下文,还可能同时出现以下关联异常:

failed to retrieve remote JWK set
JWKSet parse failed for setting jwkset_config_key
verify failed because all provided JWKs were filtered

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

这条异常的根本原因是:验签流程被触发时,可用的 JWK 列表为空。Elasticsearch 的 JWT 认证器在验签前会先收集所有候选 JWK,如果发现列表为空,就直接抛出此异常,而不是继续尝试无效的验签操作。

常见原因通常包括:

  • 本地 JWK 文件路径配置错误jwkset_path 指向的文件不存在、路径错误,或 Elasticsearch 进程没有读取权限,导致加载到的密钥集合为空。
  • JWK 文件内容为空或格式错误:文件存在但内容为空、不是合法的 JSON,或 JSON 结构中没有 keys 字段,导致解析后无法提取任何 JWK。
  • 远程 JWK Set 拉取失败且无缓存:配置了 jwkset_url 但远程服务不可达、返回非 200 状态码、返回空 keys 数组,或网络超时,且本地没有可用的缓存密钥。
  • 密钥轮换期间出现空窗期:旧密钥已被移除(或过期),新密钥尚未生效或尚未被加载,导致在轮换瞬间 JWK 列表为空。
  • JWK 过滤条件过于严格:配置了 allowed_issuerallowed_audience 或算法白名单后,所有 JWK 被过滤掉,最终传入验签函数的列表为空。
  • 安全配置未正确生效:修改了 elasticsearch.yml 中的 JWT 相关配置后未重启或未执行配置重载,导致运行时仍使用旧的(空的)密钥配置。

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

建议按"先确认密钥来源、再验证密钥内容、后修复配置"的顺序处理:

  1. 确认 JWK 来源类型:检查 elasticsearch.yml 中 JWT 认证配置,确认使用的是本地文件(jwkset_path)还是远程 URL(jwkset_url)。
  2. 验证本地 JWK 文件:如果使用本地文件,直接检查文件是否存在、内容是否非空、是否为合法 JSON,且包含至少一个 keys 元素。
  3. 测试远程 JWK 端点:如果使用远程 URL,用 curl 手动请求该端点,确认返回 200 且 keys 数组非空。
  4. 检查 Elasticsearch 日志:搜索同一时间窗口内是否有 JWK 加载失败、解析失败或远程拉取失败的日志,这些往往比异常本身更能说明根因。
  5. 确认配置已生效:检查修改配置后是否已重启节点或执行了配置重载,避免配置与实际运行状态不一致。

排查时需要注意的问题 #

  • 不要只看异常本身,必须同时检查 JWK 加载阶段的日志,往往真正的错误(如文件读取失败、JSON 解析失败)出现在更早的位置。
  • 如果使用远程 JWK,需要区分是网络问题(连接超时、DNS 失败)还是服务端问题(返回空 keys、返回错误格式),可以用 curl -v 获取详细信息。
  • 密钥轮换场景下,需要确认新旧密钥的 kid(Key ID)是否匹配 Token 中声明的 kid,不匹配时即使 JWK 列表非空也会被过滤掉。

4. 如何解决这个错误 #

常用修复思路 #

  • 提供至少一把可用公钥:确保 JWK Set 中至少包含一个有效的 JWK。RSA 公钥至少需要 ktyalgusene 字段;EC 公钥需要 ktyalgcrvxy 字段。
  • 修正本地文件路径或远程 URL:确认 jwkset_pathjwkset_url 配置正确,文件路径相对于 Elasticsearch 配置目录,URL 需要确保网络可达。
  • 验证 JWK 内容格式:本地 JWK 文件应符合 RFC 7517 定义的 JWK Set 格式,即顶层为 {"keys": [...]},且 keys 为非空数组。
  • 处理密钥轮换空窗期:在轮换密钥时,建议先添加新密钥,确认加载成功后,再移除旧密钥,避免出现任何时刻 JWK 列表为空的情况。
  • 检查 JWK 过滤条件:确认 allowed_signature_algorithmsallowed_issuerallowed_audience 等过滤条件没有把全部 JWK 排除掉。

修复示例 #

正确的本地 JWK 文件示例(jwks.json):

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

正确的 elasticsearch.yml 配置示例:

xpack.security.authc.realms.jwt.jwt1:
  order: 1
  client_authentication.type: "signed"
  token_type: "access_token"
  allowed_issuer: "my-issuer"
  allowed_audiences: ["my-audience"]
  jwkset_path: "/path/to/jwks.json"
  # 或使用远程 JWK Set
  # jwkset_url: "https://auth-server/.well-known/jwks.json"

验证远程 JWK 端点是否可用:

curl -s https://auth-server/.well-known/jwks.json | jq '.keys | length'
# 输出应大于 0

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

  • 为 JWT 认证配置建立监控,定期检查 JWK 加载状态和认证成功率,在 JWK 列表为空或加载失败时主动告警。
  • 使用远程 JWK Set 时,关注 JWK 端点的可用性和响应时间,避免因依赖服务抖动导致集群认证全面失败。
  • 密钥轮换应有明确的流程和回滚预案,确保任何时刻都有至少一把可用的签名密钥。
  • 在测试环境先验证 JWK 配置和 Token 生成逻辑,确认验签通过后再推到生产环境。

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

  • INFINI Console 适合查看集群安全配置状态、认证成功/失败趋势、节点日志聚合,帮助快速判断 JWK 加载问题是全局性还是节点级别。
  • INFINI Gateway 适合部署在 Elasticsearch 前面做请求观测和流量治理,可以在 JWT 认证失败率异常升高时及时发现,并辅助定位是密钥问题还是 Token 本身问题。
  • 如果需要长期治理,建议把认证日志、JWK 加载事件和 Token 验证结果统一接入监控面板,缩短从"发现认证失败"到"定位根因"的时间。

5. 小结 #

Verify requires a non-empty JWK list 是一个明确的前置校验异常,说明验签所需的基础条件(可用的 JWK 列表)完全不满足。相比复杂的验签失败场景,它更像是配置链路或密钥加载链路的基础问题。处理时,最有效的路径是:先确认 JWK 来源(本地文件还是远程 URL),再验证密钥内容是否合法且非空,最后排查加载和过滤逻辑,通常可以快速定位并修复。

相关错误 #

附:日志上下文 #

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

if (providedJwks == null || providedJwks.isEmpty()) {
    throw new ElasticsearchSecurityException("Verify requires a non-empty JWK list");
}