DEV Community

Cover image for Sizing the Subnet: What Nobody Tells You About Microsoft Foundry Agent Service Networking Until Production Falls Over
Manoranjan Rajguru
Manoranjan Rajguru

Posted on

Sizing the Subnet: What Nobody Tells You About Microsoft Foundry Agent Service Networking Until Production Falls Over

Sizing the Subnet: What Nobody Tells You About Microsoft Foundry Agent Service Networking Until Production Falls Over

You provisioned a Foundry Agent Service environment with a bring-your-own VNet. You picked a /27 subnet because it "felt like enough" — 32 addresses for a dev environment, what could go wrong? Three weeks later, in production, your hosted agents start failing session creation with HTTP 429 subnet_exhausted, your data proxy starts throwing intermittent 5xx errors under load, and new project provisioning silently stops working. There's no portal dashboard telling you why. There's no alert. You're left grepping through Application Insights traces trying to figure out why an agent is failing on what looks like a networking problem.

This is not a hypothetical. It's the exact failure mode Microsoft's own networking documentation for Foundry Agent Service was written to prevent, and it's one of the least-discussed parts of the platform because on the surface, network isolation looks like "just add a private endpoint." It isn't. Underneath the portal wizard is a two-plane architecture with IP allocation rules, session-to-IP mapping ratios, and failure signatures that look nothing like a VNet problem unless you know what to look for.

This article is a deep dive into how Foundry Agent Service actually behaves on the wire when you bring your own VNet: the architecture of the platform-managed network versus your customer network, how hosted agents and prompt agents consume IPs completely differently, how to size a delegated subnet for real production concurrency, and how to recognize IP exhaustion before it takes down your agent fleet.

Why This Matters

Enterprises adopting Foundry Agent Service almost always have a compliance mandate: agent traffic must stay inside customer-managed network boundaries, tool calls to internal APIs must not traverse the public internet, and data at rest must live in the customer's own tenant. Microsoft's answer to this is a "Standard Setup with private networking" — VNet injection of the agent compute plane into a subnet you own, combined with Bring-Your-Own (BYO) Storage, Cosmos DB, and Azure AI Search so no vector or transcript data ever leaves your governance boundary.

That's the pitch. The part that doesn't show up in the marketing is that this architecture turns your subnet into a shared capacity resource across every project in the Foundry account, agent sessions consume IPs the way a connection pool consumes sockets, and the platform gives you almost no visibility into utilization until something breaks. If you're the architect who signs off on the network design, you need to understand the IP math before you approve a subnet size — because there's no live utilization graph to bail you out later.

Table of Contents

  1. Two Networks, One Request
  2. Hosted Agents vs. Prompt Agents: Completely Different Network Citizens
  3. The Delegated Subnet and the Data Proxy
  4. Sizing the Subnet: The IP-to-Session Math
  5. Setting It Up: Portal, Bicep, and the azd Path
  6. DNS: The Part Everyone Gets Wrong
  7. Failure Modes: What Exhaustion Actually Looks Like
  8. VNet Peering and the IP Overlap Trap
  9. Production Recommendations
  10. Security Considerations
  11. Cost Considerations
  12. Common Mistakes
  13. Managed VNet: The Alternative Nobody Mentions First
  14. Conclusion
  15. References

Two Networks, One Request

Every single request to Foundry Agent Service crosses a boundary between two networks that most architects mentally collapse into one: the Microsoft-managed Foundry platform network, and your customer VNet.

The platform network is where Microsoft hosts the pieces you never provision yourself: the Foundry endpoint (the API gateway your client SDK actually talks to, something like <your-resource>.services.ai.azure.com), the Micro VM host layer that runs your Hosted agents, the Tools Service, and the Data Proxy host layer.

Your customer VNet contains exactly two things Foundry cares about: a delegated subnet, where Micro VMs and data proxy instances actually consume IP addresses, and a private endpoint subnet, where your Storage account, Cosmos DB, Azure AI Search, and Key Vault sit behind Private Link.

Foundry Agent Service network architecture diagram showing the platform network and customer VNet

Two request flows traverse this boundary, and they are architecturally distinct in a way that changes your capacity planning:

  • Hosted agent path: Client → Foundry endpoint → Micro VM (/invoke) → Tools Service → Data Proxy → customer resources via private endpoint
  • Prompt agent path: Client → Foundry endpoint → Tools Service → Data Proxy → customer resources via private endpoint

