# Foundry Vnet Deploy

> >

- **Type:** Skill
- **Install:** `agentstack add skill-aiappsgbb-awesome-gbb-foundry-vnet-deploy`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [aiappsgbb](https://agentstack.voostack.com/s/aiappsgbb)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [aiappsgbb](https://github.com/aiappsgbb)
- **Source:** https://github.com/aiappsgbb/awesome-gbb/tree/main/skills/foundry-vnet-deploy

## Install

```sh
agentstack add skill-aiappsgbb-awesome-gbb-foundry-vnet-deploy
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Foundry VNet Deploy — Agent Setup inside a Private VNet

## 1. Goal

Guide the user step by step to deploy **Azure AI Foundry with Agent in a private VNet** using the Bicep files from the `15-private-network-standard-agent-setup` reference project. The skill collects all required parameters, generates the `.bicepparam` file, and runs the deployment.

> **Optional scenario hint.** When the user invokes the skill, they may pass a one-line scenario hint such as `"new VNet in swedencentral"` or `"existing VNet with existing DNS zones"`. Use it to pre-fill defaults during the interview wherever it applies.

> **Day-2 lifecycle companion.** This skill covers greenfield create only. For **Day-2 capability host lifecycle** (idempotent re-create, delete, soft-delete + purge of the parent account, `Subnet already in use` redeploy guard, soft-delete recovery) see [`foundry-caphost-lifecycle`](../foundry-caphost-lifecycle/SKILL.md). You will need it any time you tear down and redeploy a Foundry caphost into the same VNet/subnet.

## 2. Architecture being deployed

The deployment creates the following secure network architecture:

```
┌─────────────────────────────────────────────────────────┐
│                    Resource Group                        │
│                                                          │
│  ┌─────────────────────────────────────────────────────┐ │
│  │              Virtual Network (VNet)                  │ │
│  │                                                      │ │
│  │  ┌──────────────────┐  ┌──────────────────────────┐ │ │
│  │  │  Agent Subnet     │  │  Private Endpoint Subnet │ │ │
│  │  │  (delegated to    │  │                          │ │ │
│  │  │  Container Apps)  │  │  ● AI Services PE        │ │ │
│  │  │                   │  │  ● AI Search PE          │ │ │
│  │  │  Network          │  │  ● Storage PE (blob)     │ │ │
│  │  │  Injection for    │  │  ● CosmosDB PE (SQL)     │ │ │
│  │  │  AI Agents        │  │                          │ │ │
│  │  └──────────────────┘  └──────────────────────────┘ │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                          │
│  ┌──────────────┐ ┌────────────┐ ┌───────────────────┐  │
│  │ AI Services  │ │ AI Search  │ │ Storage Account   │  │
│  │ (Foundry)    │ │ (standard) │ │ (StorageV2, ZRS)  │  │
│  │ ● SKU S0     │ │ ● disabled │ │ ● public access   │  │
│  │ ● public     │ │   public   │ │   disabled        │  │
│  │   disabled   │ │   access   │ │ ● shared key      │  │
│  │ ● network    │ │            │ │   disabled        │  │
│  │   injection  │ │            │ │                   │  │
│  └──────────────┘ └────────────┘ └───────────────────┘  │
│                                                          │
│  ┌──────────────┐ ┌────────────────────────────────────┐ │
│  │ CosmosDB     │ │ Private DNS Zones (6 zones)       │ │
│  │ (SQL API)    │ │ ● privatelink.services.ai.azure.. │ │
│  │ ● public     │ │ ● privatelink.openai.azure.com    │ │
│  │   disabled   │ │ ● privatelink.cognitiveservices.. │ │
│  │ ● local auth │ │ ● privatelink.search.windows.net  │ │
│  │   disabled   │ │ ● privatelink.blob.core.windows.. │ │
│  │              │ │ ● privatelink.documents.azure.com │ │
│  └──────────────┘ └────────────────────────────────────┘ │
│                                                          │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ AI Foundry Account Capability Host                   │ │
│  │ ● capabilityHostKind: Agents                         │ │
│  │ ● customerSubnet → Agent Subnet (VNet injection)     │ │
│  │ ● Replaces manual createCapHost.sh                   │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                          │
│  ┌──────────────────────────────────────────────────────┐ │
│  │ AI Foundry Project                                   │ │
│  │ ● System-Assigned Managed Identity                   │ │
│  │ ● Connections: CosmosDB, Storage, AI Search          │ │
│  │ ● Project Capability Host (Agents) with:             │ │
│  │   - vectorStoreConnections → AI Search               │ │
│  │   - storageConnections → Blob Storage                │ │
│  │   - threadStorageConnections → CosmosDB               │ │
│  │ ● Depends on Account Capability Host                 │ │
│  └──────────────────────────────────────────────────────┘ │
│                                                          │
│  Role Assignments (Project SMI):                         │
│  ● Storage Blob Data Contributor (account level)         │
│  ● Storage Blob Data Owner (container level, scoped)     │
│  ● Cosmos DB Operator (account level)                    │
│  ● Cosmos DB Built-in Data Contributor (enterprise_memory)│
│  ● AI Search Index Data Contributor                      │
│  ● AI Search Service Contributor                         │
│  └───────────────────────────────────────────────────────┘
└──────────────────────────────────────────────────────────┘
```

## 3. Workflow

Follow these steps IN ORDER. Use the `ask_user` tool for every question.

### Step 0: Choose the template (Decision Guide)

This skill vendors **two** Foundry network-isolation templates. Pick one before
the interview — they share Steps 1-8b/12/13 but differ on BYO resources and DNS.

| You need… | Template | `TEMPLATE_DIR` |
|---|---|---|
| **BYO** Azure AI Search + Storage + Cosmos wired as project connections (vector store, thread storage, file storage) | **standard-agent** (template 15) | `templates/standard-agent` |
| **Platform-managed** storage — no BYO Search/Storage/Cosmos, smallest network surface, optional private ACR | **basic-vnet** (template 11) | `templates/basic-vnet` |

Ask the user:

1. **Do your agents need BYO Search / Storage / Cosmos connected to the project?**
   - **Yes / not sure / need vector search + custom thread storage** → `standard-agent`.
   - **No — platform-managed storage is fine** → `basic-vnet`.

Set the working directory for every later deploy/verify command:

```bash
# standard:
TEMPLATE_DIR="templates/standard-agent"
# basic:
TEMPLATE_DIR="templates/basic-vnet"
```

**What differs by fork** (both keep the four awesome-gbb integrations —
hosted-agent developer RBAC, App Insights project-MI roles, Citadel spoke
peering, APIM DNS link):

| Aspect | standard-agent (15) | basic-vnet (11) |
|---|---|---|
| BYO resources | AI Search + Storage + Cosmos (create or reuse) | none (platform-managed) |
| Project connections | CosmosDb, CognitiveSearch, AzureStorageAccount (+ appinsights) | appinsights only |
| Private endpoints | AI Services, Search, Storage(blob), Cosmos(SQL) (4) | AI Services + Monitor PLS (2) + ACR (optional → 3) |
| Private DNS zones | 6 (services.ai, openai, cognitiveservices, search, blob, documents) | 3 app (services.ai, openai, cognitiveservices) + `azurecr.io` (if ACR) + 4 monitor zones |
| Optional private ACR | no | yes (`enableContainerRegistry`, default **true**; `developerIpCidr`) |
| Account capability host | yes (`accountCapHost`) | project caphost only (`projectCapHost` = `caphostproj`) |
| Role assignments | 6 (project-MI over BYO) + optional developer/telemetry | telemetry (LAW Reader + Azure AI User) + optional developer + ACR AcrPull |
| Deploy time | 45-90 min | 30-60 min (no BYO wiring) |

> Steps 7 (BYO existing resources) and 8 (6-zone DNS map) apply to
> **standard-agent only**. On **basic-vnet**, skip Step 7 entirely; in Step 8
> the DNS map uses the basic zone set (`existingDnsZones` = 3 app zones +
> optional `azurecr.io`; `existingMonitorDnsZones` = 4 monitor zones), and you
> additionally ask about the optional private ACR (`enableContainerRegistry`,
> `developerIpCidr`).

### Step 1: Verify prerequisites

Before starting, verify:

1. Run `az account show` to confirm the user is logged in to Azure CLI.
2. If NOT logged in, indicate that they must run `az login` first.
3. Show the current subscription and ask whether it is correct.

### Step 2: Subscription and Resource Group

Ask the user:

1. **Subscription**: Do they want to use the current subscription or change it? If they want to change, ask for the subscription ID.
2. **Resource Group**: Does the resource group already exist or does it need to be created?
   - If it needs to be created, ask for the name and location.
   - If it already exists, ask for the name.

### Step 3: Location

Ask for the deployment region. The allowed regions are:

- westus, eastus, eastus2, japaneast, francecentral, spaincentral, uaenorth
- southcentralus, italynorth, germanywestcentral, brazilsouth, southafricanorth
- australiaeast, swedencentral, canadaeast, westeurope, westus3, uksouth, southindia
- koreacentral, polandcentral, switzerlandnorth, norwayeast (Class B and C only)

Present the options as a list and offer `swedencentral` as the recommended one.

### Step 4: AI service and project name

Ask:

1. **aiServices**: Prefix for the AI Services resource (default: `foundry`). A unique suffix will be appended automatically.
2. **firstProjectName**: Project name (default: `project`).
3. **displayName**: Visible project name (default: same as the project name).
4. **projectDescription**: Project description (default: `A project for the AI Foundry account with network secured deployed Agent`).
5. **accountCapHost**: Name of the account-level capability host (default: `caphostacct`). This resource sets `customerSubnet` for the agent runtime network injection.

### Step 5: Model configuration

Ask:

1. **modelName**: Name of the model to deploy (default: `gpt-4.1`). Common options: gpt-4.1, gpt-4o, gpt-4o-mini, gpt-4.1-mini, gpt-4.1-nano.
2. **modelFormat**: Model provider (default: `OpenAI`).
3. **modelVersion**: Model version. Depends on the chosen model.
4. **modelSkuName**: Deployment SKU (default: `GlobalStandard`). Options: GlobalStandard, Standard, ProvisionedManaged.
5. **modelCapacity**: TPM (tokens per minute) in thousands (default: `30` = 30K TPM).

### Step 6: Network configuration (VNet)

Ask the user:

**Are you going to use an existing VNet or create a new one?**

> **Subnet sizing (agent injection).** The agent subnet is delegated to
> `Microsoft.App/environments` and consumes ~1 IP per ~10 running agent pods.
> The platform caps concurrent agent sessions at **50 per subscription per
> region** — that ceiling does **not** scale with a bigger subnet. A larger
> subnet buys **project density** (~250 projects at low traffic, as few as ~25
> at full scale) and **upgrade/scale headroom**, not more sessions.
>
> | Agent subnet CIDR | Usable IPs | Concurrent sessions | Use when |
> |---|---|---|---|
> | **/24** | 251 | 50 (platform cap) + upgrade buffer | **Production default** (Microsoft-recommended) |
> | /25 | 123 | 50 (platform cap) | Buffer between /26 and /24 |
> | /26 | 59 | ~50 — **minimum to reach the cap** | Smallest that supports the full 50 |
> | /27 | 27 | ~17 | Dev/test only — **minimum, risky** |
>
> Rules: **RFC-1918 only** (10/8, 172.16/12, 192.168/16) — the CGNAT
> `100.64.0.0/10` range is **not supported** (routing failures). Avoid
> `172.17.0.0/16` (reserved by Docker bridge). Target ** Prompt-agent revisions do **not** consume subnet IPs; hosted-agent revisions
> do (100 active / 1000 total per agent name; ~200 hosted agents per Foundry
> instance). The PE subnet only needs one IP per private endpoint (a /27 is
> plenty). Full IP math and exhaustion symptoms:
> [`references/agent-networking.md`](references/agent-networking.md).

### Option A: New VNet
Ask:
1. **vnetName**: VNet name (default: `agent-vnet`).
2. **vnetAddressPrefix**: Address space (default: `192.168.0.0/16`). Also supports `10.x.x.x/16` or `172.16.x.x/16`.
3. **agentSubnetPrefix**: CIDR of the agent subnet (default: automatically calculated as the first /24 of the address space).
4. **peSubnetPrefix**: CIDR of the private endpoint subnet (default: automatically calculated as the second /24).
5. **agentSubnetName**: Name of the agent subnet (default: `agent-subnet`).
6. **peSubnetName**: Name of the PE subnet (default: `pe-subnet`).

### Option B: Existing VNet
Ask:
1. **existingVnetResourceId**: Full resource ID of the VNet. Format: `/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Network/virtualNetworks/{name}`.
2. **agentSubnetName**: Name of the agent subnet (will be created if it does not exist). IMPORTANT: This subnet needs delegation to `Microsoft.App/environments`.
3. **peSubnetName**: Name of the private endpoint subnet (will be created if it does not exist).
4. **agentSubnetPrefix**: CIDR of the agent subnet (mandatory if the subnet does not exist). WARNING: Must not overlap with existing subnets.
5. **peSubnetPrefix**: CIDR of the PE subnet (mandatory if the subnet does not exist).

### Step 7: Existing resources (optional)

Ask whether the user has existing resources they want to reuse:

1. **Do you have an existing AI Search?** If yes → ask for `aiSearchResourceId` (full ARM format).
2. **Do you have an existing Storage Account?** If yes → ask for `azureStorageAccountResourceId`.
3. **Do you have an existing CosmosDB?** If yes → ask for `azureCosmosDBAccountResourceId`.

If none are provided, all of them will be created automatically. The new resources are created with:
- **AI Search**: Standard SKU, public access disabled, local auth enabled with AAD.
- **Storage**: StorageV2, ZRS (or GRS in southindia/westus), public access disabled, shared key disabled.
- **CosmosDB**: Global Document DB, Session consistency, public access disabled, local auth disabled.

### Step 8: Private DNS zones (optional)

Ask:

**Do you have existing private DNS zones that you want to reuse?**

If NO → all zones will be created automatically (6 zones). Continue to step 9.

If YES → ask:

1. **dnsZonesSubscriptionId**: Subscription where the DNS zones are located (leave empty if it is the same as the deployment).
2. For each zone, ask whether it exists and which resource group it is in:
   - `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`

The format is an object where each key is the zone name and the value is the resource group (empty = create a new one).

> **Central DNS at scale (hub-and-spoke).** When the spoke is deployed into an enterprise hub-and-spoke topology, the 6 zones above are typically owned by the **platform team in a separate subscription** (often the connectivity hub). The `dnsZonesSubscriptionId` parameter combined with the per-zone resource-group map in `existingDnsZones` is exactly the pattern described in Microsoft's Cloud Adoption Framework — see [Private Link and DNS integration at scale](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/private-link-and-dns-integration-at-scale#private-link-and-dns-integration-in-hub-and-spoke-network-architectures) for the canonical reference architecture. The deployment principal needs `Private DNS Zone Contributor` on each zone in the hub subscription to create the VNet links; without this you will hit `InvalidPrivateDnsZoneIds` at deploy time.
>
> - For deploy-time DNS troubleshooting (including the `InvalidPrivateDnsZoneIds` symptom → cause → fix table), see the upcoming `foundry-network-runbook` skill.

### Step 8b: Hosted agent developers (optional but recommended)

Users / service principals that are going to **create hosted agents** in this Foundry need:
- `Managed Identity Operator` on the Foundry account
- `Network Contributor` on the agent injection subnet

Without these permissions, hosted agent creation will fail with 403 errors when provisioning the MIs or NICs. The template can assign them automatically.

Ask:

1. **Which users / groups / SPs are going to create hosted agents in this Foundry?**
   - Ask for a list of *

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [aiappsgbb](https://github.com/aiappsgbb)
- **Source:** [aiappsgbb/awesome-gbb](https://github.com/aiappsgbb/awesome-gbb)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-aiappsgbb-awesome-gbb-foundry-vnet-deploy
- Seller: https://agentstack.voostack.com/s/aiappsgbb
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
