claude-apps-gateway-deploy.md +28 −26
6 6
7> 向身份提供商注册网关,构建容器,在 Kubernetes 或 Cloud Run 上部署,并运维它:健康检查、密钥轮换、升级和安全。7> 向身份提供商注册网关,构建容器,在 Kubernetes 或 Cloud Run 上部署,并运维它:健康检查、密钥轮换、升级和安全。
8 8
99本页面涵盖运行 [Claude 应用网关](/zh-CN/claude-apps-gateway) 的运维方面:在身份提供商 (IdP) 中注册 OAuth 客户端、将网关部署为容器,以及日常运行。关于网关在启动时读取的 `gateway.yaml` 文件中的每个选项,请参阅 [配置参考](/zh-CN/claude-apps-gateway-config)。本页面涵盖运行 [Claude 应用网关](/docs/zh-CN/claude-apps-gateway) 的运维方面:在身份提供商 (IdP) 中注册 OAuth 客户端、将网关部署为容器,以及日常运行。关于网关在启动时读取的 `gateway.yaml` 文件中的每个选项,请参阅 [配置参考](/docs/zh-CN/claude-apps-gateway-config)。
10 10
11生产部署按顺序遵循四个步骤,下面的部分与之相对应。前两个是您做出选择的地方;后两个是在运行后参考的材料。11生产部署按顺序遵循四个步骤,下面的部分与之相对应。前两个是您做出选择的地方;后两个是在运行后参考的材料。
12 12
31 31
32任何符合 OIDC 的 IdP 都可以工作:Okta、Microsoft Entra ID、Google Workspace、Keycloak、Dex、PingFederate 等。IdP 必须满足三个要求:32任何符合 OIDC 的 IdP 都可以工作:Okta、Microsoft Entra ID、Google Workspace、Keycloak、Dex、PingFederate 等。IdP 必须满足三个要求:
33 33
3434* 在生产环境中通过 HTTPS 提供 `/.well-known/openid-configuration`;网关接受 [`http://` 发行者](/zh-CN/claude-apps-gateway-config#oidc),本地环回发行者另外需要 `CLAUDE_GATEWAY_ALLOW_LOOPBACK=1`* 在生产环境中通过 HTTPS 提供 `/.well-known/openid-configuration`;网关接受 [`http://` 发行者](/docs/zh-CN/claude-apps-gateway-config#oidc),本地环回发行者另外需要 `CLAUDE_GATEWAY_ALLOW_LOOPBACK=1`
35* 支持授权代码流。PKCE(代码交换证明密钥)默认启用;对于不支持它的 IdP,使用 `oidc.use_pkce: false` 禁用它35* 支持授权代码流。PKCE(代码交换证明密钥)默认启用;对于不支持它的 IdP,使用 `oidc.use_pkce: false` 禁用它
36* 在 id\_token 中返回 `email` 和可选的 `groups`,或使用 `oidc.userinfo_fallback: true` 从 userinfo 端点提供它们36* 在 id\_token 中返回 `email` 和可选的 `groups`,或使用 `oidc.userinfo_fallback: true` 从 userinfo 端点提供它们
37 37
41 41
42* **Okta**:位于 `https://example.okta.com` 的组织授权服务器返回一个省略 `email` 和 `groups` 的简化 id\_token,因此当您将其用作 `issuer` 时设置 `oidc.userinfo_fallback: true`。包含 id\_token 中 `email` 和可选 `groups` 的自定义授权服务器(如 `https://example.okta.com/oauth2/default`)直接发出它们,不需要回退。Okta 仅在 `oidc.scopes` 中请求 `groups` 作用域且应用的组声明过滤器允许时才发出 `groups`;`userinfo_fallback` 无法填充 IdP 未被要求的声明。42* **Okta**:位于 `https://example.okta.com` 的组织授权服务器返回一个省略 `email` 和 `groups` 的简化 id\_token,因此当您将其用作 `issuer` 时设置 `oidc.userinfo_fallback: true`。包含 id\_token 中 `email` 和可选 `groups` 的自定义授权服务器(如 `https://example.okta.com/oauth2/default`)直接发出它们,不需要回退。Okta 仅在 `oidc.scopes` 中请求 `groups` 作用域且应用的组声明过滤器允许时才发出 `groups`;`userinfo_fallback` 无法填充 IdP 未被要求的声明。
43* **Microsoft Entra ID**:`issuer` = `https://login.microsoftonline.com/<tenant-id>/v2.0`。Entra 发出组对象 ID 而不是名称,因此在 `managed.policies.match.groups` 中使用 GUID,或使用应用角色获得人类可读的名称。如果您的租户在 `roles` 而不是 `groups` 下发出角色,设置 `oidc.groups_claim: roles`。43* **Microsoft Entra ID**:`issuer` = `https://login.microsoftonline.com/<tenant-id>/v2.0`。Entra 发出组对象 ID 而不是名称,因此在 `managed.policies.match.groups` 中使用 GUID,或使用应用角色获得人类可读的名称。如果您的租户在 `roles` 而不是 `groups` 下发出角色,设置 `oidc.groups_claim: roles`。
4444* **Google Workspace**:`issuer` = `https://accounts.google.com`。Google 的 id\_token 不包含组。要在 Google 作为 IdP 时使用基于组的 `allowed_groups` 或 `managed.policies`,配置 [`oidc.google_groups`](/zh-CN/claude-apps-gateway-config#oidc),它使用具有域范围委派的服务账户通过 Admin SDK Directory API 查找每个用户的组。没有它,使用 `oidc.allowed_email_domains` 进行成员资格门控,使用 `managed.policies.match.email_domain` 进行策略分配。Google 也忽略标准 `offline_access` 作用域。对于刷新令牌,设置 `oidc.scopes: [openid, profile, email]` 和 `oidc.extra_auth_params: { access_type: offline, prompt: consent }`。* **Google Workspace**:`issuer` = `https://accounts.google.com`。Google 的 id\_token 不包含组。要在 Google 作为 IdP 时使用基于组的 `allowed_groups` 或 `managed.policies`,配置 [`oidc.google_groups`](/docs/zh-CN/claude-apps-gateway-config#oidc),它使用具有域范围委派的服务账户通过 Admin SDK Directory API 查找每个用户的组。没有它,使用 `oidc.allowed_email_domains` 进行成员资格门控,使用 `managed.policies.match.email_domain` 进行策略分配。Google 也忽略标准 `offline_access` 作用域。对于刷新令牌,设置 `oidc.scopes: [openid, profile, email]` 和 `oidc.extra_auth_params: { access_type: offline, prompt: consent }`。
45 45
46有关不在上述范围内的身份提供商的支持,请参阅[故障排除](#troubleshooting)。46有关不在上述范围内的身份提供商的支持,请参阅[故障排除](#troubleshooting)。
47 47
48<Warning>48<Warning>
49 刷新令牌让网关可以在不将开发者发送回浏览器的情况下无声地续订开发者的会话。它们也驱动取消配置,因为当 IdP 禁用用户时,下一次刷新失败,会话在 `ttl_hours` 内结束。网关默认请求 `offline_access` 以获取刷新令牌。如果您的 IdP 需要明确同意离线访问,配置 OAuth 客户端以允许它。49 刷新令牌让网关可以在不将开发者发送回浏览器的情况下无声地续订开发者的会话。它们也驱动取消配置,因为当 IdP 禁用用户时,下一次刷新失败,会话在 `ttl_hours` 内结束。网关默认请求 `offline_access` 以获取刷新令牌。如果您的 IdP 需要明确同意离线访问,配置 OAuth 客户端以允许它。
50 50
5151 如果您的 IdP 根本无法发出刷新令牌,网关仍然可以工作,但没有无声续订,因此开发者在会话过期时重新运行浏览器登录。为了防止每小时都发生这种情况,将 [`session.ttl_hours`](/zh-CN/claude-apps-gateway-config#session) 提高到 `8` 或 `12`。权衡是取消配置延迟,因为没有刷新令牌,禁用的用户在更长的 TTL 过期之前保持访问权限。 如果您的 IdP 根本无法发出刷新令牌,网关仍然可以工作,但没有无声续订,因此开发者在会话过期时重新运行浏览器登录。为了防止每小时都发生这种情况,将 [`session.ttl_hours`](/docs/zh-CN/claude-apps-gateway-config#session) 提高到 `8` 或 `12`。权衡是取消配置延迟,因为没有刷新令牌,禁用的用户在更长的 TTL 过期之前保持访问权限。
52</Warning>52</Warning>
53 53
54<h2 id="deployment">54<h2 id="deployment">
62除了运行位置外,还有一些决策塑造部署:62除了运行位置外,还有一些决策塑造部署:
63 63
64* **成本**:网关没有单独的许可证或按座位费用;它是 `claude` 二进制文件的一部分。您通过现有的云或 Anthropic 承诺为推理付费,加上容器的计算和您的遥测收集器。64* **成本**:网关没有单独的许可证或按座位费用;它是 `claude` 二进制文件的一部分。您通过现有的云或 Anthropic 承诺为推理付费,加上容器的计算和您的遥测收集器。
6565* **绕过**:网关不强制执行通过它的唯一模型路由。具有自己凭证的开发者仍然可以直接调用提供商,因此关闭该路径是网络策略决策,例如阻止到 `api.anthropic.com` 的出口,除了来自网关的。阻止该出口也会破坏 [WebFetch 域安全检查](/zh-CN/data-usage#webfetch-domain-safety-check),它从每个开发者的机器调用 `api.anthropic.com`;在托管策略中设置 `skipWebFetchPreflight: true` 以禁用它。* **绕过**:网关不强制执行通过它的唯一模型路由。具有自己凭证的开发者仍然可以直接调用提供商,因此关闭该路径是网络策略决策,例如阻止到 `api.anthropic.com` 的出口,除了来自网关的。阻止该出口也会破坏 [WebFetch 域安全检查](/docs/zh-CN/data-usage#webfetch-domain-safety-check),它从每个开发者的机器调用 `api.anthropic.com`;在托管策略中设置 `skipWebFetchPreflight: true` 以禁用它。
66* **多个网关**:每个网关是一个单独的部署,有自己的配置。CLI 按网关主机名存储其信任指纹和凭证,因此不同的团队可以连接到不同的网关而不会冲突。要提供多个 OIDC 发行者,运行单独的实例。66* **多个网关**:每个网关是一个单独的部署,有自己的配置。CLI 按网关主机名存储其信任指纹和凭证,因此不同的团队可以连接到不同的网关而不会冲突。要提供多个 OIDC 发行者,运行单独的实例。
67* **无服务器**:Cloud Run 可以工作;设置 `min-instances: 1` 以避免冷 OIDC 发现。Lambda 和 Cloud Functions 不行,因为网关是一个长时间运行的 HTTP 服务器。67* **无服务器**:Cloud Run 可以工作;设置 `min-instances: 1` 以避免冷 OIDC 发现。Lambda 和 Cloud Functions 不行,因为网关是一个长时间运行的 HTTP 服务器。
68 68
6969这里的每个生产拓扑都在普通 HTTP 副本前面放置一个 L7 代理,如 Ingress、Cloud Run 的前端或 ALB。设置 [`listen.trusted_proxies`](/zh-CN/claude-apps-gateway-config#listen) 为代理的源范围,以便网关从 `X-Forwarded-For` 读取客户端 IP。网关仅在 TCP 对等体受信任时才遵守该标头;[Google Cloud 工作示例](/zh-CN/claude-apps-gateway-on-gcp) 为每个拓扑提供具体值。没有受信任的代理,每个请求似乎都来自代理的 IP,这会将按 IP 速率限制折叠为一个共享桶,并在审计事件中记录代理的 IP。这里的每个生产拓扑都在普通 HTTP 副本前面放置一个 L7 代理,如 Ingress、Cloud Run 的前端或 ALB。设置 [`listen.trusted_proxies`](/docs/zh-CN/claude-apps-gateway-config#listen) 为代理的源范围,以便网关从 `X-Forwarded-For` 读取客户端 IP。网关仅在 TCP 对等体受信任时才遵守该标头;[Google Cloud 工作示例](/docs/zh-CN/claude-apps-gateway-on-gcp) 为每个拓扑提供具体值。没有受信任的代理,每个请求似乎都来自代理的 IP,这会将按 IP 速率限制折叠为一个共享桶,并在审计事件中记录代理的 IP。
70 70
71<h3 id="container-image">71<h3 id="container-image">
72 容器镜像72 容器镜像
74 74
75围绕标准 Claude Code 版本中的本机 `claude` 二进制文件构建您自己的镜像:75围绕标准 Claude Code 版本中的本机 `claude` 二进制文件构建您自己的镜像:
76 76
77771. 从固定版本下载您的镜像架构的 Linux 构建;请参阅 [安装特定版本](/zh-CN/setup#install-a-specific-version) 了解下载 URL。1. 从固定版本下载您的镜像架构的 Linux 构建;请参阅 [安装特定版本](/docs/zh-CN/setup#install-a-specific-version) 了解下载 URL。
78782. 根据版本的 GPG 签名 `manifest.json` 验证它,如 [二进制完整性和代码签名](/zh-CN/setup#binary-integrity-and-code-signing) 中所述。2. 根据版本的 GPG 签名 `manifest.json` 验证它,如 [二进制完整性和代码签名](/docs/zh-CN/setup#binary-integrity-and-code-signing) 中所述。
793. 将其复制到构建上下文中。793. 将其复制到构建上下文中。
80 80
81如果您的构建无法到达版本主机,请将版本镜像到您的内部注册表中,并固定您的舰队运行的版本。81如果您的构建无法到达版本主机,请将版本镜像到您的内部注册表中,并固定您的舰队运行的版本。
82 82
83除了二进制文件外,镜像还需要:83除了二进制文件外,镜像还需要:
84 84
8585* **基于 glibc 的镜像**:glibc 构建的唯一动态依赖项是 glibc 库。基于 Musl 的镜像需要 `linux-x64-musl` 或 `linux-arm64-musl` 构建加上额外的包;请参阅 [Alpine Linux 设置](/zh-CN/setup#alpine-linux-and-musl-based-distributions)。* **基于 glibc 的镜像**:glibc 构建的唯一动态依赖项是 glibc 库。基于 Musl 的镜像需要 `linux-x64-musl` 或 `linux-arm64-musl` 构建加上额外的包;请参阅 [Alpine Linux 设置](/docs/zh-CN/setup#alpine-linux-and-musl-based-distributions)。
86* **可写状态目录**:网关以任何用户身份运行,但最小镜像没有可写的主目录。将 `CLAUDE_CONFIG_DIR` 设置为可写路径,如 `/tmp/.claude`。86* **可写状态目录**:网关以任何用户身份运行,但最小镜像没有可写的主目录。将 `CLAUDE_CONFIG_DIR` 设置为可写路径,如 `/tmp/.claude`。
87* **容器命令**:`claude gateway --config /etc/claude/gateway.yaml`,配置文件以只读方式挂载,密钥作为环境变量提供;网关在 `listen.port` 上监听,默认为 `8080`。87* **容器命令**:`claude gateway --config /etc/claude/gateway.yaml`,配置文件以只读方式挂载,密钥作为环境变量提供;网关在 `listen.port` 上监听,默认为 `8080`。
88 88
99<Note>99<Note>
100 **工作负载身份**100 **工作负载身份**
101 101
102102 优先使用平台的工作负载身份而不是静态密钥:EKS 上的 IRSA 用于 Bedrock 和 AWS 上的 Claude Platform,GKE 上的工作负载身份用于 Agent Platform,AKS 上的工作负载身份用于 Foundry。在上游块中设置 `auth: {}`,或对 Foundry 设置 `use_azure_ad: true`,网关通过该提供商的默认凭证链获取 pod 的身份。对于跨云配对,如 GKE 上的 Bedrock 上游,在上游的 `auth` 块中设置显式凭证。[`upstreams` 参考](/zh-CN/claude-apps-gateway-config#upstreams) 有每个平台的设置详情。 优先使用平台的工作负载身份而不是静态密钥:EKS 上的 IRSA 用于 Bedrock 和 AWS 上的 Claude Platform,GKE 上的工作负载身份用于 Agent Platform,AKS 上的工作负载身份用于 Foundry。在上游块中设置 `auth: {}`,或对 Foundry 设置 `use_azure_ad: true`,网关通过该提供商的默认凭证链获取 pod 的身份。对于跨云配对,如 GKE 上的 Bedrock 上游,在上游的 `auth` 块中设置显式凭证。[`upstreams` 参考](/docs/zh-CN/claude-apps-gateway-config#upstreams) 有每个平台的设置详情。
103</Note>103</Note>
104 104
105<h3 id="cloud-run">105<h3 id="cloud-run">
109按如下方式配置服务:109按如下方式配置服务:
110 110
111* 将 `listen.port` 保留在其默认值 `8080`,这与 Cloud Run 的默认 `PORT` 匹配,或设置 `port: ${PORT}`111* 将 `listen.port` 保留在其默认值 `8080`,这与 Cloud Run 的默认 `PORT` 匹配,或设置 `port: ${PORT}`
112112* 将 `public_url` 设置为外部可达的源。对于生产,这通常是内部负载均衡器的主机名,因为 `/login` [拒绝公共地址](/zh-CN/claude-apps-gateway#prerequisites),而 `*.run.app` URL 解析为一个,所以单独的 Cloud Run URL 仅适用于 `curl` 或浏览器烟雾测试。例外是一个网络,其中 `*.run.app` 通过 Private Service Connect 和 Cloud DNS 私有区域私下解析;在该拓扑中,Cloud Run URL 是有效的 `public_url`。[Google Cloud 工作示例](/zh-CN/claude-apps-gateway-on-gcp#deploy-the-gateway) 涵盖两者。* 将 `public_url` 设置为外部可达的源。对于生产,这通常是内部负载均衡器的主机名,因为 `/login` [拒绝公共地址](/docs/zh-CN/claude-apps-gateway#prerequisites),而 `*.run.app` URL 解析为一个,所以单独的 Cloud Run URL 仅适用于 `curl` 或浏览器烟雾测试。例外是一个网络,其中 `*.run.app` 通过 Private Service Connect 和 Cloud DNS 私有区域私下解析;在该拓扑中,Cloud Run URL 是有效的 `public_url`。[Google Cloud 工作示例](/docs/zh-CN/claude-apps-gateway-on-gcp#deploy-the-gateway) 涵盖两者。
113* 将配置作为密钥卷挂载113* 将配置作为密钥卷挂载
114* 设置 `min-instances: 1` 以避免首次请求时的冷 OIDC 发现114* 设置 `min-instances: 1` 以避免首次请求时的冷 OIDC 发现
115 115
116<Note>116<Note>
117117 有关 Google Cloud 上的完整工作示例,涵盖 Cloud Run 或 GKE、Cloud SQL 和 Secret Manager,请参阅 [在 Google Cloud 上部署](/zh-CN/claude-apps-gateway-on-gcp)。 有关 Google Cloud 上的完整工作示例,涵盖 Cloud Run 或 GKE、Cloud SQL 和 Secret Manager,请参阅 [在 Google Cloud 上部署](/docs/zh-CN/claude-apps-gateway-on-gcp)。
118</Note>118</Note>
119 119
120<h3 id="push-the-gateway-url-to-developer-machines">120<h3 id="push-the-gateway-url-to-developer-machines">
121 将网关 URL 推送到开发者机器121 将网关 URL 推送到开发者机器
122</h3>122</h3>
123 123
124124一旦网关开始提供服务,通过托管设置、MDM 或直接写入每个操作系统的 `managed-settings.json` 将 `forceLoginMethod` 和 `forceLoginGatewayUrl` 推送到每个开发者的机器。没有这个,`/login` 显示标准账户选择器,没有网关选项。请参阅 [客户端托管设置](/zh-CN/claude-apps-gateway-config#client-side-managed-settings) 了解文件路径。一旦网关开始提供服务,通过托管设置、MDM 或直接写入每个操作系统的 `managed-settings.json` 将 `forceLoginMethod` 和 `forceLoginGatewayUrl` 推送到每个开发者的机器。没有这个,`/login` 显示标准账户选择器,没有网关选项。请参阅 [客户端托管设置](/docs/zh-CN/claude-apps-gateway-config#client-side-managed-settings) 了解文件路径。
125 125
126<h2 id="operations">126<h2 id="operations">
127 运维127 运维
160 160
161* **现有会话**:持有者令牌使用 JWT 密钥在本地验证,会话刷新不接触存储,网关进程仍然可以提供推理161* **现有会话**:持有者令牌使用 JWT 密钥在本地验证,会话刷新不接触存储,网关进程仍然可以提供推理
162* **新登录**:失败直到 Postgres 恢复,因为设备流及其速率限制计数器存在于 Postgres 中162* **新登录**:失败直到 Postgres 恢复,因为设备流及其速率限制计数器存在于 Postgres 中
163163* **[支出限制执行](/zh-CN/claude-apps-gateway-spend-limits#postgres-availability)**:在中断期间默认失败开放,因此推理仍然流动;如果您宁愿阻止而不是无计量运行,将其翻转为失败关闭* **[支出限制执行](/docs/zh-CN/claude-apps-gateway-spend-limits#postgres-availability)**:在中断期间默认失败开放,因此推理仍然流动;如果您宁愿阻止而不是无计量运行,将其翻转为失败关闭
164* **就绪**:`/readyz` 在中断期间报告未就绪,因此在就绪上门控流量的编排器一次从轮换中移除每个副本。在该拓扑中,所有流量,包括网关仍然可以提供的推理,在负载均衡器处失败,直到 Postgres 恢复。`/healthz` 上的活跃探针继续通过,因此副本不会重新启动。如果您宁愿已登录的开发者在存储中断期间继续工作,将就绪探针指向 `/healthz`;成本是新登录失败,反对仍然报告就绪的副本。164* **就绪**:`/readyz` 在中断期间报告未就绪,因此在就绪上门控流量的编排器一次从轮换中移除每个副本。在该拓扑中,所有流量,包括网关仍然可以提供的推理,在负载均衡器处失败,直到 Postgres 恢复。`/healthz` 上的活跃探针继续通过,因此副本不会重新启动。如果您宁愿已登录的开发者在存储中断期间继续工作,将就绪探针指向 `/healthz`;成本是新登录失败,反对仍然报告就绪的副本。
165 165
166如果您的 IdP 宕机,现有会话工作直到 `ttl_hours`,新登录和刷新失败。如果您的 IdP 有频繁的维护窗口,设置更长的 `ttl_hours`。166如果您的 IdP 宕机,现有会话工作直到 `ttl_hours`,新登录和刷新失败。如果您的 IdP 有频繁的维护窗口,设置更长的 `ttl_hours`。
191| `admin_audit` | 管理员 API 变更跟踪 | `admin.audit_retention_days`,默认 365 |191| `admin_audit` | 管理员 API 变更跟踪 | `admin.audit_retention_days`,默认 365 |
192| `principal_emails` | 每个主体的最后看到的电子邮件、显示名称和 IdP 组。包含 PII。 | `admin.identity_retention_days` 自上次活动以来,默认 90 |192| `principal_emails` | 每个主体的最后看到的电子邮件、显示名称和 IdP 组。包含 PII。 | `admin.identity_retention_days` 自上次活动以来,默认 90 |
193 193
194194一个 30 秒的循环过期 `kv` 行超过其 TTL,一个每小时的扫描在支出表上强制保留窗口,因此没有什么无限增长。没有 [支出限制](/zh-CN/claude-apps-gateway-spend-limits) 配置,只有 `kv` 被写入。如果您的安全策略禁止应用角色的 DDL,预先创建这些表和 `_migrations`,使用管理员角色,并授予应用角色 `SELECT, INSERT, UPDATE, DELETE` 在每个上。一个 30 秒的循环过期 `kv` 行超过其 TTL,一个每小时的扫描在支出表上强制保留窗口,因此没有什么无限增长。没有 [支出限制](/docs/zh-CN/claude-apps-gateway-spend-limits) 配置,只有 `kv` 被写入。如果您的安全策略禁止应用角色的 DDL,预先创建这些表和 `_migrations`,使用管理员角色,并授予应用角色 `SELECT, INSERT, UPDATE, DELETE` 在每个上。
195 195
196使用支出限制,丢失的数据库意味着丢失支出跟踪和上限,不仅仅是开发者重新登录,因此运行定期备份。要立即删除一个离职的开发者而不是等待保留,直接运行 `DELETE FROM principal_emails WHERE principal = '<sub>'`;这移除了唯一持有其电子邮件、名称和组的表。`spend` 和 `admin_audit` 行仅引用伪匿名 OIDC `sub`。196使用支出限制,丢失的数据库意味着丢失支出跟踪和上限,不仅仅是开发者重新登录,因此运行定期备份。要立即删除一个离职的开发者而不是等待保留,直接运行 `DELETE FROM principal_emails WHERE principal = '<sub>'`;这移除了唯一持有其电子邮件、名称和组的表。`spend` 和 `admin_audit` 行仅引用伪匿名 OIDC `sub`。
197 197
218| 数据 | 路径 | 由网关发送给 Anthropic |218| 数据 | 路径 | 由网关发送给 Anthropic |
219| ----------------------------------------------------------------------- | -------------------------------------- | ------------------------ |219| ----------------------------------------------------------------------- | -------------------------------------- | ------------------------ |
220| 推理(提示、完成) | CLI → 网关 → 您的上游 | 仅当 Anthropic API 是配置的上游时 |220| 推理(提示、完成) | CLI → 网关 → 您的上游 | 仅当 Anthropic API 是配置的上游时 |
221221| 遥测(OTLP 指标,加上 [选择加入日志和跟踪](/zh-CN/claude-apps-gateway-config#telemetry)) | CLI → 网关 → 您的收集器 | 从不 || 遥测(OTLP 指标,加上 [选择加入日志和跟踪](/docs/zh-CN/claude-apps-gateway-config#telemetry)) | CLI → 网关 → 您的收集器 | 从不 |
222| 身份(电子邮件、组、sub) | IdP → 网关 → JWT → CLI;CLI 在 OTLP 导出上标记它 | 从不 |222| 身份(电子邮件、组、sub) | IdP → 网关 → JWT → CLI;CLI 在 OTLP 导出上标记它 | 从不 |
223| 托管设置 | 您的网关 YAML → CLI | 从不 |223| 托管设置 | 您的网关 YAML → CLI | 从不 |
224| 审计日志 | 网关 stderr → 您的聚合器 | 从不 |224| 审计日志 | 网关 stderr → 您的聚合器 | 从不 |
237 237
238两个威胁超出范围,因为它们是您的基础设施来保护:238两个威胁超出范围,因为它们是您的基础设施来保护:
239 239
240240* **受损的网关主机**:主机既持有上游凭证,又向每个连接的开发者分发 [托管设置](/zh-CN/claude-apps-gateway-config#managed),因此对网关配置的控制与对您的 MDM 的控制相当。CLI 的一次性批准对话框用于 shell 能力设置限制无声更改,但不替代主机安全。* **受损的网关主机**:主机既持有上游凭证,又向每个连接的开发者分发 [托管设置](/docs/zh-CN/claude-apps-gateway-config#managed),因此对网关配置的控制与对您的 MDM 的控制相当。CLI 的一次性批准对话框用于 shell 能力设置限制无声更改,但不替代主机安全。
241* **恶意 OIDC 提供商**:提供商签署网关信任的 id\_tokens,因此它可以声称任何身份。审查和保护您的 IdP 是您的责任。241* **恶意 OIDC 提供商**:提供商签署网关信任的 id\_tokens,因此它可以声称任何身份。审查和保护您的 IdP 是您的责任。
242 242
243<h3 id="user-code-brute-force-resistance">243<h3 id="user-code-brute-force-resistance">
246 246
247开发者在 `/device` 验证页面中输入的 `user_code` 是从 20 字符字母表中抽取的 8 个字符,产生 20⁸ 或约 2.56×10¹⁰ 个组合,在 10 分钟后过期。247开发者在 `/device` 验证页面中输入的 `user_code` 是从 20 字符字母表中抽取的 8 个字符,产生 20⁸ 或约 2.56×10¹⁰ 个组合,在 10 分钟后过期。
248 248
249249网关在设备授权端点上应用按 IP 速率限制,可通过 [`rate_limits`](/zh-CN/claude-apps-gateway-config#http-tuning) 配置。如果许多开发者从单个共享公司 NAT 地址登录,提高限制。限制仅适用于登录流,不适用于推理。网关在设备授权端点上应用按 IP 速率限制,可通过 [`rate_limits`](/docs/zh-CN/claude-apps-gateway-config#http-tuning) 配置。如果许多开发者从单个共享公司 NAT 地址登录,提高限制。限制仅适用于登录流,不适用于推理。
250 250
251<h3 id="compliance-posture">251<h3 id="compliance-posture">
252 合规性态势252 合规性态势
255* **数据驻留**:网关自己的数据平面除非 Anthropic API 是配置的上游,否则不向 Anthropic 发送任何内容;当它是时,您现有的数据处理协议适用于推理路径。遥测、审计、身份和设置仅去往您配置的目的地。255* **数据驻留**:网关自己的数据平面除非 Anthropic API 是配置的上游,否则不向 Anthropic 发送任何内容;当它是时,您现有的数据处理协议适用于推理路径。遥测、审计、身份和设置仅去往您配置的目的地。
256* **主机进程流量**:主机进程是 Claude Code CLI,它可以向 Anthropic 发送启动分析和更新检查。对于严格出口部署,在网关的容器环境中设置 `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`。256* **主机进程流量**:主机进程是 Claude Code CLI,它可以向 Anthropic 发送启动分析和更新检查。对于严格出口部署,在网关的容器环境中设置 `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1`。
257* **客户端分析**:CLI 在登录到网关时禁用自己的使用分析,错误报告在第三方 API 表面上默认关闭。257* **客户端分析**:CLI 在登录到网关时禁用自己的使用分析,错误报告在第三方 API 表面上默认关闭。
258258* **客户端机器**:开发者的 CLI 仍然向 Anthropic 发送 WebFetch 主机名检查和版本检查,除非设置了 `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` 和 `skipWebFetchPreflight: true`。请参阅 [数据使用](/zh-CN/data-usage)。* **客户端机器**:开发者的 CLI 仍然向 Anthropic 发送 WebFetch 主机名检查和版本检查,除非设置了 `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1` 和 `skipWebFetchPreflight: true`。请参阅 [数据使用](/docs/zh-CN/data-usage)。
259* **调查评分**:网关凭证禁用 Anthropic 绑定的评分接收器,因此评分不发送给 Anthropic。259* **调查评分**:网关凭证禁用 Anthropic 绑定的评分接收器,因此评分不发送给 Anthropic。
260* **成绩单共享**:在调查的成绩单共享提示上选择"是"会在 `~/.claude/feedback-bundles/` 下写入本地文件,而不是上传到 Anthropic。260* **成绩单共享**:在调查的成绩单共享提示上选择"是"会在 `~/.claude/feedback-bundles/` 下写入本地文件,而不是上传到 Anthropic。
261* **客户端更新**:更新检查与网关流量分开。通过您自己的分发固定版本,如果笔记本电脑不得获取版本,设置 `DISABLE_UPDATES`。`DISABLE_AUTOUPDATER` 仅停止后台更新,而 `claude update` 仍然有效。261* **客户端更新**:更新检查与网关流量分开。通过您自己的分发固定版本,如果笔记本电脑不得获取版本,设置 `DISABLE_UPDATES`。`DISABLE_AUTOUPDATER` 仅停止后台更新,而 `claude update` 仍然有效。
262* **TLS**:在生产中通过 HTTPS 提供 `public_url`,要么从网关自己的监听器通过 `listen.tls`,要么从 TLS 终止入口在普通 HTTP 副本前面,设置 `listen.public_url`。网关不拒绝普通 HTTP。IdP 必须在生产中提供 HTTPS,Postgres 支持 `?sslmode=require`。在您的入口处设置 `Strict-Transport-Security`。262* **TLS**:在生产中通过 HTTPS 提供 `public_url`,要么从网关自己的监听器通过 `listen.tls`,要么从 TLS 终止入口在普通 HTTP 副本前面,设置 `listen.public_url`。网关不拒绝普通 HTTP。IdP 必须在生产中提供 HTTPS,Postgres 支持 `?sslmode=require`。在您的入口处设置 `Strict-Transport-Security`。
263263* **漏洞披露**:遵循 [报告安全问题](/zh-CN/security#reporting-security-issues)* **漏洞披露**:遵循 [报告安全问题](/docs/zh-CN/security#reporting-security-issues)
264 264
265<h2 id="troubleshooting">265<h2 id="troubleshooting">
266 故障排除266 故障排除
272* **登录问题**:开发者运行 `claude --debug-file ./claude-debug.txt`,重现,并发送该文件加上相同窗口的网关审计日志272* **登录问题**:开发者运行 `claude --debug-file ./claude-debug.txt`,重现,并发送该文件加上相同窗口的网关审计日志
273* **推理问题**:请求的模型、配置的上游和请求的网关审计日志,记录哪个上游提供了它和响应状态273* **推理问题**:请求的模型、配置的上游和请求的网关审计日志,记录哪个上游提供了它和响应状态
274 274
275网关的 stderr 包含审计事件流,审计日志记录开发者身份,调试文件记录来自开发者机器的 hook 和 MCP 服务器输出。在发布到公开问题前,请审查并隐去这些信息。
276
275| 症状 | 原因 | 修复 |277| 症状 | 原因 | 修复 |
276| ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |278| ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
277279| 开发者的 `/login` 显示标准账户选择器而不是 **Cloud gateway** 屏幕 | `forceLoginMethod` 或 `forceLoginGatewayUrl` 未在该机器的托管设置中设置 | 将 [托管设置文件](/zh-CN/claude-apps-gateway#set-the-gateway-url) 部署到设备;`/login` 从那里读取网关 URL || 开发者的 `/login` 显示标准账户选择器而不是 **Cloud gateway** 屏幕 | `forceLoginMethod` 或 `forceLoginGatewayUrl` 未在该机器的托管设置中设置 | 将 [托管设置文件](/docs/zh-CN/claude-apps-gateway#set-the-gateway-url) 部署到设备;`/login` 从那里读取网关 URL |
278| 启动显示 `Gateway login is configured in managed settings, but this Claude Code build does not include Cloud gateway support.` | 安装的 Claude Code 构建早于网关支持 | 让开发者更新 Claude Code 到包括 Cloud gateway 支持的版本 |280| 启动显示 `Gateway login is configured in managed settings, but this Claude Code build does not include Cloud gateway support.` | 安装的 Claude Code 构建早于网关支持 | 让开发者更新 Claude Code 到包括 Cloud gateway 支持的版本 |
279281| CLI `/login`:`Gateway hosts must be on your organization's private network; <host> resolves to the public (or unrecognized) address <ip>` | 网关主机名解析为至少一个公共 IP 地址。Claude Code 检查每个解析的地址,需要每一个都是私有的。常见原因是一个双栈名称,其中一个族解析为公共地址,包括 AWS 内部双栈负载均衡器,它们返回公共范围 AAAA 地址。Anthropic 运营的公共网关端点免于检查,`/login` 通过 `https://` 接受它们。在 v2.1.206 之前,`/login` 拒绝它们,就像任何其他公共地址一样 | 让网关名称在开发者机器上仅解析为私有地址。对于双栈名称,删除公共范围记录或提供单独的仅内部 DNS 名称。请参阅 [私有网络先决条件](/zh-CN/claude-apps-gateway#prerequisites)。 || CLI `/login`:`Gateway hosts must be on your organization's private network; <host> resolves to the public (or unrecognized) address <ip>` | 网关主机名解析为至少一个公共 IP 地址。Claude Code 检查每个解析的地址,需要每一个都是私有的。常见原因是一个双栈名称,其中一个族解析为公共地址,包括 AWS 内部双栈负载均衡器,它们返回公共范围 AAAA 地址。Anthropic 运营的公共网关端点免于检查,`/login` 通过 `https://` 接受它们。在 v2.1.206 之前,`/login` 拒绝它们,就像任何其他公共地址一样 | 让网关名称在开发者机器上仅解析为私有地址。对于双栈名称,删除公共范围记录或提供单独的仅内部 DNS 名称。请参阅 [私有网络先决条件](/docs/zh-CN/claude-apps-gateway#prerequisites)。 |
280| CLI `/login`:`Gateway login requires a direct connection and does not support connecting through an HTTP proxy` | `HTTPS_PROXY` 或 `HTTP_PROXY` 适用于网关主机,代理的主机名解析为公共地址。代理的主机解析为仅私有地址是允许的,不会触发此错误 | 在开发者的机器上将网关主机添加到 `NO_PROXY`,以便连接是直接的,或使用主机名解析为私有地址的代理 |282| CLI `/login`:`Gateway login requires a direct connection and does not support connecting through an HTTP proxy` | `HTTPS_PROXY` 或 `HTTP_PROXY` 适用于网关主机,代理的主机名解析为公共地址。代理的主机解析为仅私有地址是允许的,不会触发此错误 | 在开发者的机器上将网关主机添加到 `NO_PROXY`,以便连接是直接的,或使用主机名解析为私有地址的代理 |
281| CLI `/login`:`Could not resolve gateway host <host>` | 机器无法解析网关的内部 DNS 名称,通常是因为它不在公司网络上 | 让开发者连接到您的网络或 VPN,然后重试 `/login` |283| CLI `/login`:`Could not resolve gateway host <host>` | 机器无法解析网关的内部 DNS 名称,通常是因为它不在公司网络上 | 让开发者连接到您的网络或 VPN,然后重试 `/login` |
282| 启动退出,配置验证错误命名 `store.postgres_url` | 未配置 Postgres;网关需要 Postgres | 设置 `store.postgres_url`。对于本地开发,使用一次性容器:`docker run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres`。 |284| 启动退出,配置验证错误命名 `store.postgres_url` | 未配置 Postgres;网关需要 Postgres | 设置 `store.postgres_url`。对于本地开发,使用一次性容器:`docker run --rm -p 5432:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres`。 |
283285| 启动退出:`requires the native binary` | 在 Node 下运行而不是本机二进制文件 | 使用 [独立安装方法](/zh-CN/setup) 之一安装 Claude Code || 启动退出:`requires the native binary` | 在 Node 下运行而不是本机二进制文件 | 使用 [独立安装方法](/docs/zh-CN/setup) 之一安装 Claude Code |
284| 启动退出,OIDC 发现错误在 `config.load` 之后 | `oidc.issuer` 无法到达,或 TLS 链不受信任 | 检查发行者是否可从 pod 到达并提供 `/.well-known/openid-configuration`。为私有 PKI 设置 `ca_cert_pem`。 |286| 启动退出,OIDC 发现错误在 `config.load` 之后 | `oidc.issuer` 无法到达,或 TLS 链不受信任 | 检查发行者是否可从 pod 到达并提供 `/.well-known/openid-configuration`。为私有 PKI 设置 `ca_cert_pem`。 |
285| 启动退出,Postgres 权限错误 | 应用角色缺少 `CREATE TABLE` | 使用管理员角色预先创建架构,并授予应用角色 DML,或临时授予 DDL 用于应用新迁移的启动 |287| 启动退出,Postgres 权限错误 | 应用角色缺少 `CREATE TABLE` | 使用管理员角色预先创建架构,并授予应用角色 DML,或临时授予 DDL 用于应用新迁移的启动 |
286| `/oauth/callback` 显示"Sign-in could not be completed" | 电子邮件域被拒绝,id\_token 验证失败,或 `email_verified` 明确为 `false`,网关总是拒绝,没有覆盖 | 检查 `allowed_email_domains` 和 IdP 返回验证的 `email` 声明。对于 `email_verified: false`,修复 IdP 端验证。如果您的 IdP 在不同的声明名称下发出电子邮件,设置 `oidc.email_claim`。 |288| `/oauth/callback` 显示"Sign-in could not be completed" | 电子邮件域被拒绝,id\_token 验证失败,或 `email_verified` 明确为 `false`,网关总是拒绝,没有覆盖 | 检查 `allowed_email_domains` 和 IdP 返回验证的 `email` 声明。对于 `email_verified: false`,修复 IdP 端验证。如果您的 IdP 在不同的声明名称下发出电子邮件,设置 `oidc.email_claim`。 |
293| 登录在 IdP 处完成,但回调失败,Chrome 中出现 CSP 错误或 Safari 中出现"this sign-in link has expired" | IdP 通过 `response_mode=form_post` 返回代码,它通过 POST 自动提交到 `/oauth/callback`。Chrome 在严格 CSP 下阻止它;Safari 允许提交,但回调仅读取查询字符串。 | 确保您的 IdP 遵守 `response_mode=query`,网关明确请求它,以便回调是普通重定向 |295| 登录在 IdP 处完成,但回调失败,Chrome 中出现 CSP 错误或 Safari 中出现"this sign-in link has expired" | IdP 通过 `response_mode=form_post` 返回代码,它通过 POST 自动提交到 `/oauth/callback`。Chrome 在严格 CSP 下阻止它;Safari 允许提交,但回调仅读取查询字符串。 | 确保您的 IdP 遵守 `response_mode=query`,网关明确请求它,以便回调是普通重定向 |
294| 登录在本地工作,但在 ALB 后面失败 | `public_url` 未设置,因此 IdP 获取内部 `http://` 源作为 `redirect_uri` | 将 `listen.public_url` 设置为外部 `https://` 源 |296| 登录在本地工作,但在 ALB 后面失败 | `public_url` 未设置,因此 IdP 获取内部 `http://` 源作为 `redirect_uri` | 将 `listen.public_url` 设置为外部 `https://` 源 |
295| 开发者重复看到信任提示 | TLS 证书每个副本或每个请求轮换 | 在入口处使用稳定的证书,或终止 TLS 一次并在内部通过普通 HTTP 运行副本 |297| 开发者重复看到信任提示 | TLS 证书每个副本或每个请求轮换 | 在入口处使用稳定的证书,或终止 TLS 一次并在内部通过普通 HTTP 运行副本 |
296298| CLI `/login`:`"Could not verify the gateway's TLS certificate"` 或 `SELF_SIGNED_CERT_IN_CHAIN` | 网关的 TLS 链由 CLI 主机的信任存储中不存在的私有 CA 签署 | Claude Code 默认在本机二进制文件上读取 OS 信任存储,在 Node 22.15 或更高版本上;[`CLAUDE_CODE_CERT_STORE`](/zh-CN/network-config#ca-certificate-store) 控制此行为。如果 CA 安装在 OS 信任存储中,确保开发者在当前运行时上。否则在启动前将 `NODE_EXTRA_CA_CERTS` 设置为 CA 证书 PEM。首次连接指纹提示仍然适用。 || CLI `/login`:`"Could not verify the gateway's TLS certificate"` 或 `SELF_SIGNED_CERT_IN_CHAIN` | 网关的 TLS 链由 CLI 主机的信任存储中不存在的私有 CA 签署 | Claude Code 默认在本机二进制文件上读取 OS 信任存储,在 Node 22.15 或更高版本上;[`CLAUDE_CODE_CERT_STORE`](/docs/zh-CN/network-config#ca-certificate-store) 控制此行为。如果 CA 安装在 OS 信任存储中,确保开发者在当前运行时上。否则在启动前将 `NODE_EXTRA_CA_CERTS` 设置为 CA 证书 PEM。首次连接指纹提示仍然适用。 |
297 299
298<h2 id="related">300<h2 id="related">
299 相关301 相关
300</h2>302</h2>
301 303
302304* [Claude 应用网关概述](/zh-CN/claude-apps-gateway):快速入门和开发者连接* [Claude 应用网关概述](/docs/zh-CN/claude-apps-gateway):快速入门和开发者连接
303305* [配置参考](/zh-CN/claude-apps-gateway-config):每个 `gateway.yaml` 选项* [配置参考](/docs/zh-CN/claude-apps-gateway-config):每个 `gateway.yaml` 选项