本文根据 Naveen Gopalakrishna 发表于 Microsoft Foundry Blog 的工程指南整理,原文发布日期为 2026 年 11 月 3 日。

企业接入 Claude Code 时,还要管理登录身份、可用模型、预算和私有网络。Naveen 开发的 Claude Code on Foundry(CCOF)处理的就是这些问题。据原作者介绍,这套架构已在多家企业上线;代码公开在 CCOF 仓库,但它不是微软产品。

接入时,先部署环境、验证一名用户,再考虑扩大范围。文中配图来自作者记录的实验室运行,名称和标识符已替换或遮蔽,并非客户生产环境。已有企业部署经验不能代替具体工作负载的容量验证。

1. 开发者和管理员分别能做什么

开发者 管理员
在 Claude Code 中使用组织批准的模型 接入已有的 Entra 安全组
通过 Microsoft Entra 登录,不共享 Foundry 密钥 设置模型、个人预算和 token 限制
使用 Claude Code CLI 和 Claude Code 的 VS Code 扩展 为每个组分配成本代码,为成员添加成本分摊标签
通过安装的用量技能查看自己的 CCOF 预算 按组、开发者和模型查看费用
启用可选的预算状态栏 导出用量报表,使用 Azure Monitor 工作簿
在 Windows 上使用受支持且经过构建版本检查的 Claude Desktop 配置 让后端保持私有访问,并在适合时复用已有 APIM

访问权限来自组成员身份。客户端配置文件本身不会授予访问权限。

CCOF 管理控制台中的两个组

图 1:实验室运行中的组管理控制台。组标识符和资源名称均已替换,并非客户目录。

2. 架构:统一网关,各组件各司其职

CCOF 主备架构:Central India 主栈、South India Cosmos 读取区域及两个 Foundry 账户

图 2:这套设计的 CCOF 栈位于单一区域,APIM 和 Functions 采用可用区冗余,存储采用 ZRS,Foundry 账户采用主备配置。图中的 Cosmos 在两个区域都未启用可用区冗余;是否开启,需要单独评估容量和部署条件。

组件 职责
API Management 验证调用方 token,执行准入和 token 限制,将请求路由到获准的 Foundry 后端
Resolver Function App 读取调用方的授权和预算,返回所属组、精确的模型权限及后端 ID
Sync Function App 读取 Entra 组的直接成员,更新 Cosmos 中的授权投影数据
Reconciler Function App 按计划读取用量,写入预算状态
Admin Function App 提供组接入、配置和报表功能
Cosmos DB 存储组、授权、预算状态,以及可选的每日成本分摊历史
Log Analytics 和 Application Insights 记录请求与计量遥测,以及运行日志
Storage 存储 Function 程序包和可选的网关日志归档
Microsoft Foundry 托管 Claude 部署

Resolver 不面向开发者开放,它接受网关的托管身份。APIM 调用 Foundry 时也使用自己的托管身份,并在账户作用域内获得 Cognitive Services User 角色。这是该实现当前使用的 Azure 内置 RBAC 角色名称。

正常请求按以下路径流转:

  1. 用户登录 Entra,辅助程序向 Claude Code 提供用于网关的短期 token。
  2. APIM 验证租户、受众(audience)、客户端应用和委托作用域(delegated scope)。
  3. 缓存未命中时,APIM 调用 Resolver,确定获准访问的组和模型。
  4. APIM 应用已配置的个人、组限制,并将请求转发给 Foundry。
  5. 用量遥测记录个人、组、模型和成本归属,后台对账更新预算。

允许访问的结果默认缓存 120 秒,时长可调整。

属于多个组的用户,可以通过 x-ccof-project 指定组的 Object ID。不指定时,配置的规则会先选本月已记录支出最多的组;再比较优先级数值,数值较小的优先。

详细设计见架构与信任边界。

3. 准备 Azure 和 Entra 前置条件

部署前,先与平台、网络和 Entra 负责人确认这些条件:

  • Azure 订阅、资源组和区域。
  • APIM 层级、网络访问方式和容量。私有后端必须有可达的私有网络路径。
  • 主、备 Foundry 部署、精确的部署名称及推理所在的地理范围。
  • 如需启用 Cosmos 可用区冗余,确认对应容量,并准备试点所需的吞吐量。
  • 子网委派、DNS、路由和出站访问。
  • 已有 Entra 组的 Object ID、测试成员和预算。
  • 谁有权创建 Azure 角色分配,以及授予 Microsoft Graph 应用程序权限。