Notice the prompt agent path has no Micro VM hop at all. That's not a simplification for the diagram — it's the actual runtime behavior, and it's the reason prompt agents and hosted agents have completely different IP consumption profiles, which we'll get to.

Hosted Agents vs. Prompt Agents: Completely Different Network Citizens

If you've been building on Foundry, you already know the SDK-level distinction between hosted agents (you own the container image, deployed to Azure Container Registry, you pick CPU/memory) and prompt agents (fully managed compute, you just define behavior via configuration). What isn't obvious is that this distinction extends all the way down to how IP addresses get consumed in your delegated subnet.

Hosted agents run inside a Micro VM — a lightweight VM dedicated to that agent's session — and the Micro VM has two network interfaces:

Traffic type Route
Agent's own outbound traffic Direct, through the Micro VM's dedicated NIC in the delegated subnet
Tool server calls Through the single-tenant data proxy, regardless of agent type

The critical detail: even though the Micro VM has its own dedicated NIC, every tool invocation still routes through the data proxy. Your agent's raw HTTP calls to, say, an internal REST API you registered as a tool server don't leave through the Micro VM's NIC — they get proxied. This matters when you're debugging: a tool call failing with a timeout might be a Micro VM problem, a data proxy problem, or a private endpoint DNS problem, and distinguishing between them requires understanding this dual-path model.

Prompt agents never touch a Micro VM. The Foundry endpoint forwards the request straight to the Tools Service, which calls the single-tenant data proxy on your behalf. Compute for prompt agents runs entirely in Microsoft-managed infrastructure — you don't provision or scale it, and versions of a prompt agent don't consume subnet IPs at all.

This asymmetry is the single most important fact in this entire article: hosted agent sessions consume delegated subnet IPs, prompt agent versions do not. If your workload is prompt-agent-heavy, your subnet math looks completely different than if you're running a fleet of hosted agents with custom containers.

The Delegated Subnet and the Data Proxy

The single-tenant data proxy is the unsung hero (and occasional villain) of this architecture. It's a platform-managed networking component dedicated to your Foundry project — every project gets its own isolated instance — and it handles all outbound connectivity for your agents' tool calls. Whether you're calling a REST-based tool server, hitting Azure AI Search for grounding, or writing conversation state to Cosmos DB, that traffic goes through the data proxy, which then egresses to your resources through private endpoints in your private endpoint subnet.

Because IPs for prompt agents are allocated at the project level, every prompt agent inside a single project shares that project's data proxy infrastructure. That's a resource-sharing design decision worth internalizing: if you're running twenty prompt agents in one project, they are not twenty independent network citizens — they're twenty consumers of one shared proxy.

Subnet configuration itself, on the other hand, applies at the Foundry account level, not the project level. Every project under that account shares the same delegated subnet, and hosted and prompt agents draw from the same pool of addresses. This is the detail that trips up teams who provision one Foundry account per business unit expecting network isolation between projects — the subnet doesn't care about your project boundaries, it only cares about aggregate IP demand across the entire account.

Sizing the Subnet: The IP-to-Session Math

Here's where architecture meets arithmetic. Microsoft publishes a default mapping of 1 concurrent hosted-agent session per usable subnet IP, and a support-escalatable mapping of 1:10 (one IP supporting ten concurrent sessions) if you request it and your region has capacity.

Subnet Total IPs Usable IPs ~Concurrent sessions (1:1)
/27 32 ~27 ~20
/26 64 ~59 ~50
/25 128 ~123 ~100
/24 256 ~251 ~250
/23 512 ~507 ~500
/22 1,024 ~1,019 ~1,000
/21 2,048 ~2,043 ~2,000

Two numbers in that table deserve emphasis. First, /27 is explicitly called out as a minimum, not a recommendation — it might carry a dev/test workload but leaves essentially no headroom. Second, "~20 concurrent sessions" on a /27 is not a hard ceiling you approach gracefully; it's a hard ceiling you slam into, because platform upgrades run old and new infrastructure in parallel, temporarily doubling IP consumption during the rollout window. A subnet sized exactly to your steady-state peak will fail during Microsoft's own maintenance windows — not because of anything you did.

A session, importantly, represents hosted-agent compute and persisted file state, not conversation history. With the Responses protocol, a conversation maps to a session; with other invocation patterns, a session can be reused across conversations without platform-managed history. This distinction matters for planning — don't naively multiply "expected concurrent users" by "conversations per user" and assume that's your session count. Model actual concurrent hosted-agent compute demand, which is usually lower than raw conversation concurrency because idle conversations don't hold a live session.

