只要跟正在把 Microsoft Foundry 往生产环境搬的企业团队聊过,我几乎都会听到同一条底线:智能体不能跑在公网上。它一旦碰到专有数据、内部 API 或者受监管的负载,安全团队就要求把它塞进公司自己的虚拟网络里,藏在专用终结点、中心防火墙和受控 DNS 后面。这种拓扑,也就是一个 Foundry Standard 智能体被注入到 自带(BYO)VNet 里,正是大多数大型组织真正推到生产的形态。也恰恰是在这里,很多团队的首次部署悄无声息地卡住了。

卡住的原因有点反直觉。部署智能体本身,说到底不过是一份 Bicep 或 Terraform 模板,是轻松的那 20%。真正难啃的 80%,是你在运行模板之前就得定下来的网络设计。而且它有两个模板不具备的特点,一点都不留情面。

第一,好几个选择是不可逆的。出站网络注入和智能体子网在部署后无法更改,子网也不能原地扩容。第一天选错了,等着你的是重新部署,而不是改个参数。第二,真正拖时间的是组织流程,不是技术。防火墙变更申请、从中心 IPAM 拿 IP、NSG 审批、中心辐射(hub-and-spoke)模型里 Private DNS 的归属,每一项都要几天到几周才能走完。等你部署到一半才发现少了个东西,你被卡住的地方是一张工单,不是一段模板。

我写这篇就是想帮你避开这个坑。它写给真正管地基的人:平台/着陆区架构师、网络安全团队,以及负责跑部署、作为第二读者的 AI 平台负责人。目标很朴素:让你走进第一次规划会议时,就已经清楚自己要申请哪些子网、CIDR、DNS 区域、NSG 规则和防火墙 FQDN。把子网布局、Private DNS 设计和防火墙放行清单这三件事定对了,模板就回归它本该有的样子,一道走过场的手续。

我每次跟企业聊 BYO VNet 里的 Foundry 标准智能体,开场几乎都是同一批问题。这些问题问得都对,而且每一个都是一次设计决策,不是排障步骤:

  • 我需要几个子网,每个长什么样?
  • 智能体子网该预留多大的 CIDR?
  • 中心防火墙上必须放行哪些 FQDN?
  • Private DNS 区域放在哪儿?
  • 第一次智能体调用之前,我怎么证明这一切都对?

下面几节把每个问题都当成一件你提前拍板的事来回答。

适用范围: Microsoft Foundry Standard 部署(account + project + capability host)注入到客户 VNet,可选用 API Management 打头,可选放在中心辐射架构的 Azure Firewall 后面并配中心 Private DNS。

这篇写给谁看?

读者 他们负责什么 从本文能拿到什么
云平台/着陆区架构师 子网、IPAM、Private DNS、中心辐射拓扑 要申请和预配的确切子网、CIDR 和 DNS 设计
网络安全负责人 NSG、Azure Firewall 策略、UDR 一次过审的防火墙放行清单和 NSG 规则集
AI 平台负责人/解决方案架构师 Foundry 部署本身 第一天就能交给网络团队的一份完整、精确的需求

怎么用这篇文章: 第 7 节的部署前检查清单才是交付物。1 到 6 节是每一个勾选项背后的推理,读一遍,之后就照着清单干活。

1. 所有组件放在同一个区域

平台层面并没有一条硬性要求,逼着 Foundry 标准部署的所有组件都待在同一个 Azure 区域。但一旦你把智能体运行时注入到自己的 VNet,把资源摊到跨区域会让你付出两样你并不想付的成本。

第一是跨区域数据传输费。如果 Foundry 在区域 A,而 Cosmos、Search、Storage 或你的模型终结点落在区域 B,每一次智能体调用都要穿过跨区域 VNet 对等,这部分按 GB 双向计费。把一切留在同一区域,流量就在本地兜圈,没有跨区域对等,没有按 GB 的数据传输账单,云开支也实打实地降下来。

第二是延迟。智能体的一次运行很"话痨":读线程、调工具、查向量、调模型。跨区域每一跳多加 40 到 100 毫秒,用户在面向自己的响应里立刻就能感觉到。

经验法则: Foundry account、project、capability host、模型部署、依赖存储(Cosmos、Storage、Search)、APIM(如果用)、VNet 以及跳板机,最好全部放在同一区域。配对区域只留给灾备,别拿来做第一天的架构。

2. 子网结构:动模板之前先把布局画出来