如果只自动同步用户,同步身份需要 GroupMember.Read.All,并通过 User.Read.All 读取用户的启用、禁用状态。这些 Microsoft Graph 应用程序权限应授予 Function App 的托管身份,不授予开发者。

如果组成员包含服务主体,还需另行评估权限。

管理端要搜索组、读取名称,也得单独申请相应的 Graph 读取权限。托管身份获得新权限后,缓存的 token 可能过几小时才会更新,所以最好在上线窗口前完成授权。

私有 IP 放在 DNS 中,不要写进后端 URL

后端地址使用账户的主机名:

1
https://<foundry-account>.services.ai.azure.com/anthropic

私有 DNS 将其解析为私有终结点 IP。如果把主机名替换成 https://10.x.x.x,就会破坏基于主机名的 TLS 验证;CCOF 还要求备用主机名符合预期。

私有 DNS 区域是全局资源,多部署一个 Foundry 区域,无需再建一套同名 DNS 区域。要检查的是 APIM 所在网络使用哪个 DNS 区域解析,以及能否访问解析出的 IP。网络对等互连本身不提供 DNS 转发。

Azure 门户中的 Cosmos 账户、私有终结点和网络接口

图 3:早期 East US 2 实验室的 Azure 门户局部截图,资源名称和订阅信息均已替换。账户、SQL 私有终结点和 NIC 是独立资源;服务本身并不位于终结点子网内。

Azure 门户中的 APIM 入站和出站网络配置

图 4:早期实验室允许 APIM 公网入站,并启用了出站 VNet 集成。生产网关也可以使用私有入站访问,但这需要负责人另行决定,截图本身没有验证这种配置。

如果关闭 APIM 公网访问,验收测试机器和开发者机器都需要能经由企业网络、VPN 或 VDI 访问网关,并使用私有 DNS。操作人员可以从互联网通过 ARM 部署资源,却仍可能无法调用私有网关。

4. 分阶段部署

部署日操作手册给出了执行顺序和预期输出,配置指南解释各项选择。

阶段 工作
0 只读预检:检查订阅、资源提供程序、HA 支持、模型部署和已有 APIM
1 创建资源并验证配置
2 创建 Cosmos 数据库和容器
3 分配并验证运行时 Azure/Cosmos 角色
4 创建或复用 Entra 应用注册和组
5 应用程序设置、APIM 策略与后端、遥测配置
6 创建或验证配置中的私有网络路径
7 发布代码、写入初始数据、加载成员并导出客户端配置
8 测试身份验证、允许及拒绝访问的模型,以及用量计量

在检出的仓库中,使用 PowerShell 7 执行:

1
2
3
4
5
6
7
$cfg = Join-Path $HOME 'ccof-private/staged.config.json'
$run = Join-Path (Get-Location) 'infra/staged/Invoke-StagedDeployment.ps1'
pwsh -File $run -Stage 0 -ConfigPath $cfg

# Preview, review, then apply one stage at a time.
pwsh -File $run -Stage 1 -ConfigPath $cfg
pwsh -File $run -Stage 1 -ConfigPath $cfg -Apply

前一阶段验证通过后,再执行下一阶段,直至 Stage 8。配置文件和保存的状态要放在一起。Stage 1 只创建资源,HA 选项必须在这一阶段成功执行前定下来。

复用 APIM 会保留其网络配置、容量单元和已有 API。为 CCOF 选择未占用的名称,例如 apiId: ccof-claude-messages、apiPath: ccof 和后端 ID ccof-foundry。

已有的全局策略仍然生效。服务级诊断可能连其他 API 一起覆盖,应与负责人确认诊断范围和成本。

前置条件就绪后,操作手册建议预留 2–3 小时。作者一次演练的记录是:

  • 接入两个组并完成带价格计量的 API 验证:约 2 小时 12 分钟。
  • 收到第一条真实 Claude Code 回复:约 2 小时 28 分钟。

完整演练和证据整理耗时更长。这些记录不保证实际安装时长。

5. 接入一个 Entra 组

在管理控制台中打开 Groups → Onboard:

  1. 查找已获批准的现有组,或输入其 Object ID。
  2. 设置每人每月预算,并决定是否为整个组设置总额上限。
  3. 选择允许的模型、后端和限制。
  4. 审查方案并提交。

管理控制台中的组预算设置

图 5:实验室的组配置。1 美元的小额预算用于测试,不是推荐的开发者额度。

预算、token 配额和提供方容量要分开考虑。全组每天 200 万 token,听起来不少,但分给 2,000 人,平均每人只有 1,000 token。组限制应按实际人数和用量来设,演示值不能直接照搬。