Sizing methodology, distilled from Microsoft's guidance:

  1. Estimate peak concurrent hosted agent sessions across every project under the account, for the target region.
  2. Check the region's default concurrent session quota — this is a subscription+region-wide ceiling, independent of subnet size.
  3. Size the subnet so usable IPs comfortably exceed your target, keeping planned peak under 80% utilization to absorb upgrade/scaling spikes.
  4. If your target exceeds the regional quota, file a limit-increase support request specifying subscription, region, and expected concurrency.
  5. If the subnet physically can't grow (address space constraints) and you need more sessions than 1:1 mapping allows, request the 1:10 IP-to-session mapping increase in the same support ticket.

Also worth internalizing: project provisioning itself competes for the same IP pool. A Foundry account supports roughly 250 projects under light traffic, but that can collapse to as few as ~25 projects under heavy session load, because provisioning a new project also needs available subnet capacity. If you're planning a platform for many teams (many projects) and heavy concurrent agent usage, you need to size for both dimensions simultaneously, not just session count.

Setting It Up: Portal, Bicep, and the azd Path

Microsoft supports two operational paths to configure private networking, and picking the right one depends on whether you're standing up net-new infrastructure or wiring an existing azd-based hosted agent project into an existing secured VNet.

Path 1 — Standard Setup with private networking (Portal, Bicep, or Terraform): provisions a Foundry resource, project, and (optionally) the supporting VNet/subnet from scratch, with no public egress by default. If you don't already have a VNet, this flow can provision one for you. Prerequisites include registering several resource providers up front:

az provider register --namespace 'Microsoft.KeyVault'
az provider register --namespace 'Microsoft.CognitiveServices'
az provider register --namespace 'Microsoft.Storage'
az provider register --namespace 'Microsoft.MachineLearningServices'
az provider register --namespace 'Microsoft.Search'
az provider register --namespace 'Microsoft.Network'
az provider register --namespace 'Microsoft.App'
az provider register --namespace 'Microsoft.ContainerService'
# Only required if you plan to use the Grounding with Bing Search tool
az provider register --namespace 'Microsoft.Bing'
Enter fullscreen mode Exit fullscreen mode

Note the BYO requirement: Standard setups with private networking require you to bring your own Azure Storage, Azure AI Search, and Azure Cosmos DB. This isn't optional tooling — it's how Microsoft guarantees all agent data at rest (files, vector indexes, conversation/session state) stays inside your tenant's governance boundary rather than a Microsoft-managed multi-tenant store.

Path 2 — azd for hosted agent source-code deployments: if you're deploying a hosted agent from source using the Azure Developer CLI, you attach its dependencies to an already-secured VNet rather than provisioning the whole environment from scratch. This is the path most application teams will actually use day-to-day once platform/security teams have stood up the shared network.

Role-wise, don't underestimate the permission surface. Creating this setup requires Foundry Account Owner at subscription scope, plus Role Based Access Administrator (or subscription Owner) to grant role assignments to Cosmos DB, AI Search, and Storage — because the BYO resources need managed-identity role assignments wired up as part of provisioning. Separately, day-to-day builders only need the Foundry User role scoped to agents/*/read, agents/*/action, agents/*/delete — they should never need account-level network permissions.

DNS: The Part Everyone Gets Wrong

Private endpoints are useless without correct DNS resolution, and this is where a lot of "we set up the private endpoint but it doesn't work" tickets originate. When you create a private endpoint, Azure updates the Foundry resource's DNS CNAME to an alias under a privatelink subdomain, and by default provisions a matching Private DNS zone with A records pointing at the private endpoint IP.

The behavior that surprises people: the same connection string works both inside and outside the VNet — it just resolves differently depending on where the client sits. From outside the VNet, the FQDN resolves to the public endpoint. From inside the VNet (or from an on-prem network connected via VPN/ExpressRoute with proper DNS forwarding), it resolves to the private IP. There's no separate "private" connection string to remember, which is convenient for application config but means DNS misconfiguration fails silently as "it connects, just to the wrong thing" rather than an obvious connection error.

If you run custom DNS servers (common in enterprises with on-prem AD-integrated DNS), you must explicitly delegate the privatelink subdomain to Azure's private DNS zone, or replicate the A records manually. Validate with:

# From a VM/host inside the VNet (or via VPN/ExpressRoute)
nslookup <your-foundry-endpoint-hostname>
Enter fullscreen mode Exit fullscreen mode
# Confirm TCP reachability on 443 to the resolved private IP
Test-NetConnection <private-endpoint-ip-address> -Port 443
Enter fullscreen mode Exit fullscreen mode