在你照抄下面这张表之前,你的 SKU 和着陆区会改变它的形状。 下面的布局是生产负载(Premium APIM 加一台跳板机)的推荐模式,但有两个选择会实质性地把子网加进来或去掉。

  • APIM SKU 决定你需要一个子网还是两个。 Standard v2 用 VNet 集成做出站,再用一个单独的专用终结点做入站,是两个各司其职的独立子网(apim-outbound-subnet 加上落在 pe-subnet 上的入站 PE)。Premium(经典版)支持完整的 VNet 注入,一个委托子网同时承载入站和出站,你拿到更高的吞吐、多区域、可用区,还少规划一个子网,代价是更高的价格。先选 SKU,子网数量随之而定。
  • 跳板机子网取决于着陆区。 如果你企业的着陆区已经让运维能直接看到 spoke,比如走 ExpressRoute 或站点到站点 VPN,那你这里根本不需要专门的 jumpbox-subnet。什么时候加?当你要接入合作方团队、远程外包,或者任何还没有到 VNet 私有路由、又需要一个受控入口做 nslookup / 门户验证的人。

我见得最多的错误,是把 VNet 当成一个扁平的大子网。Foundry Standard 加 APIM 有一批硬约束,会把你推向至少四个各有用途的子网:

子网 用途 委托 说明
agent-subnet Foundry capability-host 在这里为智能体运行时注入 NIC Microsoft.App/environments(必需) 里面不能有专用终结点,委托和 PE 的 NIC 无法共存
pe-subnet Cosmos、Storage、Search、Foundry account 以及 APIM 入站的专用终结点 PE 子网不能被委托
apim-outbound-subnet APIM VNet 集成,从 APIM 到私有后端的出口路径 Microsoft.Web/serverFarms(必需) 专属于单个 APIM 实例,不能共享
jumpbox-subnet 供 RDP/SSH 访问、nslookup 验证、私有门户浏览的 VM 跟 pe-subnet 分开放,NSG 姿态不同、UDR 需求不同,你也不想让 VM 频繁增删啃掉 PE 的地址空间

同一个 VNet 里还有别的负载怎么办? 上面这张表是 Foundry + APIM 的基线。如果你还在旁边托管别的东西,比如 MCP 服务器、自定义 API、后台 worker,给每一个单独一个子网。它不能共用 agent-subnet(专属于一个 Foundry account),也不能共用 pe-subnet(不能委托),它的委托取决于宿主:Container Apps 用 Microsoft.App/environments(跟 Foundry 的是不同的环境),Container Instances 用 Microsoft.ContainerInstance/containerGroups,带 VNet 集成的 App Service / Functions 用 Microsoft.Web/serverFarms,AKS 或纯 VM 则不委托。

推荐的 APIM 拓扑:Premium v2,入站走 PE、出站走集成

APIM 支持好几种网络模式。但对一个需要同时隔离入站网关对私有后端的出站调用的生产级 Foundry 部署,能给出最干净拓扑的模式是这样的:

  • SKU:API Management Premium v2。 Premium v2 给你可用区、更高吞吐、工作区、专用计算,以及最高的扩展上限,都是你希望一个坐在 Foundry 前面的 AI Gateway 在生产路径上具备的能力。Standard v2 支持同样的网络模型,但当这层 API 是一等的生产依赖时,你部署的应该是 Premium v2。
  • 入站 = pe-subnet 上的专用终结点。 针对 Microsoft.ApiManagement/service 的 Gateway 子资源为 APIM 建一个专用终结点。它会自动注册进 privatelink.azure-api.net,给你一个不需要任何子网委托的私有入站 IP。反正 PE 子网本来也不能委托,所以 APIM 的入站正好该落在这儿,跟你其他的 PE 挨着。
  • 出站 = VNet 集成进 apim-outbound-subnet。 启用 Premium v2 VNet 集成,让 APIM 对后端的调用从一个委托给 Microsoft.Web/serverFarms 的专用子网出去。从这里,APIM 经由各自的 PE 去够到 Foundry、Cosmos、内部 HR API 等等,流量全程不碰公网。

