网关鉴权用 auth_request 交给独立服务,还是网关本地校验 JWT?延迟差多少?令牌撤销多久生效?鉴权服务挂了怎么办?身份头会不会被伪造?这篇用 nginx 1.31.6 和 Envoy 1.39.3 逐项量出来。
做法 | 延迟中位数 | p99 | 鉴权服务被调用 | 状态码
----------------------------------+----------+----------+---------+-----------
不鉴权 | 0.15 ms | 0.54 ms | 0 | {200: 500}
auth_request(鉴权服务 ~0 ms) | 0.32 ms | 0.51 ms | 500 | {200: 500}
auth_request(鉴权服务 20 ms) | 29.34 ms | 33.15 ms | 500 | {200: 500}
auth_request + 缓存 5 s(鉴权服务 20 ms) | 0.17 ms | 0.57 ms | 1 | {200: 500}
Envoy 本地 jwt_authn | 0.18 ms | 0.34 ms | 0 | {200: 500}auth_request 每个请求多一次往返;加缓存可以把鉴权服务的调用降到几乎为零,本地校验没有往返。
做法 | 撤销之后,最后一个被放行的请求距撤销多久 | 撤销之后第一个被拒绝的请求距撤销多久 | 撤销之后仍被放行的请求数 --------------------------------------------+----------------------+--------------------+------------- auth_request 无缓存 | 立刻 | 0.00 s | 0 auth_request 缓存 5 s | 2.34 s | 2.60 s | 10 Envoy 本地 jwt_authn(clock_skew_seconds 保持默认) | 11.36 s | 没有拒绝 | 45 Envoy 本地 jwt_authn(clock_skew_seconds: 1) | 10.60 s | 10.86 s | 42 本地校验 JWT 不查撤销名单,令牌在过期之前一直有效(令牌有效期 12 秒、撤销发生在第 3 秒,所以要等令牌过期才会被拒);Envoy jwt_authn 的 clock_skew_seconds 默认允许令牌过期之后再宽限一段时间(默认值下整个 14.5 秒的测试里令牌一直被放行,设成 1 才在过期时被拒(0 表示“用默认值”,不能用来关掉宽限));auth_request 每次问鉴权服务,撤销立刻生效;给鉴权结果加缓存,撤销的生效延迟最长就是缓存时间
auth_request 可以立刻撤销,缓存会延迟;本地校验无法撤销,只能等过期。
做法 | 第 0 秒 放行/失败 | 第 1 秒 放行/失败 | 第 2 秒 放行/失败 | 第 3 秒 放行/失败 | 第 4 秒 放行/失败 | 第 5 秒 放行/失败 --------------------------------------------------------+-------------+-------------+-------------+-------------+-------------+------------ auth_request 无缓存 | 50/0 | 50/0 | 0/50 | 0/50 | 0/50 | 0/50 auth_request 缓存 5 s,proxy_cache_use_stale error timeout | 50/0 | 50/0 | 50/0 | 50/0 | 50/0 | 50/0 auth_request 缓存 5 s,不允许用过期缓存 | 50/0 | 50/0 | 50/0 | 50/0 | 50/0 | 16/34 Envoy 本地 jwt_authn(鉴权服务关不关都不影响) | 50/0 | 50/0 | 50/0 | 50/0 | 50/0 | 50/0 auth_request 是网关对鉴权服务的硬依赖:无缓存时鉴权服务一挂,所有需要鉴权的请求立刻失败;带缓存且不允许用过期缓存时,缓存有效期内的请求还能放行,缓存过期之后一起失败;加了 proxy_cache_use_stale error timeout 之后,鉴权服务挂了,过期的缓存继续被用,请求一直被放行——可用性好了,代价是撤销、封禁都不再生效(这是“失败时放行”的行为);本地校验的网关不依赖外部服务
auth_request 是硬依赖;缓存加 use_stale 会失败时放行;本地校验不受影响。
配置 | 状态码 | 后端回应(hello + 它看到的 X-User) ---------------------------------------------+-----+-------------------------- nginx (a) 不覆盖 X-User | 200 | hello admin nginx (b) proxy_set_header X-User $auth_user | 200 | hello alice Envoy jwt_authn(没有配置覆盖) | 200 | hello admin 网关鉴权通过之后,要把“已验证的身份”用网关自己的值覆盖到发给后端的头里,并且把 client 发来的同名头丢掉,否则后端会信任伪造的身份
网关要用自己确认的身份覆盖发给后端的头。