Skip to main content

概览

Caddy 的 forward_auth 会询问另一个服务某个请求是否可以继续。将它指向 GoModel 的 GET /v1/auth/verify,Caddy 就能基于 GoModel API 密钥控制流量——而代理中无需保存这些密钥的任何副本。 这种做法有两个用途:
  • 在边缘拒绝未认证的流量。 没有可用密钥的请求永远不会到达网关,因此扫描器和配置错误的客户端既不会与网关建立连接,也不会出现在其审计日志中。GoModel 仍会对其处理的每个请求进行认证;边缘检查是前置的过滤器,而不是替代品。
  • 用 GoModel 密钥保护其他服务。 同一主机上的内部控制台、文档站点或指标端点,无需自行实现认证,即可要求访问者持有有效的 GoModel 密钥。
/v1/auth/verify 默认禁用。使用 AUTH_VERIFY_ENABLED=true(server.auth_verify_enabled)启用。它不是 /admin 路由,因此在 ADMIN_ENDPOINTS_ENABLED=false 时仍可正常工作。

工作原理

forward_auth 仅根据状态码做出决定: GoModel 的 401 响应体是其常规的 OpenAI 格式错误封装,因此已经能理解 GoModel 错误的客户端,从代理处看到的也是熟悉的格式。 200 响应体(valid、method、key_id、user_path)会被 Caddy 忽略—— 它是为想知道哪个密钥通过验证的脚本和服务准备的。

用 GoModel 密钥保护其他服务

这里的上游可以是任何您希望用 GoModel 密钥保护的应用。
forward_auth 会将传入请求自身的请求头发送给 GoModel,因此被检查的正是调用方的 Authorization: Bearer sk_gom_...(或 x-api-key)。无需其他任何配置即可让凭据到达网关。 copy_headers X-Gomodel-Auth-User 会转发 GoModel 关于调用方是谁的答复:对于绑定了用户路径的托管密钥,上游会收到该路径,并可据此限定展示的内容。对于使用主密钥的调用方以及未绑定路径的密钥,该请求头为空。 验证一下:

在网关前过滤流量

要在 GoModel 本身前面加上同样的检查,请向网关进行验证并将请求代理给它:
这样,每个被代理的请求都会多一次到网关的往返,并且网关在处理请求时还会再认证一次。这是在未认证流量到达应用之前将其丢弃的代价——在面向互联网的边缘值得这样做;而在私有网络中,如果 GoModel 自身的认证已经是唯一的关卡,则不值得。 如果您使用以下路由,它们必须在没有密钥的情况下仍可访问:
健康检查和 Prometheus 抓取请求不携带 API 密钥,因此如果不这样配置,即使 GoModel 本身无需认证即可响应它们,它们也会被边缘关卡拒绝。
关卡的强度取决于网关自身的认证。 在既没有主密钥也没有托管密钥的 GoModel 实例上(即不安全的开发默认配置),所有请求都会被接受,/v1/auth/verify 会返回 200 和 {"valid": false, "method": "none"}(因为没有可确认的密钥),forward_auth 会放行所有请求。在依赖此机制拦截任何流量之前,请先设置 GOMODEL_MASTER_KEY 或签发托管密钥。

注意事项

  • Caddy 会在每个请求上重新检查密钥。forward_auth 中没有结果缓存,因此每个被代理的请求都会让网关收到一次验证调用;/v1/auth/verify 不会调用提供商,直接根据密钥存储作答。
  • 该端点会返回 Cache-Control: no-store——答复描述的是某个调用方的凭据,不得提供给其他任何人。
  • 启用该端点相当于暴露了一个密钥校验器(oracle):任何能访问它的人都可以测试某个密钥是否有效。请仅在需要的地方暴露它,并对不受信任的调用方启用 GoModel 的速率限制。
  • Caddy 会在验证子请求中添加 X-Forwarded-Method 和 X-Forwarded-Uri。GoModel 会忽略这两者;检查针对的是凭据,而不是所请求的路由。
最后修改于 2026年10月24日