启用自动同步后,把测试用户加入 Entra 组,再确认同步确实成功。定时器显示 Enabled 还不够,成员数据必须已经写入 Cosmos 的授权投影。

6. 配置 Claude Code 和 CLI

Stage 7 会导出客户端配置。通过组织批准的渠道分发这个文件,绝不要分发用户 token 或 Azure 登录缓存。

Windows

开发者在检出的仓库中执行:

1
2
3
4
npm ci --prefix .\client --no-audit --no-fund
$env:CCOF_CONFIG_FILE = (Resolve-Path '<client-config.json>').Path
pwsh -NoProfile -File .\scripts\client\Set-ClaudeCodeGateway.ps1 -ConfigPath $env:CCOF_CONFIG_FILE -Confirmed -UsageStatusLine
& "$env:USERPROFILE\.claude\ccof-token.cmd" login

最后一行适用于使用 Azure CLI 登录的配置;实际操作请以安装程序打印的完整登录命令为准。

macOS

CCOF 在 macOS 上配置 Claude Code 时使用 signInMethod: azure-cli。安装 Azure CLI 和 PowerShell 7 后执行:

1
2
3
4
5
npm ci --prefix ./client --no-audit --no-fund
New-Item -ItemType Directory -Force ~/.config/ClaudeGateway | Out-Null
Copy-Item '<client-config.json>' ~/.config/ClaudeGateway/config.json
pwsh -NoProfile -File ./scripts/client/Set-ClaudeCodeGateway.ps1 -Confirmed -UsageStatusLine
& "$HOME/.claude/ccof-token" login

辅助程序在客户端配置旁使用独立的 Azure CLI 配置目录。它把 token 提供给 Claude Code,但不会将 token 写进设置文件。

主要的非敏感设置如下。部署名称只是示例,必须与 Foundry 中的实际名称完全一致:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "apiKeyHelper": "'/Users/alex/.claude/ccof-token' token",
  "model": "claude-sonnet-5",
  "env": {
    "ANTHROPIC_BASE_URL": "https://ccof-sample.azure-api.net/ccof",
    "ANTHROPIC_MODEL": "claude-sonnet-5",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-5",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-haiku-4-5",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-5-5",
    "CLAUDE_CODE_API_KEY_HELPER_TTL_MS": "240000"
  }
}

安装脚本做的事比这段配置多:它还会处理提供方变量冲突、各用户的配置、模型列表,以及可选的用量集成。其他设置会保留,最终仍以托管策略为准。

通过网关收到真实回复的 Claude Code CLI 记录

图 6:实验室中的一次真实 CLI 请求返回了 OK。截图中的客户端构建版本同时警告:本地模型目录不识别该部署。应使用与部署模型匹配的客户端版本和模型映射,不要隐藏兼容性警告。

配置完成后,在 Claude Code 交互界面发送一条简短提示,用 /model 试选一个获准模型,检查连接是否正确。个人预算可以通过安装的 CCOF 用量技能查询。不过,部分 Claude Code 构建版本也内置了 /usage,要分清实际调用的是哪一个命令。

CCOF 用量辅助程序与预算状态栏

图 7:辅助程序和状态栏的运行记录,标识符已替换。截图明确标注计价不完整及报表延迟,并非原生 Desktop 对话。

VS Code 中的 Claude Code

安装程序会写入扩展的非敏感环境设置,并在使用外部管理的身份验证时关闭托管登录提示。

重新加载 VS Code 窗口,在 Claude Code 面板发起请求。核对当前网关和模型,再到成本分摊记录中找到这次请求;仅打开扩展还不能确认路由。

7. Claude Desktop 需要单独配置

仓库提供的 Desktop 安装程序支持 Windows,会检查已安装构建版本的配置 schema:

1
pwsh -NoProfile -File .\scripts\client\Set-ClaudeDesktopGateway.ps1 -ConfigPath $env:CCOF_CONFIG_FILE -Confirmed

根据受支持的构建版本和登录方式,安装程序选择兼容的辅助脚本或外部身份提供方配置。它不会绕过托管推理策略。这与给 CLI 设置 ANTHROPIC_BASE_URL 不同。

Claude Desktop 网关配置片段示例

图 8:由 CCOF 的 Desktop 配置构建器生成的示例,并非一次成功 Desktop 聊天的截图。辅助脚本凭据类型取决于客户端构建版本,请使用安装脚本的 schema 检查。

完全退出并重启 Desktop,检查当前版本支持的连接与配置设置。选中网关配置,发送一条简短提示,再到 CCOF 遥测中核对。

