ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Envoy JWT 认证过滤器:claim_to_headers 无法解析时的静默丢弃问题与 Debug 日志修复

Envoy JWT 认证过滤器:claim_to_headers 无法解析时的静默丢弃问题与 Debug 日志修复 Envoy JWT 认证过滤器claim_to_headers 无法解析时的静默丢弃问题与 Debug 日志修复【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文围绕 Envoy 当前版本changelogs/current的一条 bug fix 展开jwt_authnHTTP 过滤器在claim_to_headers配置的 claim 无法从 JWT payload 中解析时此前会静默丢弃对应的头注入现在会输出 debug 级别日志。读完本文你将理解claim_to_headers的完整工作机制配置字段、claim 路径解析、值类型转换、该静默丢弃发生在哪条代码路径上、如何开启日志定位问题以及与之联动的clear_route_cache和头清洗header sanitization行为。一、这次修复了什么Changelog 原文jwt_authn__log-unresolvable-claim.rst只有一句话但信息量很关键Fixed a bug where aclaim_to_headersentry whose claim could not be resolved in the JWT payload was dropped without any trace. Such an entry is now logged at debug level.翻译成工程语言修复前你在JwtProvider.claim_to_headers里配置了「把 JWT payload 中某个 claim 拷贝为某个请求头」但如果这个 claim 在实际 token 的 payload 里不存在拼错了 claim 名、payload 结构与预期不符、claim 为空对象等过滤器就什么都不做——不注入头、不记日志、不报错。上游服务如果依赖这个头会收到一个缺失关键身份信息的请求排查时几乎没有线索。修复后解析失败时会输出一条 debug 日志明确指出是哪个 claim 路径无法解析、解析状态码是什么、哪个头因此没有被添加。这是一条典型的可观测性修复行为本身解析失败则不注入头没有变变的是「失败可被看到」。二、claim_to_headers 的完整工作机制2.1 配置字段定义API 定义在 config.proto 中JwtProvider消息的claim_to_headers字段repeated JwtClaimToHeader claim_to_headers 15;见 config.proto#L372类型是JwtClaimToHeader的 repeated 字段。JwtClaimToHeader消息见 config.proto#L907 起的核心字段header_nameclaim 值要写入的目标请求头名称claim_name点号分隔的 claim 路径字符串如sub、realm_access.rolesclaim_path结构化的PathSegment列表适合 claim 路径本身包含点号等复杂 key 的场景。约束claim_name与claim_path必须且只能设置其一。这条约束不是靠 proto validation 注解实现的proto 注解无法表达「二选一」语义而是在过滤器配置加载阶段由代码强制校验见 filter_config.cc#L31-L36若两者同时为空或同时非空直接拒绝整个 provider 配置错误信息形如Provider xxx has a claim_to_headers entry for header yyy which does ...同时设置或同时缺失都会触发。一个符合该约束的配置示例configs/jwt_authn.yaml展示了jwt_authn过滤器的整体用法claim 头注入部分可在此基础上补充filters: - name: envoy.filters.http.jwt_authn typed_config: type: type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication providers: my_provider: issuer: https://accounts.google.com forward: true remote_jwks: http_uri: uri: cluster: jwks_cluster path: /jwks.json cache_duration: 300s claim_to_headers: - header_name: x-verified-sub claim_name: sub # 与 claim_path 二选一 - header_name: x-verified-roles claim_path: # 复杂 key 场景用结构化路径 - key: realm_access - key: roles2.2 配置加载期claim 路径的一次性解析请求路径上的每一步都不应重复做字符串切分。在 jwks_cache.cc#L54-L71JwksDataImpl的构造函数会在每个 provider 初始化时而非每请求把claim_to_headers条目解析成显式路径claim_path为空时用absl::StrSplit(claim_name, .)把点号字符串拆成路径段claim_path非空时逐段取PathSegment.key()结果存入claims_to_headers_vectorClaimToHeader见 jwks_cache.h#L55-L80 的接口注释「Aclaim_to_headersentry with its claim path resolved once, at config load」。代码注释里也明确记录了前置条件FilterConfigImpl在构造JwksCache之前已保证「每个条目恰好设置了claim_name或claim_path之一」所以此处只需二选一分支不需要再校验。2.3 请求处理期claim 值提取与头注入JWT 校验成功后AuthenticatorImpl::handleGoodJwt遍历该 provider 的全部claim_to_headers条目逐一调用addJWTClaimToHeaderauthenticator.cc#L407-L414。核心实现在 authenticator.cc#L340-L389流程是用StructUtils payload_getter(jwt_-payload_pb_)以解析好的 claim 路径去 JWT payloadprotobufStruct中取值取到值后按类型转换为目标头字符串string原样使用number经convertClaimDoubleToString转成十进制字符串bool转成字面量true/falsestruct / list先序列化为 JSON再做Base64 编码后作为头值避免 JSON 中的冒号、引号等破坏头解析其他未知类型记一条 debug 日志后跳过注意这与「claim 不存在」是两种不同情况前者是 claim 存在但类型不支持。转换结果非空时通过headers_-addCopy把目标头加入请求头并记一条成功日志[jwt_auth] claim : path with value : value is added to the header : header。2.4 本次修复的日志落点StructUtils::GetValueByPath返回非 OK 状态claim 路径在 payload 中不存在时走 else 分支——这正是本次修复新增的日志位置authenticator.cc#L382-L388} else { ENVOY_LOG(debug, [jwt_auth] claim : {} could not be resolved in the payload (status {}); the header : {} is not added, absl::StrJoin(claim_path, .), static_castint(status), header_name); }日志里三个占位符分别对应占位符含义排查价值claim路径段用.连接配置里声明的 claim 路径直接对照 token payload 检查是否拼错、是否真的缺失status整数StructUtils::GetValueByPath的返回状态码区分「路径某段不存在」「段类型不匹配」等失败原因header因此未被注入的目标头名与上游报错中「缺少某头」一一对应如何使用把jwt日志模块调到 debug 级别即可复现排查。运行期可通过 admin 接口/logging?leveldebug全局或/logging/jwt?leveldebug仅 jwt 模块动态调整无需重启也可在启动参数中用--component-log-level jwt:debug。开启后成功注入与解析失败都会出现在日志中形成对照[debug][jwt] [jwt_auth] claim : sub with value : user-123 is added to the header : x-verified-sub [debug][jwt] [jwt_auth] claim : realm_access.roles could not be resolved in the payload (status N); the header : x-verified-roles is not added需要强调的一点这条修复不改变判定行为——解析失败的条目依旧不注入头、JWT 依旧判定为有效claim 缺失不构成鉴权失败鉴权失败只与签名、issuer、aud、exp、sub 匹配等相关。它只是把「配置写了但从未生效」这件事从黑箱变成可检索的日志。三、与 claim_to_headers 联动的两个关键行为理解了头注入本身后还有两处与「头是否真正加上去」强相关的逻辑值得注意否则容易误判。3.1 clear_route_cache路由缓存失效联动在handleGoodJwt中authenticator.cc#L412-L414if (provider.clear_route_cache() (header_added || !provider.payload_in_metadata().empty())) { clear_route_cache_ true; }header_added是本轮所有addJWTClaimToHeader调用的逻辑或结果。也就是说只有确实有至少一个 claim 头被注入成功或配置了payload_in_metadata且clear_route_cache: true时才会清除该 stream 上的路由缓存使后续路由决策能看到新注入的头。若所有 claim 都解析失败header_added为 false缓存不会被清——这是设计使然但也是排查「为什么路由规则里匹配不到我注入的头」时的一个检查点先用 debug 日志确认头到底加没加上。3.2 bypass 路径的头清洗防伪造身份头claim_to_headers配置的所有header_name连同forward_payload_header在配置加载时就被收集进一个待清洗列表extractor.cc#L229-L235for (const auto header_and_claim : provider.claim_to_headers()) { headers_to_sanitize_.emplace_back(header_and_claim.header_name()); }过滤器级的sanitizePayloadHeadersfilter_config.h#L96-L105会在所有 bypass 路径没有匹配到 rule、requires为空、per-route 禁用、CORS preflight 等上把这些头从请求中删除防止客户端伪造这些「应当由 JWT 验证后由 Envoy 生成」的身份头直接打到上游。当前行为受 runtime flagenvoy.reloadable_features.jwt_authn_sanitize_payload_headers_filter_wide保护注释说明这是为了允许运维在灰度期回退到旧行为。这个联动对调试有直接含义如果你在未认证通过的请求上看到目标头消失或客户端显式发送了同名的x-verified-sub却发现上游没收到原因不是过滤器丢了它而是清洗逻辑按设计删掉了它。四、排查清单小结结合本次修复遇到「配置了claim_to_headers但上游收不到头」时按以下顺序检查开 debug 日志/logging/jwt?leveldebug确认日志中出现的是「is added to the header」成功还是「could not be resolved in the payload」本次修复新增的失败日志对照 payload拿真实 token 的 payload 段base64url 解码后核对 claim 路径注意嵌套 key 需用claim_name: a.b或claim_path表达检查类型struct/list 类型会以 Base64(JSON) 注入未知类型走另一条 debug 日志「claim : ... is of an unknown type」两者日志文案不同便于区分检查路由缓存若路由规则依赖注入的头确认clear_route_cache: true且确实有头注入成功检查请求路径确认该请求真的走了匹配jwt_authnrule 的路径而不是 bypass 路径bypass 时清洗逻辑会删除这些头这属于安全设计。五、适用前提与版本说明该修复条目位于 changelogs/current/bug_fixes/ 目录对应尚未发布的在研版本current 会在发版时归档进正式 changelog因此只有包含该提交的构建/镜像才会输出这条 debug 日志claim_to_headers本身是稳定 APIv3上述配置字段与行为以当前仓库 config.proto 为准修复本身是纯可观测性变更不新增统计项、不改变 401/403 判定、不改变任何头的注入结果升级没有行为回退风险。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表