委托为什么重要:

  • agent-subnet 上的 Microsoft.App/environments 把子网正式交给 Foundry capability-host 所运行的 Container Apps 托管环境底座。委托授权平台代你在子网内预配和管理它自己的基础设施(NIC、负载均衡器、健康探针、必需的路由策略),并让这个子网专属于那个服务,PE、VM 和其他任何负载都不能共享它。没有这个委托,capabilityHosts 的 PUT 会在子网校验时失败。
  • APIM 出站子网上的 Microsoft.Web/serverFarms 是 Premium v2(或 Standard v2)VNet 集成必需的。这个子网是专用的,一个 APIM 实例独占它,不能跟任何其他 Azure 资源共享。另外记得在订阅里注册 Microsoft.Web 资源提供程序。
  • 委托不可互换:你没法以后把 agent-subnet 改成 PE 子网,因为一个子网不能同时托管委托服务专用终结点。而且按 Foundry 官方指引,出站网络注入在部署后无法更改,智能体子网要慎选,以后想挪它就意味着重新部署 Foundry。

智能体子网的容量。 Foundry 智能体服务网络文档对这点写得很明确:委托智能体子网的推荐大小是 /24(256 个地址),正是因为子网委托给了 Microsoft.App/environments,Container Apps 运行时在横向扩展时会吃掉 IP。/27 是 API 强制的硬下限,对更小的非生产部署够用,比如 PoC、开发测试,或者你清楚扩展上限的低流量内部智能体。把 /27 当成平台能接受的下界,而不是生产环境要部署的尺寸。

除此之外,你无法原地扩容子网,一旦用满,迁移是破坏性的。第一天就预配 /24,它不会让你多花一分钱,却能消除未来一整类扩容事故。

APIM 出站子网的容量。 Premium v2 VNet 集成要求最小 /27,推荐 /24 留横向扩展的余量,道理一样,宁可给得宽裕些。

3. 中心辐射加 Azure Firewall:写规则之前先把流量建模

如果你坐在一个中心化的 Azure Firewall 后面,还有一条 UDR 把 0.0.0.0/0 强行导过它,那运行时碰到的每一个主机名都得在你的应用规则集合里。部署之前,把流量分成两桶来建模会很有帮助。

第一桶是 VNet 内、服务到服务的流量:Foundry 运行时到 Cosmos / Storage / Search / 你的模型终结点 / APIM。因为你在每一个服务前面都部署了专用终结点,这类流量是出站到 VNet 内部的私有 IP,不是出站到公网 FQDN。它默认也不经过防火墙:Azure 为每个 PE 注入的 /32 系统路由优先级高于你的 0.0.0.0/0 UDR,所以 PE 流量直奔 PE 的 NIC。你的 NSG 规则应当反映这一点:放行 agent-subnet → pe-subnet 的 443,数据平面就搞定了,这一段不需要防火墙应用规则。

第二桶是出站到微软托管的控制平面 FQDN:Entra 令牌获取、托管标识、容器镜像拉取、评估遥测等等。防火墙应用规则集合真正要管的就是这一桶。

防火墙上要放行的源地址

  • agent-subnet,运行时几乎每一次控制平面调用都从这里发起。
  • jumpbox-subnet,如果你为了 nslookup、门户浏览和排障预配了专门的 jumpbox-subnet。

FQDN:从文档给的基线开始

Foundry 专用链接官方文档为带虚拟网络注入的 Foundry 发布了这份最小放行清单:

场景 FQDN / 服务标记 为什么
Agents *.identity.azure.netlogin.microsoftonline.com*.login.microsoftonline.com*.login.microsoft.com(或用 AzureActiveDirectory 服务标记) 承载智能体运行时的 Azure Container App 委托所必需,Entra + 托管标识
Evaluations & Traces AzureMachineLearning 服务标记、settings.sdk.monitor.azure.com 评估器目录,以及把结果送往 Application Insights。优先用服务标记而不是裸的 *.blob.core.windows.net 通配,它把出口范围收窄到 Foundry 真正需要的那几个微软托管存储终结点,而不是打开 Azure 里的每一个 blob 账户

先从这里起步。如果你的部署只是 Foundry + PE + 一个防火墙,这份清单通常就够了。

FQDN:实践中你多半还得补上的部分

如果你还在跑 APIM(Standard v2 出站集成)、拉容器镜像,或者端到端用 Application Insights,预计还要加上:

