在现代企业 IT 架构中,零信任(Zero Trust)不再是可选项,而是安全基线。传统的边界防御模型假设内网是可信的,而零信任模型则坚持 “永不信任,始终验证” 的原则。身份联邦(Identity Federation)则解决了异构系统间的身份互通问题,使得员工可以使用一套凭证访问多个平台。本文将聚焦工程实践,探讨如何利用开源工具 Vouch Proxy,结合 OIDC(OpenID Connect)与 JWT(JSON Web Token),在 Nginx 环境下构建零信任身份联邦代理,并实现细粒度访问控制与跨域会话管理。
零信任与身份联邦的工程挑战
零信任架构的核心挑战在于如何将 “验证” 这件事从应用层剥离,下沉到基础设施层,同时保持灵活性。如果每个应用都自己实现一套登录逻辑,不仅维护成本高,而且难以做到全局统一策略。身份联邦则要求我们在不同域名、不同安全域之间共享身份上下文,比如子公司与母公司之间,或者 SaaS 服务与企业 IdP(身份提供商)之间。
Vouch Proxy 正是为了解决这两个问题而生的。它是一个轻量级的身份验证代理,部署在 Nginx 之后,作为 “守门人”。当用户访问受保护资源时,Nginx 的 auth_request 模块会先将请求发送给 Vouch Proxy。Vouch Proxy 会检查是否存在有效的 JWT Cookie,如果不存在或已过期,则将用户重定向到配置的 OIDC IdP(如 Google、Okta、Keycloak)进行登录。整个过程对用户透明,登录成功后,Vouch Proxy 会签发一个包含用户身份信息(Claims)的 JWT,并将其写入 Cookie。随后,Vouch Proxy 将请求放回 Nginx,Nginx 再将请求转发给后端应用,同时通过 HTTP 头(如 X-Vouch-User)传递用户身份。
这种架构的优势在于:后端应用无需关心登录逻辑,只需解析 Header 即可知道 “用户是谁”。同时,由于 JWT 是自包含的,后端服务甚至可以独立验证 JWT 的有效性,无需实时查询 IdP,这大大提升了性能。
核心架构与认证流程解析
Vouch Proxy 的工作流程可以分为四个阶段:请求拦截、身份验证、JWT 签发与请求转发。
首先是请求拦截。Nginx 的 auth_request 模块是实现这一点的关键。当配置了 auth_request /validate 后,Nginx 会在处理请求之前,先向 Vouch Proxy 的 /validate 端点发起一个子请求。如果 Vouch Proxy 返回 200 OK,则主请求继续;如果返回 401 Unauthorized,则 Nginx 根据 error_page 指令将用户重定向到登录页。这种机制将认证逻辑与业务逻辑完全解耦。
其次是身份验证阶段。如果用户没有有效的 JWT Cookie,Vouch Proxy 会生成一个随机的 state(防止 CSRF 攻击),并记录用户原本请求的 URL(用于登录后重定向),然后将用户重定向到 IdP 的授权端点。用户登录成功后,IdP 会将浏览器重定向回 Vouch Proxy 的 /auth 端点,并携带授权码(Authorization Code)和 state。Vouch Proxy 验证 state 后,会使用授权码向 IdP 交换访问令牌(Access Token),并通过访问令牌获取用户信息(UserInfo)。
接下来是 JWT 签发与 Cookie 设置。Vouch Proxy 从用户信息中提取所需的 Claims(如 email、groups),并使用配置的密钥(默认为 HMAC-SHA256,即 HS256)对这些信息进行签名,生成一个 JWT。这个 JWT 被设置为名为 VouchCookie 的 Cookie,作用域为配置的共享域(如 .yourdomain.com)。这样,子应用(如 app1.yourdomain.com、app2.yourdomain.com)都能共享这个 Cookie,实现跨域单点登录(SSO)。
最后是请求转发与 Header 传递。Vouch Proxy 在验证 JWT 有效后,会在响应头中设置 X-Vouch-User(通常包含用户邮箱或用户名)以及 X-Vouch-IdP-Claims-*(包含自定义 Claims,如用户组)。Nginx 通过 auth_request_set 指令捕获这些响应头,并将其注入到主请求的环境中,最终通过 proxy_set_header 传递给后端应用。
在配置文件中,domains 和 cookie.domain 的设置至关重要。如果 domains 设置为 yourdomain.com,那么 Vouch Proxy 就会尝试设置 .yourdomain.com 的 Cookie;如果 domains 未设置,则需要显式配置 vouch.cookie.domain,否则跨域 SSO 将无法工作。这一点也是新手最容易踩坑的地方。
工程化配置与部署要点
Vouch Proxy 的部署高度灵活,既可以通过 docker 容器运行,也可以直接编译运行。下面以 Docker 为例,介绍关键的工程化配置。
基础配置需要关注三个方面:OAuth/OIDC 设置、Vouch 服务设置以及 Cookie 与 JWT 设置。在 OAuth 设置中,provider 指定了使用的 IdP 类型(如 google、oidc),client_id 和 client_secret 是 IdP 端注册应用后获得的凭证,callback_urls 必须与 IdP 中配置的回调地址完全一致。
Vouch 服务设置包括监听地址、端口、日志级别以及超时时间。特别需要注意的是超时时间的配置。如果 Vouch Proxy 前端有负载均衡器或代理,需要确保 Vouch 的 idleTimeout 大于前端代理的空闲超时时间,否则可能会出现间歇性的 502 Bad Gateway 错误。
JWT 和 Cookie 的配置直接关系到安全性和用户体验。jwt.signing_method 默认为 HS256,适用于单机部署;如果是多实例部署,则建议使用 RS256 或 ES256,并配置公私钥文件。jwt.maxAge 控制 JWT 的有效期,默认为 240 分钟(4 小时)。cookie.secure 必须设置为 true(生产环境强制要求 HTTPS),sameSite 建议设置为 lax 或 strict,以防止 CSRF 攻击。
为了实现细粒度访问控制,Vouch Proxy 支持 Claims 映射。通过配置 headers.claims,你可以将 IdP 返回的用户组(groups)、名字(given_name)等信息提取出来,作为自定义 HTTP 头传递给后端。例如,配置 claims: [groups],后端服务就会收到 X-Vouch-IdP-Claims-Groups 头。后端服务可以基于这个 Header 实现权限判断,比如只有 admin 组的用户才能访问 /admin 路由。这种方式将认证(Authentication)与授权(Authorization)分离,后端服务只需专注于授权逻辑。
对于更复杂的场景,比如基于 IP 地址的访问控制,可以在 Nginx 层通过 satisfy any 指令结合 allow/deny 指令实现。Vouch Proxy 官方文档中也提到了这一点:可以在 Vouch 验证之前,先由 Nginx 检查 IP 白名单,如果 IP 在白名单中则直接放行,否则再走 Vouch 验证流程。
总结与实践建议
Vouch Proxy 为 Nginx 用户提供了一个简洁、高效的零信任身份联邦解决方案。它通过 OIDC 协议与各种主流 IdP 互通,通过 JWT 实现了安全的会话管理,并通过 HTTP Header 将身份上下文传递给后端应用。在落地过程中,工程师需要特别注意以下几点:
- Cookie 域配置:确保
vouch.domains与vouch.cookie.domain设置正确,且所有子应用都在同一个根域下。 - 安全加固:生产环境务必启用 HTTPS,并配置强密码或非对称密钥作为 JWT 签名密钥。
- 性能优化:对于高并发场景,建议将 Vouch Proxy 与 Nginx 部署在同一台机器上,实测响应时间可控制在 1 毫秒以内。
- 细粒度授权:将授权逻辑下放到应用层或 OpenResty,利用 Vouch 传递的 Claims 实现动态访问控制。
通过 Vouch Proxy,我们可以在不修改业务代码的前提下,将一套统一的身份治理体系(零信任 + 身份联邦)平滑地嵌入到现有的 Web 架构中,这正是工程化思维的体现。
参考资料:
- Vouch Proxy GitHub 仓库:https://github.com/vouch/vouch-proxy
- Vouch Proxy 官方配置示例:https://raw.githubusercontent.com/vouch/vouch-proxy/master/config/config.yml_example