Scope: Four Entra ID groups provide role-based access across two projects within one Foundry Resource. An Account Owner group administers the Foundry Resource, two Dev groups each own a project, and a Subscription Admin group has full resource provisioning rights. All resource connections use managed identity — no keys or secrets in Bicep parameters.
| Resource | Purpose |
|---|---|
| AI Foundry Resource | CognitiveServices account (2025-09-01) with allowProjectManagement — the central workspace |
| AI Foundry Project 1 | First team-scoped project under the Foundry Resource for agent development |
| AI Foundry Project 2 | Second team-scoped project under the Foundry Resource for agent development |
| Model Deployments | 15 models across Standard, DataZoneStandard, and GlobalStandard SKUs (see Model Deployments section) |
| Azure AI Search | Grounding and vector search for agent knowledge |
| Azure Blob Storage | Grounding corpus, agent artifacts, file storage |
| Azure Cosmos DB | Serverless — agent memory and session state |
| Azure Key Vault | RBAC-enabled, soft-delete + purge protection for secrets |
| Grounding with Bing Search | Web grounding for agents via Bing Search API (G1 SKU) |
| Log Analytics Workspace | Shared observability workspace |
| Application Insights | Telemetry linked to Log Analytics |
| Diagnostic Settings | Enabled for all services → Log Analytics |
| Budget Alert | 80% and 100% spend alerts to owner email |
| Foundry Connections | AI Search, Storage, Cosmos DB, Key Vault, App Insights, Bing Search — all AAD/MI auth (except Bing: ApiKey) |
| Capability Hosts | Agent infrastructure wiring per project (threads, storage, vector store) |
| RBAC Assignments | Account Owner group, 2× Project Dev groups, Subscription Admin group, and Managed Identity roles |
Resource Group
├── AI Foundry Resource (SystemAssigned MI)
│ ├── Project 1 (SystemAssigned MI)
│ │ └── Capability Host (Agents)
│ ├── Project 2 (SystemAssigned MI)
│ │ └── Capability Host (Agents)
│ ├── Connections
│ │ ├── AI Search (AAD)
│ │ ├── Blob Storage (AAD)
│ │ ├── Cosmos DB (AAD)
│ │ ├── Key Vault (AccountManagedIdentity)
│ │ ├── Bing Search (ApiKey)
│ │ └── App Insights (ApiKey)
│ └── Model Deployments (15 models — see below)
├── Azure AI Search
├── Azure Storage Account
├── Azure Cosmos DB (serverless)
├── Azure Key Vault
├── Grounding with Bing Search
├── Log Analytics Workspace
├── Application Insights
└── Budget Alert
Entra ID Groups
├── Account Owners → Azure AI Administrator on Foundry Resource + admin on connected services
├── Project 1 Devs → Azure AI Developer scoped to Project 1 + contributor on Cosmos DB + reader on other services
├── Project 2 Devs → Azure AI Developer scoped to Project 2 + contributor on Cosmos DB + reader on other services
└── Subscription Admins → Contributor at subscription scope
Shared infrastructure resources are prefixed with the businessUnit parameter, while Foundry projects use their own projectName/project2Name:
| Resource | Naming pattern | Example |
|---|---|---|
| Foundry Resource | {businessUnit}{suffix} |
og-01-eastus2abcd |
| Project 1 | {projectName}-proj-{suffix} |
aiteam01-proj-abcd |
| Project 2 | {project2Name}-proj-{suffix} |
aiteam02-proj-abcd |
| AI Search | {businessUnit}-search-{suffix} |
og-01-eastus2-search-abcd |
| Storage Account | {businessUnit}st{suffix} |
og01eastus2stabcd |
| Cosmos DB | {businessUnit}-cosmos-{suffix} |
og-01-eastus2-cosmos-abcd |
| Key Vault | {businessUnit}-kv-{suffix} |
og-01-eastus2-kv-abcd |
| Bing Search | {businessUnit}-bing-{suffix} |
og-01-eastus2-bing-abcd |
The {suffix} is a stable 4-character hash derived from uniqueString(resourceGroup().id). It is deterministic — the same resource group always produces the same suffix — enabling idempotent re-deploys that update resources in place rather than creating duplicates.
- Azure subscription with Owner or User Access Administrator access (needed for subscription-level RBAC)
- Four Entra ID groups created — note each Object ID:
- Account Owners group
- Project 1 Dev group
- Project 2 Dev group
- Subscription Admins group
- Azure CLI v2.60+ with Bicep extension
- Microsoft.Bing provider registered on the subscription:
az provider register --namespace Microsoft.Bing
Open main.bicepparam and replace all placeholder values:
param location = 'eastus2'
param projectName = 'aiteam01'
param project2Name = 'aiteam02'
param accountOwnerGroupObjectId = '<account-owner-group-object-id>'
param project1DevGroupObjectId = '<project1-dev-group-object-id>'
param project2DevGroupObjectId = '<project2-dev-group-object-id>'
param subscriptionAdminGroupObjectId = '<subscription-admin-group-object-id>'
param businessUnit = 'og-01-eastus2'
param costCenter = 'og-01-eastus2-cs-001'
param ownerEmail = 'owner@company.com'
param monthlyBudget = 500
// Model deployments are defined as an array — see main.bicepparam for the full list
param modelDeployments = [ ... ]az group create \
--name rg-og-01-eastus2 \
--location eastus2az deployment group create \
--resource-group rg-og-01-eastus2 \
--template-file main.bicep \
--parameters main.bicepparamThe template is idempotent — re-running the same command against the same resource group will update existing resources in place (no duplicates). This is safe for changing model TPM limits, adding connections, updating RBAC, etc.
To deploy a separate environment, create a new resource group:
az group create --name rg-og-02-eastus2 --location eastus2
az deployment group create \
--resource-group rg-og-02-eastus2 \
--template-file main.bicep \
--parameters main.bicepparamEach resource group generates a unique suffix, so globally-scoped resources (Storage, Cosmos DB, Key Vault, AI Search, Foundry) won't collide.
| Resource | Role |
|---|---|
| Foundry Resource | Azure AI Administrator |
| AI Search | Search Service Contributor |
| Blob Storage | Storage Blob Data Contributor |
| Cosmos DB | Cosmos DB Operator |
| Key Vault | Key Vault Secrets Officer |
| Resource | Role |
|---|---|
| Assigned Foundry Project | Azure AI Developer |
| AI Search | Search Index Data Reader |
| Blob Storage | Storage Blob Data Reader |
| Cosmos DB | Cosmos DB Built-in Data Contributor |
| Key Vault | Key Vault Secrets User |
Dev groups are scoped to their specific project only — teams are isolated from each other at the Foundry level. Cosmos DB write access enables agent memory and session state operations.
| Resource | Role |
|---|---|
| Entire subscription | Contributor |
Members can provision any resource in the subscription. Does not include RBAC management (Owner role would be needed for that).
| Identity | Roles |
|---|---|
| Foundry MI | Search Index Data Contributor, Search Service Contributor, Storage Blob Data Contributor, Cosmos DB Operator + Data Contributor, Key Vault Secrets User |
| Project 1 MI | Storage Blob Data Contributor, Search Index Data Contributor, Search Service Contributor, Cosmos DB Operator + Data Contributor |
| Project 2 MI | Storage Blob Data Contributor, Search Index Data Contributor, Search Service Contributor, Cosmos DB Operator + Data Contributor |
| Guardrail | Mechanism | Details |
|---|---|---|
| LLM rate limit | TPM cap per model deployment | Each model set to 25% of subscription quota max |
| Budget alert | Azure Budget at 80% and 100% | Configurable via monthlyBudget (default $500/mo), emails ownerEmail |
| AI Search scale lock | Devs lack Search Service Contributor | Cannot add partitions/replicas — locked to Standard 1×1 |
| Cosmos DB storage cap | Serverless 1 TB limit | Inherent platform limit — no additional config needed |
| Bing Search | G1 pay-per-call | 1,000 free transactions/month; usage driven by agent calls |
| Storage | Devs have read-only access | Cannot upload data directly; writes flow through Foundry MI |
The budget is notification-only — it alerts the owner but does not stop spending. For automated enforcement, add an Action Group with an Azure Function or Logic App.
15 models deployed across three SKU types, each set to 25% of subscription quota max. Models are deployed sequentially via @batchSize(1).
| Deployment Name | Model | Version | Capacity (K TPM) |
|---|---|---|---|
gpt-4-1 |
gpt-4.1 | 2025-04-14 | 250 |
o4-mini |
o4-mini | 2025-04-16 | 250 |
text-embedding-3-large |
text-embedding-3-large | 1 | 87 |
| Deployment Name | Model | Version | Capacity |
|---|---|---|---|
gpt-5-4-dz |
gpt-5.4 | 2026-03-05 | 75K TPM |
gpt-5-mini-dz |
gpt-5-mini | 2025-08-07 | 75K TPM |
gpt-5-nano-dz |
gpt-5-nano | 2025-08-07 | 500K TPM |
model-router-dz |
model-router | 2025-11-18 | 75K TPM |
o3-dz |
o3 | 2025-04-16 | 75K TPM |
gpt-image-1-5-dz |
gpt-image-1.5 | 2025-12-16 | 1 (concurrent requests) |
text-embedding-3-small-dz |
text-embedding-3-small | 1 | 250K TPM |
text-embedding-3-large-dz |
text-embedding-3-large | 1 | 250K TPM |
| Deployment Name | Model | Version | Capacity (K TPM) |
|---|---|---|---|
gpt-5-3-chat-gs |
gpt-5.3-chat | 2026-03-03 | 250 |
gpt-5-3-codex-gs |
gpt-5.3-codex | 2026-02-24 | 250 |
gpt-5-1-codex-mini-gs |
gpt-5.1-codex-mini | 2025-11-13 | 250 |
Note: Some models require registration before deployment: gpt-5.4 & gpt-5.3-codex, gpt-image-1.5.
| Step | Module | Description | Dependencies |
|---|---|---|---|
| 1 | ai-search, storage-account, cosmos-db, key-vault |
Foundation services (parallel) | None |
| 2 | ai-foundry |
Foundry Resource + 2 Projects + 15 Model deployments | Step 1 |
| 3 | observability |
Log Analytics, App Insights, Diagnostic Settings | Steps 1–2 |
| 4 | rbac-managed-identity |
Foundry Resource & Project MI role assignments | Step 2 |
| 5 | rbac-account-owner-group |
Account Owner Entra ID group | Step 2 |
| 6 | rbac-project-dev-group (×1) |
Project 1 Dev group | Step 2 |
| 7 | rbac-project-dev-group (×2) |
Project 2 Dev group | Step 2 |
| 8 | rbac-subscription-admin |
Subscription-scoped Contributor | None |
| 9 | foundry-connections |
Register 5 connections on Foundry Resource | Steps 3–4 |
| 10 | capability-host (×2) |
Agent infrastructure per project | Steps 4, 9 |
| 11 | bing-grounding |
Bing Search resource + Foundry connection | Step 4 |
| 12 | budget |
Monthly budget alert | None |
baseline-dev-enablement/
├── main.bicep # Orchestrator
├── main.bicepparam # Parameters file
├── README.md # This file
├── architecture-diagram.md # Mermaid architecture diagram
└── modules/
├── ai-foundry.bicep # Foundry Resource + 2 Projects + Model
├── ai-search.bicep # AI Search service
├── storage-account.bicep # Blob Storage
├── cosmos-db.bicep # Cosmos DB (serverless)
├── key-vault.bicep # Key Vault
├── bing-grounding.bicep # Grounding with Bing Search + Foundry connection
├── observability.bicep # Log Analytics + App Insights + Diagnostics
├── budget.bicep # Budget alert
├── foundry-connections.bicep # All Foundry connections (AAD/MI auth)
├── capability-host.bicep # Agent capability host (reusable per project)
├── rbac-account-owner-group.bicep # Account Owner group role assignments
├── rbac-project-dev-group.bicep # Project Dev group role assignments (reusable)
├── rbac-subscription-admin.bicep # Subscription Admin group (subscription scope)
├── rbac-managed-identity.bicep # Foundry Resource + Project 1 + Project 2 MI role assignments
├── rbac-foundry-owner.bicep # (available) Single-user owner role assignments
└── rbac-team-group.bicep # (available) Single team group role assignments
- Entra ID (AAD) auth only — local auth / API keys disabled on every service that supports it (see section below).
- Group-based RBAC — four Entra ID groups replace individual user/group assignments for scalable access management.
- Project isolation — each dev group is scoped to its own project; teams cannot see each other's Foundry artifacts.
- Serverless Cosmos DB — cost-efficient for POC/dev scale; no provisioned throughput to manage. Devs have data-plane contributor access for agent memory operations.
- System-assigned managed identities — Foundry Resource and both projects get their own MI for least-privilege access.
- BusinessUnit-based naming — shared infrastructure resources (AI Search, Storage, Cosmos DB, Key Vault, Bing) are prefixed with
businessUnit; only Foundry projects use their project-specific names. - Idempotent deploys — stable
uniqueSuffixderived from resource group ID enables re-deploys that update in place without creating duplicates. - Grounding with Bing Search — web grounding available to agents via G1 SKU with ApiKey-based Foundry connection.
- Tags cascade — applied at the resource group level using
Microsoft.Resources/tags. - API version
2025-09-01— latest stable GA for all CognitiveServices resource types.
This deployment enforces Entra ID (AAD) authentication across every service, with local auth and shared keys disabled. This is the enterprise-recommended security pattern for the following reasons:
- Eliminates shared secrets — API keys and shared access keys are static credentials that can be copied, leaked in source control, or exfiltrated. Disabling them removes this entire attack surface.
- Centralized identity governance — all access flows through Entra ID, enabling Conditional Access policies, Multi-Factor Authentication (MFA), and Privileged Identity Management (PIM) to apply uniformly.
- Full audit trail — every data-plane and control-plane operation is tied to a named identity in Entra ID sign-in and audit logs, satisfying SOC 2, ISO 27001, and FedRAMP logging requirements.
- Automated credential lifecycle — managed identities and Entra ID tokens are rotated automatically by the platform. No manual key rotation schedules or secrets to manage.
- Least-privilege by default — RBAC role assignments grant only the specific permissions needed, scoped to the exact resource. Keys typically grant full access with no scoping.
- Compliance alignment — Microsoft's own Well-Architected Framework, Azure Security Benchmark, and CIS Azure Foundations Benchmark all recommend disabling local auth in favor of Entra ID.
| Resource | Setting | Effect |
|---|---|---|
| AI Foundry | disableLocalAuth: true |
API keys disabled; Entra ID required |
| AI Search | disableLocalAuth: true |
Admin/query keys disabled; Entra ID required |
| Cosmos DB | disableLocalAuth: true |
Primary/secondary keys disabled; Entra ID required |
| Storage Account | allowSharedKeyAccess: false |
Shared key and SAS disabled; Entra ID required |
| Key Vault | enableRbacAuthorization: true |
Access policies disabled; RBAC-only via Entra ID |
| App Insights Connection | authType: 'ApiKey' |
Exception — connection string passed as credential* |
* The Application Insights Foundry connection category only supports
ApiKeyauth type. This is the sole exception — no AAD auth option exists for this connection type. The connection string is not a data-plane secret; it controls where telemetry is sent, not who can read it. Read access to telemetry data is still governed by RBAC on the Application Insights resource.
The model deployment is configurable via parameters. Defaults are suitable for most dev/POC teams.
| Parameter | Default | Description |
|---|---|---|
modelName |
gpt-4.1 |
Model to deploy |
modelFormat |
OpenAI |
Provider format |
modelVersion |
2025-04-14 |
Model version |
modelDeploymentType |
GlobalStandard |
Deployment SKU type |
modelTpmLimit |
40 |
TPM limit in thousands (40 = 40K TPM) |
| Type | Description |
|---|---|
Standard |
Single-region deployment with dedicated capacity |
GlobalStandard |
Multi-region load-balanced deployment (default — best availability) |
DataZoneStandard |
Data-zone-scoped deployment for data residency requirements |
To customize, update the values in main.bicepparam:
param modelName = 'gpt-4.1'
param modelDeploymentType = 'GlobalStandard' // Standard | GlobalStandard | DataZoneStandard
param modelTpmLimit = 40 // TPM in thousands (e.g., 40 = 40K TPM)An Account Owner should:
- Open the Azure AI Foundry portal
- Verify both projects are visible under the Foundry Resource
- Verify each connection is visible under Connected Resources
- Test model access with a sample prompt in the Playground
- Confirm Project 1 Dev group members can access Project 1 (but not Project 2)
- Confirm Project 2 Dev group members can access Project 2 (but not Project 1)
- Confirm Subscription Admin group members can provision resources in the subscription