类别 FQDN 什么时候需要
Azure Resource Manager management.azure.com*.management.azure.com 运行时的 ARM 调用(读角色分配、资源元数据)
Microsoft Graph graph.microsoft.com 某些智能体场景里的目录 / 用户上下文
容器镜像拉取 mcr.microsoft.com*.data.mcr.microsoft.com*.azurecr.io cap-host 拉它的运行时镜像
APIM 内部遥测 *.prod.warm.ingest.monitor.core.windows.net*.prod.hot.ingest.monitor.core.windows.net*.prod.microsoftmetrics.comazureprofiler.trafficmanager.net 仅当防火墙 Deny 日志显示 APIM 出站子网在试图够 Geneva/监控终结点时。大多数 Premium v2 部署里这段留在微软骨干网上,根本不碰防火墙
Application Insights 摄取 *.in.applicationinsights.azure.com*.monitor.azure.com 如果你的应用或 APIM 往 App Insights 发遥测

有一点要说清楚:通配符是务实的起点,而 premium SKU 上的 PE 才是给受监管、高敏感环境的加固手段,在那种环境里防火墙上一大片 IP 池本身就是一条合规问题。所以尽量用带专用终结点的 premium SKU,别在防火墙上开大通配。清单里有几个服务只在较低层级暴露公网多租户终结点,这也是你最后不得不放行 *.data.mcr.microsoft.com*.monitor.azure.com*.in.applicationinsights.azure.com 这类宽通配的原因,每一条都把一大片共享的微软 IP 开给了你的出口。premium 层级给了你一条退路。

为什么你明明没用 blob 存储,*.blob.core.windows.net / AzureMachineLearning 服务标记还是冒出来了: 好几个微软托管服务(App Insights、Foundry 评估器、Container Apps 镜像缓存)会绕经它们自己的存储账户。官方放行清单已经把它列进了 Evaluations & Traces。

为迭代而设计

第一天就打开 Azure Firewall 诊断日志,指向一个 Log Analytics 工作区。你会想按源子网加目标 FQDN 过滤 Deny 事件,去补齐放行清单里剩下的缺口。不过你迭代的是一个很短的增量,而不是从零开始搭这份清单。

4. Private DNS:最该第一个做对的高价值决策

BYO VNet 的 Foundry 事故里,追溯到 DNS 的比追溯到任何其他单一组件的都多,这正是它值得第一个设计的原因。两条规则能帮你挡掉大部分问题。

规则一:绝不出现重复的 Private DNS 区域。 如果 privatelink.blob.core.windows.net 在你的 hub 和 spoke 里同时存在,VNet 解析就变得不确定,你会时不时解析到错误的私有 IP,甚至更糟,解析到 0.0.0.0。给每个区域挑一个家,把重复的删掉。

规则二:在中心辐射里,PDZ 属于 hub。 每一个 privatelink.* 区域都只在 hub 里建一次。把每个 spoke VNet 的 DNS 服务器都设成防火墙的私有 IP(Azure Firewall 开启 DNS 代理)。spoke 的查询流程是:spoke 查询 → 防火墙 DNS 代理 → 在 hub 上下文里由 Azure DNS(168.63.129.16)解析 → hub 关联的 PDZ → 返回 PE 的 IP。这条链路跑通并不需要在 spoke 上再关联 PDZ。

Foundry Standard 需要的七个区域: privatelink.services.ai.azure.com、privatelink.openai.azure.com、privatelink.cognitiveservices.azure.com、privatelink.search.windows.net、privatelink.blob.core.windows.net、privatelink.documents.azure.com、privatelink.azure-api.net。

把流量强制导过防火墙: 光靠 VNet 对等不会把 spoke 出口送过 hub 防火墙,Azure 的路由更偏好直接走对等。你需要在每个 spoke 子网上放一条 UDR,用 0.0.0.0/0 指向防火墙私有 IP。没有这条 UDR,你的 FQDN 放行清单是在对空气生效。

5. 网络安全组:最小规则集

NSG 是这样一层:少一条出站规则,数据平面就被悄悄掐断,一切都预配得干干净净,但谁也说不上话。用第 3 节那个两桶模型来想 NSG,VNet 内部服务到服务,加上出站控制平面。

  • 放行出站 HTTPS(TCP 443),从 agent-subnet 和 apim-outbound-subnet 到 pe-subnet 的 CIDR(或者你愿意的话,到相应的服务标记:AzureCosmosDB、Storage.、AzureCognitiveSearch、AzureAD)。这覆盖了运行时经由各自专用终结点对 Cosmos、Storage、Search 以及 Foundry / 模型终结点的调用。
  • 放行 APIM 的出站依赖,从 apim-outbound-subnet 至少放行到 Storage 和 AzureKeyVault 服务标记的出站 TCP 443,具体见 APIM 出站集成 NSG 参考。漏了这些,就是经典的"APIM 在门户里变成 Failed"的症状。
  • 放行来自防火墙子网的 RDP/SSH(不是来自公网)到 jumpbox-subnet,并用防火墙 DNAT 把它暴露出去,VM 上不挂公网 IP。
  • 在 agent、PE 和 APIM 子网上默认拒绝出站到公网,只让防火墙路由经 UDR 逃出去。这样每一次 FQDN 调用都走你的放行清单,而不是绕过它。