And check that the private endpoint connection status shows Approved under the project's Networking blade before assuming the DNS layer is the problem — a pending approval looks like a DNS issue if you don't check connection status first.

Failure Modes: What Exhaustion Actually Looks Like

This is the section that will save you the most on-call pain. The Azure portal does not expose IP utilization for delegated subnets. There is no gauge, no metric, no alert rule you can attach to "subnet 80% full." You are flying blind until symptoms appear, and the symptoms look like generic platform instability unless you know the signature.

Diagram showing the subnet IP exhaustion failure mode: full delegated subnet leading to HTTP 429 subnet_exhausted and HTTP 5xx data proxy errors

The two leading indicators to monitor for:

  • HTTP 429 subnet_exhausted on hosted-agent session creation or resume — this is the platform explicitly telling you it can't allocate a Micro VM because there's no IP available in the delegated subnet.
  • HTTP 5xx from the data proxy — the data proxy itself can't scale because it also draws IPs from the same subnet.

Either signal, combined with new project provisioning failures, means you've hit the ceiling. The remediation is not a config toggle — it typically means provisioning a fresh Foundry instance with a larger subnet, migrating workloads, or filing a support request for a mapping increase, none of which are fast under production pressure. This is exactly why the sizing methodology in the previous section is not optional busywork — it's the only real mitigation, because reactive monitoring for this failure mode barely exists today.

Practical monitoring recommendation: since the platform doesn't expose subnet-level metrics, build your own leading indicators from what is observable — track HTTP status codes returned to hosted-agent session creation/resume calls and data proxy-adjacent tool call latencies/error rates in Application Insights (see Day 10 of this series on Foundry observability for how to wire OpenTelemetry tracing to catch this pattern before it becomes an incident).

VNet Peering and the IP Overlap Trap

If your delegated subnet's VNet is peered with other VNets (common in hub-spoke enterprise topologies), all peered VNets must use unique, non-overlapping IP ranges — this applies even for one-directional peering relationships, because Azure VNet peering is inherently bidirectional at the routing level. Only RFC 1918 ranges are supported (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16); CGNAT ranges like 100.64.0.0/10 will cause outright routing failures, not degraded performance.

If your organization has an existing address plan with unavoidable overlaps (mergers/acquisitions are the classic cause), bring-your-own VNet is not viable without renumbering. In that situation, Microsoft's own guidance is to fall back to Managed VNet, which we cover below.

Production Recommendations

Distilling everything above into an actionable checklist for a production rollout:

  • Default to /24 for production. Don't start at /27 "to be safe" — it isn't. /24 gives you room for the 1:1 default mapping to support roughly 250 concurrent hosted-agent sessions with headroom for platform upgrade spikes.
  • Plan for 80% max utilization, not 100%. The 20% buffer exists specifically to absorb Microsoft's own rolling upgrades, which temporarily run old and new infrastructure side by side.
  • Model hosted vs. prompt agent mix explicitly. If your workload is prompt-agent-dominant, your subnet consumption profile is driven by project count and data proxy scaling, not per-session IP draw — size differently than a hosted-agent-heavy fleet.
  • Request the 1:10 mapping proactively if you expect high concurrency, rather than waiting for a 429 storm in production to file the support ticket.
  • Treat account-level subnet sharing as a capacity planning input, not an afterthought — if multiple teams share one Foundry account, their peak concurrency demands are additive against one shared pool.
  • Instrument your own leading indicators for 429/5xx patterns tied to session creation, since the platform gives you no native subnet utilization telemetry.

Security Considerations

Network isolation and security posture are deeply intertwined here, and a few points are easy to miss:

  • Public network access (PNA) is a separate control from private endpoints. You can have private endpoints configured and still leave PNA enabled, in which case your resource is reachable both ways. To be genuinely locked down, disable PNA or restrict to selected IPs, in addition to configuring the private endpoint.
  • Trusted Azure services can bypass network rules via managed identity — Foundry Tools, Azure AI Search, and Azure Machine Learning can be granted exceptions through role assignment even when your project restricts network access to everything else. This is useful, but it's also a policy surface security review should explicitly check, since it's an intentional hole in an otherwise closed network.
  • The BYO data resources (Storage, Cosmos DB, AI Search) are independent Azure resources with their own governance boundaries. Locking down the Foundry resource's networking does not automatically lock down these dependencies — you must separately configure private endpoints, firewalls, and RBAC on each of them. Teams frequently secure the Foundry front door and forget the BYO backends are still wide open.
  • Removing a private endpoint does not make a project publicly accessible again — re-enabling public access is a distinct, explicit action. This asymmetry is a deliberate safety rail against accidental exposure during network reconfiguration.