原作者的可复用操作手册证据中,没有经过验证的原生 Desktop 成功对话。图中的配置示例不能证明聊天已经跑通。仓库安装程序也不支持 macOS Desktop。

兼容性说明见客户端配置文档。

8. 验证用户的实际访问路径

在用户机器上接入所需网络、完成登录后执行:

1
pwsh -NoProfile -File ./scripts/client/Test-ClientGatewayAccess.ps1 -Confirmed

脚本会检查生成的 token 辅助程序,向网关发送小请求,并运行已安装的 Claude Code CLI。通过测试需要同时满足两个条件:

  • gateway_result 中的 httpStatus: 200。
  • claude_code_result 中的 ok: true。

返回 not_installed 表示没有完成 Claude Code 测试。

结果 优先检查
APIM 响应提示已禁用公网访问 VPN/VDI 路径和私有 DNS
401 登录状态,以及网关 token 的 audience/scope
403 组准入、模型权限,或预算是否已耗尽
Foundry 429 提供方配额、容量,或网关配置的限制
后端故障 路由、DNS、终结点健康状态,以及账户作用域的托管身份角色

Reconciler 完成一次运行后,检查个人预算。在管理控制台中打开 Budgets → Snapshots → People 和 Chargeback → Developers。

预算快照和所选组的预算消耗情况

图 9:实验室中有两个组快照和两个人员快照。小额费用舍入后显示为 USD 0.00;不完整的金额仍标记为 partial,不会被当作完整账单。

管理控制台中的成本分摊报表

图 10:实验室中的组级成本分摊报表,可以按组、开发者、模型和时间段筛选。

用量一次最多导出 5,000 行,超过时会提示截断。要统计 25,000 人,就得用支持的筛选条件拆分报表请求,不能默认一个 CSV 已经包含所有人。控制台拿到批准的 Graph 权限后可以解析名称,用量导出中仍使用 Object ID。

控制台截图使用真实的实验室 API 数据,但显示值已替换为化名。截图中的 demo-editor 标签,是只读截图时替换登录配置产生的;后端仍使用获准的 Entra token 完成授权,并未开放匿名访问。

成员同步定时器是否正常运行

在客户的 CCOF Log Analytics 工作区运行:

FunctionAppLogs
| where TimeGenerated > ago(1h)
| where Message has "ccof.sync.run.v1"
| extend r = parse_json(substring(Message, indexof(Message, "{")))
| project TimeGenerated, outcome=tostring(r.outcome),
          membersAdmitted=tolong(r.counts.membersAdmitted),
          writeFailures=tolong(r.counts.writeFailures),
          reasons=tostring(r.reasons)
| order by TimeGenerated desc
| take 10

检查最近是否有 succeeded 记录、成员数量是否符合预期,并查清所有写入失败。遇到 graph_permission_missing 时,缺的是同步身份上的 Graph 授权,不是开发者应用注册的权限。

9. 高可用与扩展限制

架构图中的不同设计应对不同故障:

  • 可用区冗余的 APIM 和 Functions 应对可用区故障,但要考虑容量,以及始终就绪计算资源的成本。
  • 第二个 Cosmos 区域有助于保持注册数据可用。可用区设置和服务容量仍需单独评估。
  • 当配置的断路器开启时,Foundry 优先级池可以选择备用后端。

同一订阅中的 Foundry 账户共享模型配额池。增加一个账户不会增加配额。需要规划模型匹配和备用容量;不同订阅可以隔离配额。

APIM v2 和 Function Apps 仍只部署在一个区域。Central India 一旦故障,即使 Cosmos 和备用 Foundry 账户还在运行,服务也可能中断。这套设计没有提供网关自动跨区域恢复。

扩大使用范围前,先做试点:检查模型请求能否成功、真实流式请求的表现,再测网关 CPU、Cosmos 限流、同步耗时,以及对账数据是否及时更新。maxStates 这类行数保护阈值不能当成吞吐量承诺。容量规划指南也把实验室测量值和工作负载估算分开列出。

预算不是严格的账单上限。对账有延迟,网关实时账本也无法识别流式请求中的提示缓存 token 分类。即使 Reconciler 正常运行,缺失的分类也补不回来。

界面显示的费用只能当作支出下限,仍要另行核对实际账单。

操作手册与参考资料

部署 CCOF 会产生 Azure 资源费用。使用代码和操作手册前,仍需完成组织要求的安全、网络和容量审查。文中的截图记录了作者做过的检查,不能代替对自己环境的验证。