6. 在写第一行智能体代码之前先验证

在你从应用里调用 agents.create() 之前,先证明网络是对的。从你的跳板机上:

1. DNS 从 spoke 私有解析

nslookup <foundry-account>.services.ai.azure.com
nslookup <search-name>.search.windows.net
nslookup <cosmos-name>.documents.azure.com
nslookup <apim-name>.azure-api.net

每一条都应当返回一个 10.x / 192.168.x 的 IP(你的 PE),而不是公网 IP。

如果跳板机能私有解析、但智能体子网不能,那你的 PDZ VNet 关联或者 UDR 出了问题。智能体子网必须解析到跟跳板机一样的私有 IP,否则运行时会出到公网 IP,然后在 Cosmos 上被你那个只认 PE 的防火墙回一个 403。

同样的源 IP 原则也适用于防火墙规则:你从哪些子网验证的,就得把它们作为 sourceAddresses 列进应用规则集合,连同它们要够到的每一个 FQDN。

7. 一份部署前检查清单

在你启动部署之前走一遍这份清单,每一项现在修都比 capabilityHosts PUT 已经在飞之后修要便宜。

  • 智能体子网委托给 Microsoft.App/environments,按微软官方推荐定为 /24(/27 是 API 强制的硬下限,不是目标)。
  • 已经决定智能体工具是否跑在 VNet 后面,并据此选好了对应模板(standard 还是 tools-behind-VNet)。
  • APIM 入站经由 pe-subnet 上的专用终结点,APIM 出站经由 VNet 集成进一个委托给 Microsoft.Web/serverFarms 的专用 apim-outbound-subnet,大小 /24(最小 /27)。
  • privatelink.* 的 PDZ(含 privatelink.azure-api.net)只存在一次(中心辐射的话就在 hub 里),并且只关联到 hub VNet,spoke 经防火墙 DNS 代理去解析它们。
  • spoke VNet 的 DNS = 防火墙私有 IP,防火墙策略开启了 DNS 代理。
  • 每个 spoke 子网上有一条 UDR 把 0.0.0.0/0 强制导向防火墙。
  • 防火墙应用规则包含文档里的 Foundry 基线(见第 3 节),加上你额外部分的补充(容器拉取、App Insights),并把智能体子网和跳板机子网作为源地址。(只有当 Deny 日志显示来自 apim-outbound-subnet 的流量时,才把它加进去。)
  • NSG 放行从智能体子网和 APIM 出站子网到 PE 子网 CIDR(或相应服务标记)的出站 443,以及按 APIM 文档放行 APIM 的 Storage / AzureKeyVault 出站规则。
  • 从跳板机和智能体子网做的 nslookup,对 Foundry、Cosmos、Storage、Search、APIM 都返回私有 IP。

收个尾:先决策,再部署

BYO VNet 上的 Foundry Standard 并不比任何其他做了网络隔离的 Azure 负载更难。它只是五个产品面的交叉口,Foundry、APIM、Cosmos、Search、Storage,每一个都有自己那点私有网络的怪脾气。让它显得难的,是先部署、再回过头撞上约束。

把这个顺序倒过来,它就顺了。在你跑任何一份模板之前:

  • 锁定子网布局和委托。智能体子网不可逆,第一天就定 /24。
  • Private DNS 一次性设计好,放在 hub,并用 UDR 把 spoke 出口强制导过防火墙。
  • 防火墙放行清单和 NSG 规则攒成一份变更申请,让网络团队一次过审。
  • 在任何智能体代码存在之前,就从跳板机和智能体子网两头验证 DNS
  • 整件事照着部署前检查清单跑,那份清单才是交付物,上面的一切都是它背后的推理。

这几件事做对了,模板就是走个手续。做错了,你就得重新部署。这就是"网络优先"这个思路的全部理由。

接下来去哪儿