跳到主要内容
版本:3.10.x

刷新 JWT Auth 凭证

在 3.10.6 之前,控制面在把使用非对称算法(RS*ES*PS*EdDSA)的 jwt-auth 消费者凭证写入配置存储前,会为其补上一个固定的 private_key 占位字段。该字段只是为了通过 3.9.4 之前数据面的 jwt-auth 消费者 schema 校验——那些版本要求凭证必须带上 private_key。它并不是一把可用的密钥,数据面也从不用它签名:校验使用的是 public_key

3.9.4 及之后的数据面已经从该 schema 中移除了 private_key,于是这个被补上的字段变成了任何 schema 都未声明的字段,数据面会在配置兼容性报告中报告它:

plugin [jwt-auth] has unrecognized fields: private_key

该报告项的级别是告警:凭证仍然会生效,JWT 校验也照常工作。从 3.10.6 起,控制面不再补充该字段。本文说明如何清除已经写入配置中的这个字段带来的告警。

影响范围

如果某个消费者凭证的 jwt-auth 配置中 algorithm 不是 HS256HS384HS512,就会受到影响。使用 HS* 算法的凭证从未被补充过该字段。

控制面不会主动移除已经写入配置中的该字段,因此仅完成升级并不会消除告警——每个受影响的凭证都需要被重新写入一次,这正是刷新脚本所做的事情。

升级步骤

  1. 升级控制面,参考就地升级
  2. 升级所有数据面,参考滚动升级
  3. 使用下面的脚本刷新受影响的凭证。
警告

请在所有数据面都升级完成之后再执行刷新。低于 3.9.4 的数据面仍然要求 private_key:如果在这类数据面仍在连接时刷新凭证,写入的配置将无法通过它的消费者 schema 校验,数据面会丢弃该凭证,使用该凭证认证的请求会开始返回 401

刷新受影响的凭证

如果受影响的凭证不多,直接在控制台里操作即可:逐个打开受影响的凭证,不做任何修改直接保存。保存本身就会重新写入该凭证,这正是刷新所需要的。下面的脚本做的是同一件事,只是一次覆盖所有网关组。

脚本通过 Admin API 用凭证当前的配置重新写入一次,让控制面重新把它同步到配置存储中,从而去掉占位字段。脚本不会修改任何凭证内容。

运行脚本需要 curljq、控制面地址,以及一个具备读取和更新消费者凭证权限的控制台令牌,参考从控制台获取令牌

export CP_ADDR="https://127.0.0.1:7443"
export API_KEY="a7ee-xxxxxxxxxxxxx"
#!/usr/bin/env bash
set -euo pipefail

api() {
curl -sk --fail-with-body -H "X-API-KEY: ${API_KEY}" -H "Content-Type: application/json" "$@"
}

for gg in $(api "${CP_ADDR}/api/gateway_groups?page_size=1000" | jq -r '.list[] | select(.type != "api7_ingress_controller") | .id'); do
for username in $(api "${CP_ADDR}/apisix/admin/consumers?gateway_group_id=${gg}&page_size=1000" | jq -r '.list[].username'); do
credentials=$(api "${CP_ADDR}/apisix/admin/consumers/${username}/credentials?gateway_group_id=${gg}&plugin_name=jwt-auth&page_size=1000")
while read -r credential; do
[ -n "${credential}" ] || continue
id=$(jq -r '.id' <<<"${credential}")
body=$(jq -c '{name, desc, labels, plugins} | with_entries(select(.value != null))' <<<"${credential}")
api -X PUT -d "${body}" \
"${CP_ADDR}/apisix/admin/consumers/${username}/credentials/${id}?gateway_group_id=${gg}" >/dev/null
echo "refreshed ${gg}/${username}/${id}"
done < <(jq -c '.list[] | select((.plugins["jwt-auth"].algorithm // "HS256") | startswith("HS") | not)' <<<"${credentials}")
done
done
备注

如果一个网关组下的消费者超过 1000 个,或者一个消费者下的凭证超过 1000 个,请调大 page_size,或使用 page 参数分页遍历。每个列表响应的 total 字段会告诉你总共有多少条记录。

脚本会跳过由 Ingress Controller 管理的网关组:Admin API 不接受使用控制台令牌对这类网关组的写入,它们的配置会在 Ingress Controller 下一次同步时被重新写入。

如果 jwt-auth 直接配置在消费者自身的 plugins 字段上而不是凭证上,这类配置是凭证机制出现之前的历史数据,无法通过 Admin API 重新写入——Admin API 会拒绝直接配置在消费者上的认证插件。请把这类配置迁移到凭证上,以消除对应的告警。

验证

在控制台中打开对应的网关组,选择一个网关实例,查看它的配置兼容性报告。jwt-auth 应该不再出现在报告中,也不再提示 private_key 字段无法识别。

该报告由每个数据面根据自身持有的配置生成,并随心跳上报,因此刷新之后需要等待一个心跳周期再查看。