Cost Considerations

The direct cost of the networking layer itself is modest relative to compute/token spend — private endpoints, VNet infrastructure, and the data proxy are billed as standard Azure networking/Container Apps resources — but there are indirect cost implications worth flagging:

  • Larger subnets don't cost more by themselves (private IP address space inside your own VNet is free), so there's little financial reason to under-provision a subnet purely to "save cost." The real cost risk is under-provisioning and then paying in incident response and lost throughput when sessions fail.
  • The 1:10 IP-to-session mapping increase is a support-mediated capacity change, not a paid SKU upgrade — but it requires lead time, so factor that into your rollout timeline rather than treating it as an instant lever.
  • BYO Storage/Cosmos DB/AI Search costs are yours to manage independently of Foundry billing — since these are customer-owned resources, their throughput/RU/storage costs scale with your usage patterns and are worth modeling separately from Foundry's own agent/token costs.

Common Mistakes

A pattern-matched list from how teams actually get this wrong in the field:

  1. Sizing the subnet for today's dev traffic, not production peak. A /27 that works fine in a proof-of-concept becomes the production bottleneck three sprints later when nobody revisits the network design.
  2. Assuming project-level network isolation. Subnet capacity is shared at the account level — spinning up a new project doesn't give you a fresh IP pool.
  3. Forgetting that platform upgrades transiently double IP consumption. Sizing exactly to observed steady-state peak, with zero headroom, guarantees an outage during Microsoft's next maintenance window.
  4. Treating tool calls as "direct" traffic for hosted agents. Even with a dedicated Micro VM NIC, tool invocations still route through the data proxy — debugging tool latency by only checking the Micro VM is looking in the wrong place.
  5. Not delegating the privatelink DNS subdomain when using custom/on-prem DNS servers, resulting in "connects but resolves to the wrong endpoint" bugs that look like application errors.
  6. Ignoring VNet peering IP overlap until deployment time. This is an address-planning problem best caught in design review, not discovered mid-rollout when peering fails.
  7. Assuming there's a portal metric for subnet utilization. There isn't. Teams that don't build their own 429/5xx monitoring get zero warning before exhaustion.

Managed VNet: The Alternative Nobody Mentions First

Everything above assumes bring-your-own VNet, which is the right choice when you have existing enterprise network topology, address planning constraints, or compliance requirements around network ownership. But if your primary driver is "no public egress" rather than "reuse our exact existing VNet," Managed VNet is worth strong consideration: Microsoft automates the network setup end-to-end and — critically — eliminates the IP overlap problem entirely, since you're not injecting into an address space you have to coordinate with the rest of your enterprise network.

The trade-off is control: with Managed VNet you give up fine-grained subnet sizing decisions and custom peering topology in exchange for Microsoft handling the plumbing. For teams without a hard requirement to reuse a specific existing VNet, or those who've been burned by IP overlap issues in hub-spoke topologies, this is a legitimate default rather than a fallback of last resort.

Conclusion

Network isolation for Foundry Agent Service isn't a checkbox you tick in the portal wizard — it's a capacity-planning discipline that most teams under-invest in because the failure signature (429s and 5xx errors) doesn't look like a networking problem at first glance. The core mental model to carry forward: hosted agents consume subnet IPs per session through dedicated Micro VM NICs, prompt agents share project-level data proxy capacity without consuming per-version IPs, all tool traffic funnels through the data proxy regardless of agent type, and the entire subnet is a shared resource across every project in your Foundry account — not per-project isolated capacity.

If you're designing this for production today: start at /24, plan for 80% utilization, explicitly model your hosted-vs-prompt agent mix, and instrument your own leading indicators for exhaustion since the platform won't do it for you. Get this right at design time, because by the time you're staring at subnet_exhausted errors in production, your remediation options are all slow ones.

Next in this series: we'll look at how Foundry's Grounding with Bing and Azure AI Search tools interact with this same private networking model — and what changes when your grounding data source is a public-internet API versus a BYO private resource.

References

This is Day 11 of the Microsoft Foundry 100 Days / 100 Blogs series — a daily deep dive into the architecture, internals, and production realities of building on Microsoft Foundry.

Top comments (0)