
Azure Enterprise Infra Planner
- 317k installs
- 1.3k repo stars
- Updated July 26, 2026
- microsoft/azure-skills
azure-enterprise-infra-planner is a skill that architects enterprise Azure infrastructure, generates Bicep or Terraform code, and validates against Well-Architected Framework guidelines.
About
Architects enterprise Azure infrastructure from workload descriptions. Generates Bicep or Terraform for subscription-scope deployments, landing zones, hub-spoke networks, and multi-region topologies while validating against WAF guidelines.
- Generates Bicep or Terraform directly from workload descriptions
- Covers landing zones, hub-spoke networks, multi-region DR, and WAF alignment
- Includes MCP tools for insights, best practices, and Well-Architected Framework validation
Azure Enterprise Infra Planner by the numbers
- 317,382 all-time installs (skills.sh)
- +20,335 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #13 of 1,041 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
azure-enterprise-infra-planner capabilities & compatibility
- Capabilities
- architecture · iac generation · waf validation
- Works with
- azure · azure devops · terraform
- Use cases
- devops · code review
What azure-enterprise-infra-planner says it does
Architect and provision enterprise Azure infrastructure from workload descriptions. For cloud architects and platform engineers planning networking, identity, security, compliance, and multi-resource
Generate Bicep or Terraform for subscription-scope or multi-resource-group deployments
npx skills add https://github.com/microsoft/azure-skills --skill azure-enterprise-infra-plannerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 317k |
|---|---|
| repo stars | ★ 1.3k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 26, 2026 |
| Repository | microsoft/azure-skills ↗ |
How do you plan enterprise Azure landing zones?
Plan and generate infrastructure-as-code for enterprise Azure deployments
Who is it for?
Cloud architects and platform engineers designing subscription-scope Azure topologies with networking, DR, and compliance requirements.
Skip if: App-centric Azure Developer CLI workflows—use azure-prepare instead—or small single-resource deployments without enterprise networking.
When should I use this skill?
User asks to plan Azure infrastructure, architect a landing zone, design hub-spoke networks, or generate subscription-scope Bicep or Terraform.
What you get
Enterprise Azure infrastructure plans with networking, identity, security, compliance, and Bicep or Terraform definitions.
- infrastructure architecture plan
- Bicep templates
- Terraform configurations
By the numbers
- 7 phases of infrastructure planning
- WAF service guide validation
Files
Azure Enterprise Infra Planner
When to Use This Skill
Activate this skill when user wants to:
- Plan enterprise Azure infrastructure from a workload or architecture description
- Architect a landing zone, hub-spoke network, or multi-region topology
- Design networking infrastructure: VNets, subnets, firewalls, private endpoints, VPN gateways
- Plan identity, RBAC, and compliance-driven infrastructure
- Generate Bicep or Terraform for subscription-scope or multi-resource-group deployments
- Plan disaster recovery, failover, or cross-region high-availability topologies
Quick Reference
| Property | Details |
|---|---|
| MCP tools | insights_get, get_azure_bestpractices_get, wellarchitectedframework_serviceguide_get, microsoft_docs_fetch, microsoft_docs_search, bicepschema_get |
| CLI commands | az deployment group create, az bicep build, az resource list, terraform init, terraform plan, terraform validate, terraform apply |
| Output schema | schema.md |
| Key references | workflow.md, waf-checklist.md, resources/, constraints/ |
Workflow (Start Here)
Follow the step-by-step instructions in workflow.md to execute the 7 phases of infrastructure planning and provisioning.
MCP Tools
| Tool | Purpose |
|---|---|
insights_get | Retrieve insights about the user's existing Azure environment to guide planning decisions |
get_azure_bestpractices_get | Azure best practices for code generation, operations, and deployment |
wellarchitectedframework_serviceguide_get | WAF service guide for a specific Azure service |
microsoft_docs_search | Search Microsoft Learn for relevant documentation chunks |
microsoft_docs_fetch | Fetch full content of a Microsoft Learn page by URL |
bicepschema_get | Bicep schema definition for any Azure resource type (latest API version) |
Error Handling
| Error | Cause | Fix |
|---|---|---|
| MCP tool error or not available | Tool call timeout, connection error, or tool doesn't exist | Retry once; fall back to reference files and notify user if unresolved |
| Plan approval missing | meta.status is not approved | Stop and prompt user for approval before IaC generation or deployment |
| IaC validation failure | az bicep build or terraform validate returns errors | Fix the generated code and re-validate; notify user if unresolved |
| Pairing constraint violation | Incompatible SKU or resource combination | Fix in plan before proceeding to IaC generation |
| Infra plan or IaC files not found | Files written to wrong location or not created | Verify files exist at <project-root>/.azure/ and <project-root>/infra/; if missing, re-create the files by following workflow.md exactly |
Bicep Generation
Generate Bicep IaC files from the approved infrastructure plan.
Important: All Bicep files must be created under<project-root>/infra/. Never place.bicepfiles in the project root or in.azure/.
File Structure
Generate files under <project-root>/infra/:
infra/
├── main.bicep # Orchestrator — deploys all modules
├── main.bicepparam # Parameter values
└── modules/
├── storage.bicep # One module per resource or logical group
├── compute.bicep
├── networking.bicep
└── monitoring.bicepGeneration Steps
1. Create infra/ directory — create <project-root>/infra/ and <project-root>/infra/modules/ directories. All files in subsequent steps go here. 2. Read plan — load <project-root>/.azure/infrastructure-plan.json, verify meta.status === "approved" 3. Fetch Bicep schemas — for each resource in the plan, use a sub-agent to call bicepschema_get with resource-type set to the ARM type from the relevant resources/ category file (e.g., Microsoft.ContainerService/managedClusters). Instruct the sub-agent: "Return the full property structure for {ARM type}: required properties, allowed values, child resources. ≤500 tokens." Use this output — not training data — to generate correct resource definitions.
The schema tool returns only the schema for the exact type requested. Sub-resource types (e.g.,Microsoft.Network/virtualNetworks/subnets) return a smaller, focused schema but miss parent-level properties (e.g., VNetencryptionlives on the parent, not the subnet sub-resource). Strategy:
- Start with sub-resource types when validating child resources — smaller responses (~25KB vs ~95KB), easier to summarize
- Fetch the parent type separately when you need parent-level properties (encryption, tags, SKU) — delegate to a sub-agent with specific property extraction instructions to manage the large response
4. Generate modules — group resources by category; one .bicep file per group under infra/modules/. Use the schema from step 3 for property names, allowed values, and required fields. 5. Generate main.bicep — write infra/main.bicep that imports all modules and passes parameters 6. Generate parameters — create infra/main.bicepparam with environment-specific values
Bicep Conventions
- Use
@description()decorators on all parameters - Use
@secure()for secrets and connection strings - Choose
targetScopeinmain.bicepbased on the deployment plan: - For single resource group deployments, set
targetScope = 'resourceGroup'and deploy withaz deployment group create. - For subscription-scope deployments (for example, resources across multiple resource groups or subscription-level resources), set
targetScope = 'subscription'and deploy withaz deployment sub create. - Use
existingkeyword for referencing pre-existing resources - Output resource IDs and endpoints needed by other resources
- Use
dependsOnonly when implicit dependencies are insufficient
Parameter File Format
using './main.bicep'
param location = 'eastus'
param environmentName = 'prod'
param workloadName = 'datapipeline'Multi-Environment
For multi-environment plans, generate one parameter file per environment:
infra/
├── main.bicep
├── main.dev.bicepparam
├── main.staging.bicepparam
└── main.prod.bicepparamValidation Before Deployment
Run az bicep build --file infra/main.bicep to validate syntax before deploying.
AI & ML Pairing Constraints
AI Search
| Paired With | Constraint |
|---|---|
| Cognitive Services (AI Enrichment) | For AI enrichment pipelines (skillsets), attach a Cognitive Services account. Must be kind: 'CognitiveServices' or kind: 'AIServices' and in the same region as the search service. |
| Storage Account (Indexers) | Indexer data sources support Blob, Table, and File storage. Storage must be accessible (same VNet or public). For managed identity access, assign Storage Blob Data Reader role. |
| Cosmos DB (Indexers) | Indexer data source for Cosmos DB. Requires connection string or managed identity with Cosmos DB Account Reader Role. |
| SQL Database (Indexers) | Indexer data source. Requires change tracking enabled on the source table. |
| Private Endpoints | When publicNetworkAccess: 'Disabled', create shared private link resources for outbound connections to data sources. |
| Managed Identity | Assign system or user-assigned identity for secure connections to data sources. Use RBAC instead of connection strings. |
| Semantic Search | Requires semanticSearch property set to free or standard. Available on basic and above SKUs. |
Cognitive Services
| Paired With | Constraint |
|---|---|
| Azure OpenAI Deployments | When kind: 'OpenAI' or kind: 'AIServices', create model deployments as child resource accounts/deployments. |
| Microsoft Entra ID Auth | Requires customSubDomainName to be set. Without it, only API key auth works. |
| Private Endpoint | Requires customSubDomainName. Set publicNetworkAccess: 'Disabled' and configure private DNS zone. |
| Key Vault (CMK) | When using customer-managed keys, Key Vault must have soft-delete and purge protection enabled. Set encryption.keySource: 'Microsoft.KeyVault'. |
| Storage Account | When using userOwnedStorage, the storage account must be in the same region. Required for certain features (e.g., batch translation). |
| AI Foundry Hub | When kind: 'AIServices' with allowProjectManagement: true, can manage Foundry projects as child resources (accounts/projects). |
| VNet Integration | Configure networkAcls with defaultAction: 'Deny' and add virtual network rules. Set bypass: 'AzureServices' to allow trusted Azure services. |
ML Workspace
| Paired With | Constraint |
|---|---|
| Storage Account | Must be linked via properties.storageAccount. Cannot change after creation. Use StorageV2 kind with standard SKU. |
| Key Vault | Must be linked via properties.keyVault. Cannot change after creation. Requires soft-delete enabled. |
| Application Insights | Linked via properties.applicationInsights. Should use workspace-based App Insights (backed by Log Analytics). |
| Container Registry | Optional but recommended for custom environments. Linked via properties.containerRegistry. |
| Hub workspace (kind=Project) | Must set properties.hubResourceId to the parent Hub's ARM resource ID. The Project inherits the Hub's linked resources. |
| VNet Integration | When managedNetwork.isolationMode is AllowOnlyApprovedOutbound, must configure outbound rules for all dependent services. |
Compute (PaaS) Pairing Constraints
App Service
| Paired With | Constraint |
|---|---|
| App Service Plan | Must be in the same region. Linux apps need Linux plan (reserved: true). Windows apps need Windows plan. |
| Deployment Slots | Only available on Standard or higher plan tiers. Free and Basic do not support slots. |
| VNet Integration | Requires Basic or higher plan tier. Subnet must be delegated to Microsoft.Web/serverFarms. VNet integration subnet must be a different subnet than any Private Endpoint subnet. |
| Private Endpoints | Requires Basic or higher plan tier. Not available on Free or Shared tiers. |
| Custom Domain | Requires Shared (D1) or higher tier for custom domains. Free tier only supports *.azurewebsites.net. Managed certificates require Basic or higher. |
| Application Insights | Set APPLICATIONINSIGHTS_CONNECTION_STRING in app settings. |
| Key Vault References | Use @Microsoft.KeyVault(SecretUri=...) in app settings. Requires managed identity with Key Vault access. |
| Managed Identity | Enable identity.type: 'SystemAssigned' or 'UserAssigned' for passwordless auth to other Azure resources. |
App Service Plan
| Paired With | Constraint |
|---|---|
| Function App | Consumption (Y1) and Flex (FC1) plans cannot be shared with web apps. EP plans can host both functions and web apps. |
| Linux Apps | Linux plan (reserved: true) cannot host Windows apps and vice versa. |
| Zone Redundancy | Requires Premium v3 (P1v3+) or Isolated v2. Minimum 3 instances. |
| Deployment Slots | Slots share plan capacity. Standard+ tier required. Slots are not available on Free/Basic. |
| Auto-scale | Not available on Free/Shared/Basic. Standard+ required for manual scale, auto-scale. |
| VNet Integration | Requires Basic or higher. Subnet must be delegated to Microsoft.Web/serverFarms. Minimum subnet size /28 (or /26 for multi-plan subnet join). VNet integration subnet must be a different subnet than any Private Endpoint subnet. |
| Private Endpoints | Requires Basic tier or higher. Not available on Free or Shared tiers. |
| Isolated Compute | Dedicated single-tenant compute requires IsolatedV2 (I1v2+) tier. |
| Free/Shared Tiers | Free (F1) and Shared (D1) use shared compute with no VNet integration, no private endpoints, no deployment slots, no Always On, and no auto-scale. Managed Identity is available but limited. |
Container App
| Paired With | Constraint |
|---|---|
| Container Apps Environment | Must reference environmentId. Environment must exist in the same region. |
| VNet | VNet integration is configured on the Environment, not the individual app. Environment needs a dedicated subnet with minimum /23 prefix for Consumption-only environments or /27 for workload profiles environments. |
| Container Registry | Requires registry credentials in configuration.registries[] or managed identity-based pull. |
| Dapr | Enable via configuration.dapr.enabled: true. Dapr components are configured on the Environment. |
| CPU/Memory | CPU and memory must follow valid combinations: 0.25 cores/0.5Gi, 0.5/1Gi, 1/2Gi, 2/4Gi, 4/8Gi (consumption). |
| Scale Rules | KEDA-based scale rules reference secrets by name — secrets must be defined in configuration.secrets[]. |
Container Apps Environment
| Paired With | Constraint |
|---|---|
| Container App | Container Apps reference the environment via properties.environmentId. Apps and environment must be in the same region. |
| Log Analytics Workspace | Provide customerId and sharedKey in appLogsConfiguration. Workspace must exist before the environment. |
| VNet / Subnet | Subnet must have a minimum /23 prefix for Consumption-only environments or /27 for workload profiles environments. Subnet must be dedicated to the Container Apps Environment (no other resources). Workload Profiles: subnet must be delegated to Microsoft.App/environments. Consumption-only: subnet MUST NOT be delegated to any service. |
| Zone Redundancy | Requires VNet integration. Zone-redundant environments need a /23 subnet in a region with availability zones. |
| Internal Environment | When internal: true, no public endpoint is created. Requires custom DNS or Private DNS Zone and a VNet with connectivity to clients. |
| Workload Profiles | At least one Consumption profile must be defined when using workload profiles. Dedicated profiles require minimumCount and maximumCount. |
| Workload Profiles vs Consumption-only | UDR support, NAT Gateway egress, private endpoints, and remote gateway peering are only available with Workload Profiles environments — not Consumption-only. |
| Network Immutability | Network type (Workload Profiles vs Consumption-only) is immutable after creation. Cannot change between environment types. |
| IPv6 | IPv6 is not supported for either Workload Profiles or Consumption-only environments. |
| VNet Move | VNet-integrated environments cannot be moved to a different resource group or subscription while in use. |
Container Registry
| Paired With | Constraint |
|---|---|
| AKS | AKS needs acrPull role assignment on the registry. Use managed identity (attach via az aks update --attach-acr). |
| Container App | Reference in configuration.registries[]. Use managed identity or admin credentials. |
| ML Workspace | Referenced as containerRegistry property. Used for custom training/inference images. |
| Private Endpoint | Premium SKU required. Set publicNetworkAccess: 'Disabled'. |
| Geo-Replication | Premium SKU required. Configure via child replications resource. |
| CMK | Premium SKU required. Needs user-assigned identity with Key Vault access. |
Function App
| Paired With | Constraint |
|---|---|
| Storage Account | Must use StorageV2 or Storage kind. BlobStorage, BlockBlobStorage, FileStorage not supported (need Queue + Table). |
| Storage (Consumption) | Consumption plan cannot use VNet-secured storage. Only Premium/Dedicated support VNet-restricted storage. |
| Storage (ZRS) | Zone-redundant functions require Standard_ZRS storage SKU. |
| App Service Plan | Plan must be in the same region. Linux functions need Linux plan (reserved: true). |
| VNet Integration | Requires Premium (EP) or Dedicated plan. Consumption does not support VNet integration (use Flex Consumption). |
| Application Insights | Set APPINSIGHTS_INSTRUMENTATIONKEY or APPLICATIONINSIGHTS_CONNECTION_STRING in app settings. |
| Key Vault References | App settings can use @Microsoft.KeyVault(SecretUri=...) syntax. Requires managed identity with Key Vault access. |
Static Web App
| Paired With | Constraint |
|---|---|
| GitHub Repository | Provide repositoryUrl, branch, and repositoryToken. A GitHub Actions workflow is auto-created in the repo. |
| Azure DevOps | Set provider: 'DevOps'. Provide repositoryUrl and branch. Pipeline is configured separately. |
| Azure Functions (managed) | API location in buildProperties.apiLocation deploys a managed Functions backend. Limited to HTTP triggers, C#, JavaScript, Python, Java. |
| Linked Backend | Use linkedBackends child resource to connect an existing Function App, Container App, or App Service as the API backend. Standard SKU required. |
| Private Endpoint | Only available with Standard SKU. Set up a Private Endpoint to restrict access to the static web app. |
| Custom Domain | Custom domains are child resources. Require DNS CNAME or TXT validation. Free SSL certificates are auto-provisioned. |
| Enterprise-Grade CDN | Standard SKU only. Enables Azure Front Door integration for advanced caching and edge capabilities. |
Compute (IaaS) Pairing Constraints
AKS Cluster
| Paired With | Constraint |
|---|---|
| VNet / Subnet | With Azure CNI, subnet must have enough IPs for nodes + pods (30 pods/node default × node count). Subnet cannot have other delegations. Reserved CIDR ranges cannot be used: 169.254.0.0/16, 172.30.0.0/16, 172.31.0.0/16, 192.0.2.0/24. |
| Pod CIDR | Pod CIDR must not overlap with cluster subnet, peered VNets, ExpressRoute, or VPN address spaces. Overlapping causes SNAT/routing issues. |
| kubenet | Kubenet uses NAT — subnet only needs IPs for nodes. Less IP pressure but no direct pod-to-VNet connectivity. Kubenet is retiring March 2028 — migrate to CNI Overlay. Not supported by Application Gateway for Containers. |
| CNI Overlay | CNI Overlay does not support VM availability sets (must use VMSS-based node pools), virtual nodes, or DCsv2-series VMs (use DCasv5/DCadsv5 instead). |
| Dual-stack CNI Overlay | IPv4+IPv6 dual-stack disables Azure/Calico network policies, NAT gateway, and virtual nodes. |
| Key Vault | Enable azureKeyvaultSecretsProvider addon. Use enableRbacAuthorization: true on Key Vault with managed identity. |
| Container Registry | Attach ACR via acrPull role assignment on cluster identity, or use imagePullSecrets. |
| Log Analytics | Enable omsagent addon with config.logAnalyticsWorkspaceResourceID pointing to workspace. |
| Load Balancer | AKS creates a managed Standard LB by default (loadBalancerSku: 'standard'). |
| System Pool | At least one agent pool must have mode: 'System'. System pools run critical pods (CoreDNS, tunnelfront). |
Availability Set
| Paired With | Constraint |
|---|---|
| Virtual Machine | VMs must be in the same resource group. Set vm.properties.availabilitySet.id. |
| Availability Zones | Cannot combine with zones — availability zones supersede availability sets for zone-redundant architectures. |
| Managed Disks | sku.name must be Aligned when VMs use managed disks. |
| VM Scale Set | A VM cannot be in both an availability set and a VMSS. |
Managed Disk
| Paired With | Constraint |
|---|---|
| Virtual Machine | Attach via storageProfile.osDisk or storageProfile.dataDisks. Disk must be in same region. |
| Availability Zone | PremiumV2_LRS and UltraSSD_LRS require zone specification. |
| Premium SSD v2 | Cannot be used as OS disk (data disks only). Does not support host caching (ReadOnly/ReadWrite unavailable). Requires zonal VM deployment. Cannot mix with other storage types on SQL Server VMs. |
| Key Vault (CMK) | Requires a Disk Encryption Set pointing to Key Vault key. Key Vault must have purge protection enabled. |
Virtual Machine
| Paired With | Constraint |
|---|---|
| NIC | At least one NIC required via networkProfile.networkInterfaces. NIC must be in the same region. |
| Availability Set | Cannot combine with virtualMachineScaleSet or availability zones. Set availabilitySet.id. |
| Availability Zone | Cannot combine with availability sets. Set zones: ['1'] (string array). |
| Managed Disk (Premium SSD) | Not all VM sizes support Premium storage — check size docs for compatibility. |
| Managed Disk (UltraSSD) | Requires additionalCapabilities.ultraSSDEnabled: true. Cannot enable on a running VM — requires stop/deallocate first. |
| Managed Disk (Premium SSD v2) | Premium SSD v2 cannot be used as OS disk (data disks only). Does not support host caching (ReadOnly/ReadWrite unavailable). Requires zonal VM deployment. Cannot mix Premium SSD v2 with other storage types on SQL Server VMs. |
| Dedicated Host | Cannot specify both host and hostGroup. |
| Boot Diagnostics Storage | Cannot use Premium or ZRS storage. Use Standard_LRS or Standard_GRS. |
| CNI Overlay (AKS) | DCsv2-series VMs are not supported with Azure CNI Overlay. Use DCasv5/DCadsv5 for confidential computing. |
VM Scale Set
| Paired With | Constraint |
|---|---|
| Subnet | Network interfaces defined inline in virtualMachineProfile.networkProfile. Subnet must be in same region. |
| Load Balancer | Reference backend pool ID in NIC IP configuration. |
| Orchestration Mode | Flexible is the modern default. Uniform requires upgradePolicy. |
| Availability Zone | Set zones: ['1', '2', '3'] for zone distribution. Cannot combine with availability sets. |
Data (Analytics) Pairing Constraints
Cosmos DB
| Paired With | Constraint |
|---|---|
| Multi-region writes | consistencyPolicy.defaultConsistencyLevel cannot be Strong when enableMultipleWriteLocations: true. |
| Strong consistency | Strong consistency with regions >5000 miles apart is blocked by default (requires support ticket to enable). Strong and Bounded Staleness reads cost 2× RU/s compared to Session/Consistent Prefix/Eventual. |
| Serverless | Cannot combine EnableServerless capability with multi-region writes or analytical store. Serverless is single-region only — cannot add regions. No shared throughput databases. Cannot provision throughput (auto-managed; settings return error). Merge partitions not available for serverless accounts. |
| Free tier | Only one free-tier account per subscription. Cannot combine with multi-region writes. |
| VNet | Set isVirtualNetworkFilterEnabled: true and configure virtualNetworkRules[] with subnet IDs. Subnets need Microsoft.AzureCosmosDB service endpoint. |
| Private Endpoint | Set publicNetworkAccess: 'Disabled' when using private endpoints exclusively. One Private DNS Zone record per DNS name — multiple private endpoints in different regions need separate Private DNS Zones. |
| Key Vault (CMK) | Requires keyVaultKeyUri in encryption config. Key Vault must be in same region. |
| Merge Partitions | Not available for serverless or multi-region write accounts. Single-region provisioned throughput only. |
Redis Cache
| Paired With | Constraint |
|---|---|
| VNet | Only Premium SKU supports VNet injection via subnetId. Basic/Standard use firewall rules only. |
| VNet + Private Endpoint | VNet injection and private endpoint are mutually exclusive — cannot use both on the same cache. |
| Private Endpoint | Available for Basic, Standard, Premium, and Enterprise tiers. Set publicNetworkAccess: 'Disabled' when using private endpoints. Premium with clustering supports max 1 private link; non-clustered supports up to 100. |
| Clustering | Only Premium SKU supports shardCount. Basic and Standard are single-node/two-node only. |
| Persistence | Only Premium SKU supports RDB/AOF persistence. Requires a storage account for RDB exports. |
| Geo-replication | Only Premium SKU. Primary and secondary must be Premium with same shard count. Passive geo-replication with private endpoints requires unlinking geo-replication first, adding private link, then re-linking. |
| Zones | Zone redundancy requires Premium SKU with multiple replicas. |
| Tier Scaling | Cannot scale down tiers (Enterprise → lower, Premium → Standard/Basic, Standard → Basic). Cannot scale between Enterprise and Enterprise Flash, or from Basic/Standard/Premium to Enterprise/Flash — must create a new cache. |
| Enterprise/Flash | Firewall rules and publicNetworkAccess flag are not available on Enterprise/Enterprise Flash tiers. |
| Azure Lighthouse | Azure Lighthouse + VNet injection is not supported. Use private links instead. |
Storage Account
| Paired With | Constraint |
|---|---|
| Azure Functions | Must use StorageV2 or Storage kind. BlobStorage, BlockBlobStorage, FileStorage not supported (missing Queue/Table). |
| Functions (Consumption plan) | Cannot use network-secured storage (VNet rules). Only Premium/Dedicated plans support VNet-restricted storage. |
| Functions (zone-redundant) | Must use ZRS SKU (Standard_ZRS). LRS/GRS not sufficient. |
| VM Boot Diagnostics | Cannot use Premium storage or ZRS. Use Standard_LRS or Standard_GRS. Managed boot diagnostics (no storage account required) is also available. |
| CMK Encryption | Key Vault must have enableSoftDelete: true AND enablePurgeProtection: true. |
| CMK at creation | Requires user-assigned managed identity (system-assigned only works for existing accounts). |
| Geo-redundant failover | Certain features (SFTP, NFS 3.0, etc.) block GRS/GZRS failover. |
Data Factory
| Paired With | Constraint |
|---|---|
| Storage Account | Linked service requires Storage Blob Data Contributor role on the storage account for the ADF managed identity. For ADLS Gen2, also requires Storage Blob Data Reader at minimum. |
| Key Vault | For CMK encryption, Key Vault must have enableSoftDelete: true and enablePurgeProtection: true. ADF managed identity needs Key Vault Crypto Service Encryption User role or equivalent access policy. |
| Managed VNet | When managedVirtualNetworks is configured, all outbound connections must use managed private endpoints (factories/managedVirtualNetworks/managedPrivateEndpoints). |
| Private Endpoint | When publicNetworkAccess: 'Disabled', must create private endpoint to dataFactory sub-resource for studio access and pipeline connectivity. |
| Purview | Requires Microsoft Purview instance resource ID. ADF managed identity must have Data Curator role in Purview. |
| Integration Runtime | Self-hosted IR requires network line-of-sight to on-premises sources. Azure IR regional choice affects data residency. |
Synapse Workspace
| Paired With | Constraint |
|---|---|
| ADLS Gen2 Storage Account | Required. Storage account must have isHnsEnabled: true (hierarchical namespace / Data Lake Storage Gen2) and kind: 'StorageV2'. Synapse managed identity needs Storage Blob Data Contributor role on the storage account. |
| Key Vault | For CMK encryption, Key Vault must have enableSoftDelete: true and enablePurgeProtection: true. Synapse managed identity needs Get, Unwrap Key, and Wrap Key permissions. |
| Managed VNet | When managedVirtualNetwork: 'default', all outbound connections require managed private endpoints. Set at creation time — cannot be changed after. |
| Private Endpoint | When publicNetworkAccess: 'Disabled', create private endpoints for sub-resources: Dev (Studio), Sql (dedicated SQL), SqlOnDemand (serverless SQL). |
| Purview | Requires Microsoft Purview resource ID. Synapse managed identity needs appropriate Purview roles. |
| VNet (compute subnet) | virtualNetworkProfile.computeSubnetId must reference an existing subnet. The subnet must be delegated to Microsoft.Synapse/workspaces if required by the deployment model. |
Data (Relational) Pairing Constraints
SQL Server
| Paired With | Constraint |
|---|---|
| SQL Database | Databases are child resources — must reference this server as parent. |
| Key Vault (TDE) | Key Vault must have enablePurgeProtection: true. Must be in same Azure AD tenant. Server needs GET, WRAP KEY, UNWRAP KEY permissions on key. TDE protector setup fails if Key Vault soft-delete and purge-protection are not both enabled. |
| Virtual Network | Use Microsoft.Sql/servers/virtualNetworkRules to restrict access to specific subnets. Subnets need Microsoft.Sql service endpoint. |
| Private Endpoint | Set publicNetworkAccess: 'Disabled' when using private endpoints exclusively. |
| Elastic Pool | Databases using elastic pools reference elasticPoolId — server must host both pool and databases. Hyperscale elastic pools cannot be created from non-Hyperscale pools. |
| Failover Group | Both primary and secondary servers must exist. Databases to be replicated must belong to the primary server. Failover group from zone-redundant to non-zone-redundant Hyperscale elastic pool fails silently (geo-secondary shows "Seeding 0%"). |
SQL Database
| Paired With | Constraint |
|---|---|
| SQL Server | Must be deployed as child of the parent SQL Server. Location must match. |
| Elastic Pool | elasticPoolId must reference a pool on the same server. Cannot set sku when using elastic pool (it inherits pool SKU). |
| Zone Redundancy | Only available in GeneralPurpose, BusinessCritical, and Hyperscale tiers. Not available in DTU tiers. General Purpose zone redundancy is only available in selected regions. Hyperscale zone redundancy can only be set at creation — cannot modify after provisioning; must recreate via copy/restore/geo-replica. |
| Serverless | Only available in GeneralPurpose tier. SKU name uses GP_S_Gen5_* pattern. |
| Hyperscale | Reverse migration from Hyperscale to General Purpose is supported within 45 days of the original migration. Databases originally created as Hyperscale cannot reverse migrate. |
| Hyperscale Elastic Pool | Cannot be created from a non-Hyperscale pool. Cannot be converted to non-Hyperscale (one-way only). Named replicas cannot be added to Hyperscale elastic pools (UnsupportedReplicationOperation). Zone-redundant Hyperscale elastic pools require databases with ZRS/GZRS backup storage — cannot add LRS-backed databases. |
| Failover Group | Failover group from zone-redundant to non-zone-redundant Hyperscale elastic pool fails silently (geo-secondary shows "Seeding 0%"). |
| Backup Redundancy | GeoZone only available in select regions. Local not available in all regions. |
MySQL Flexible Server
| Paired With | Constraint |
|---|---|
| VNet (private access) | Requires a dedicated subnet delegated to Microsoft.DBforMySQL/flexibleServers. Subnet must have no other resources. |
| Private DNS Zone | For VNet-integrated (private access) servers, use the zone name {name}.mysql.database.azure.com (not privatelink.*). The privatelink.mysql.database.azure.com zone is used for Private Endpoint connectivity only. Provide privateDnsZoneResourceId and the DNS zone must be linked to the VNet. |
| High Availability | ZoneRedundant HA requires GeneralPurpose or MemoryOptimized tier. Not available with Burstable. |
| Geo-Redundant Backup | Must be enabled at server creation time. Cannot be changed after creation. Not available in all regions. |
| Storage Auto-Grow | Storage can only grow, never shrink. Enabled by default. |
| Read Replicas | Source server must have backup.backupRetentionDays > 1. Replica count limit: up to 10 replicas. |
| Key Vault (CMK) | Customer-managed keys require user-assigned managed identity and Key Vault with purge protection enabled. |
PostgreSQL Flexible Server
| Paired With | Constraint |
|---|---|
| VNet (private access) | Requires a dedicated subnet delegated to Microsoft.DBforPostgreSQL/flexibleServers. Subnet must have no other resources. |
| Private DNS Zone | For VNet-integrated (private access) servers, use the zone name {name}.postgres.database.azure.com (not privatelink.*). The privatelink.postgres.database.azure.com zone is used for Private Endpoint connectivity only. Provide privateDnsZoneArmResourceId and the DNS zone must be linked to the VNet. |
| High Availability | ZoneRedundant HA requires GeneralPurpose or MemoryOptimized tier. Not available with Burstable. |
| Geo-Redundant Backup | Not available in all regions. Cannot be enabled with VNet-integrated (private access) servers in some configurations. |
| Storage Auto-Grow | Storage can only grow, never shrink. Minimum increase is based on current size. |
| Key Vault (CMK) | Customer-managed keys require user-assigned managed identity and Key Vault with purge protection enabled. |
Messaging Pairing Constraints
Event Grid Topic
| Paired With | Constraint |
|---|---|
| Event Subscriptions | Subscriptions are child resources. Delivery endpoints include: Webhook, Azure Function, Event Hub, Service Bus Queue/Topic, Storage Queue, Hybrid Connection. |
| Private Endpoint | Only available with Premium SKU. Set publicNetworkAccess: 'Disabled' when using private endpoints exclusively. |
| Managed Identity | Required for dead-letter destinations and delivery to Azure resources that require authentication (Event Hub, Service Bus, Storage). |
| Function App | Use Event Grid trigger binding. Subscription endpoint type is AzureFunction. Function must have Event Grid extension registered. |
| Event Hub | Subscription endpoint type is EventHub. Provide the Event Hub resource ID. Requires managed identity or connection string. |
| Storage Queue | Subscription endpoint type is StorageQueue. Provide storage account ID and queue name. |
| Dead Letter | Dead-letter destination must be a Storage blob container. Requires managed identity or storage key for access. |
Event Hub
| Paired With | Constraint |
|---|---|
| VNet | Standard, Premium, and Dedicated SKUs support VNet service endpoints and private endpoints. |
| Zone Redundancy | Available in Standard (with ≥4 TU recommended) and Premium. |
| Kafka | Kafka protocol support available in Standard and Premium only (not Basic). |
| Capture | Event capture to Storage/Data Lake available in Standard and Premium only. |
| Consumer Groups | Basic: 1 consumer group. Standard: 20. Premium: 100. Dedicated: 1,000. |
| Retention | Basic: 1 day. Standard: 1–7 days. Premium: up to 90 days. |
| Function App | Event Hub trigger uses connection string or managed identity. Set EventHubConnection in app settings. |
Service Bus
| Paired With | Constraint |
|---|---|
| Topics | Only Standard and Premium SKUs support topics and subscriptions. Basic supports queues only. |
| VNet | Only Premium SKU supports VNet service endpoints and private endpoints. |
| Zone Redundancy | Only Premium SKU supports zone redundancy. |
| Partitioning | Premium messaging partitions cannot be changed after creation. |
| Message Size | Basic/Standard: max 256 KB. Premium: max 100 MB. Plan accordingly for large payloads. |
| Function App | Service Bus trigger uses connection string or managed identity. Set ServiceBusConnection in app settings. |
Monitoring Pairing Constraints
Application Insights
| Paired With | Constraint |
|---|---|
| Log Analytics | Workspace-based App Insights (recommended) requires WorkspaceResourceId. Classic (standalone) is being phased out. |
| Function App | Set APPLICATIONINSIGHTS_CONNECTION_STRING or APPINSIGHTS_INSTRUMENTATIONKEY in function app settings. |
| App Service | Set APPLICATIONINSIGHTS_CONNECTION_STRING in app settings. Enable auto-instrumentation for supported runtimes. |
| AKS | Use Container Insights (different from App Insights) for cluster-level monitoring. App Insights used for application-level telemetry. |
| Private Link | Use Azure Monitor Private Link Scope (AMPLS) to restrict ingestion/query to private networks. |
| Retention | If workspace-based, retention is governed by the Log Analytics workspace. Component-level retention acts as an override. |
Log Analytics
| Paired With | Constraint |
|---|---|
| Application Insights | App Insights WorkspaceResourceId must reference this workspace. Both should be in the same region for optimal performance. |
| AKS (Container Insights) | AKS omsagent addon references workspace via logAnalyticsWorkspaceResourceID. |
| Diagnostic Settings | Multiple resources can send diagnostics to the same workspace. Configure via Microsoft.Insights/diagnosticSettings on each resource. |
| Retention | Free tier is limited to 7-day retention. PerGB2018 supports 30–730 days. Archive tier available for longer retention. |
| Private Link | Use Azure Monitor Private Link Scope (AMPLS) for private ingestion/query. A workspace can be linked to up to 100 AMPLS resources (a VNet can connect to only one AMPLS). |
Networking (Connectivity) Pairing Constraints
Azure Bastion
| Paired With | Constraint |
|---|---|
| VNet | Requires a subnet named exactly AzureBastionSubnet with minimum /26 prefix. |
| Developer SKU | Does NOT require AzureBastionSubnet or public IP. Deploys as shared infrastructure. Only connects to VMs in the same VNet. |
| Public IP | Requires Standard SKU public IP with Static allocation. |
| NSG | NSG on AzureBastionSubnet requires mandatory inbound (HTTPS 443 from Internet, GatewayManager 443) and outbound rules (see Bastion NSG docs). |
| VMs | Target VMs must be in the same VNet as Bastion (or peered VNets with Standard/Premium SKU). |
Azure Firewall
| Paired With | Constraint |
|---|---|
| VNet | Requires a subnet named exactly AzureFirewallSubnet with minimum /26 prefix. |
| Basic Tier | Additionally requires AzureFirewallManagementSubnet with /26 minimum and its own public IP. |
| Public IP | Requires Standard SKU public IP with Static allocation. |
| Firewall Policy | Cannot use both firewallPolicy.id and classic rule collections simultaneously. Policy tier must match or exceed firewall tier. |
| Zones | In zone-redundant mode, all associated public IPs must also be zone-redundant (Standard SKU). |
| Virtual WAN | AZFW_Hub SKU name must reference virtualHub.id instead of ipConfigurations. |
VPN Gateway
| Paired With | Constraint |
|---|---|
| VNet | Requires a subnet named exactly GatewaySubnet with minimum /27 prefix. Use /26+ for 16 ExpressRoute circuits or for ExpressRoute/VPN coexistence. |
| Public IP | Basic VPN SKU requires Basic public IP. VpnGw1+ requires Standard public IP. |
| Active-Active | Requires 2 public IPs and 2 IP configurations. Only supported with VpnGw1+. |
| Zone-Redundant | Must use AZ SKU variant (e.g., VpnGw1AZ). Requires Standard SKU public IPs. AZ SKU cannot be downgraded to non-AZ (one-way migration only). |
| ExpressRoute | Can coexist with VPN gateway on the same GatewaySubnet (requires /27 or larger). Not supported with Basic SKU. Route-based VPN required. |
| PolicyBased | Limited to 1 S2S tunnel, no P2S, no VNet-to-VNet. Use RouteBased for most scenarios. |
| Basic SKU | Basic VPN Gateway does not support BGP, IPv6, RADIUS authentication, IKEv2 P2S, or ExpressRoute coexistence. Max 10 S2S tunnels. |
| GatewaySubnet UDR | Do not apply UDR with 0.0.0.0/0 next hop on GatewaySubnet. ExpressRoute gateways require management controller access — this route breaks it. |
| GatewaySubnet BGP | BGP route propagation must remain enabled on GatewaySubnet. Disabling causes the gateway to become non-functional. |
| DNS Private Resolver | DNS Private Resolver in a VNet with an ExpressRoute gateway and wildcard forwarding rules can cause management connectivity problems. |
DNS Zone
| Paired With | Constraint |
|---|---|
| Domain Registrar | NS records from properties.nameServers must be configured at your domain registrar to delegate the domain to Azure DNS. |
| App Service | Create a CNAME record pointing to {app-name}.azurewebsites.net for custom domains. Add a TXT verification record. |
| Front Door | Create a CNAME record pointing to the Front Door endpoint. Add a _dnsauth TXT record for domain validation. |
| Application Gateway | Create an A record pointing to the Application Gateway public IP, or a CNAME to the public IP DNS name. |
| Traffic Manager | Create a CNAME record pointing to the Traffic Manager profile {name}.trafficmanager.net. |
| Child Zones | Delegate subdomains by creating NS records in the parent zone pointing to the child zone's Azure name servers. |
Private DNS Zone
| Paired With | Constraint |
|---|---|
| Virtual Network | Must create a virtualNetworkLinks child resource to link the DNS zone to each VNet that needs resolution. |
| Private Endpoint | Use a privateDnsZoneGroups child on the Private Endpoint to auto-register A records, or manually create A record sets. One DNS record per DNS name — multiple private endpoints in different regions need separate Private DNS Zones. |
| VNet Link (auto-registration) | Only one Private DNS Zone with registrationEnabled: true can be linked per VNet. Auto-registration creates DNS records for VMs in the VNet. |
| Hub-Spoke VNet | Link the Private DNS Zone to the hub VNet. Spoke VNets resolve via hub DNS forwarder or VNet link. |
| PostgreSQL Flexible Server | For Private Endpoint access, zone name is privatelink.postgres.database.azure.com. For VNet-integrated (private access) servers, the zone name is {name}.postgres.database.azure.com (not privatelink.*). Referenced via properties.network.privateDnsZoneArmResourceId. |
| MySQL Flexible Server | For Private Endpoint access, zone name is privatelink.mysql.database.azure.com. For VNet-integrated (private access) servers, the zone name is {name}.mysql.database.azure.com (not privatelink.*). Referenced via properties.network.privateDnsZoneResourceId. |
Private Endpoint
| Paired With | Constraint |
|---|---|
| Subnet | The subnet must not have NSG rules that block private endpoint traffic. Subnet must have privateEndpointNetworkPolicies set to Disabled (default) for network policies to be bypassed. |
| Private DNS Zone | Create a Microsoft.Network/privateDnsZones/virtualNetworkLinks to link the DNS zone to the VNet. Create an A record or use a private DNS zone group to auto-register DNS. |
| Private DNS Zone Group | Use privateEndpoint/privateDnsZoneGroups child resource to auto-register DNS records in the Private DNS Zone. |
| Key Vault | Group ID: vault. DNS zone: privatelink.vaultcore.azure.net. |
| Storage Account | Group IDs: blob, file, queue, table, web, dfs. Each requires its own PE and DNS zone. |
| SQL Server | Group ID: sqlServer. DNS zone: privatelink.database.windows.net. |
| Container Registry | Group ID: registry. DNS zone: privatelink.azurecr.io. |
Networking (Core) Pairing Constraints
Virtual Network
| Paired With | Constraint |
|---|---|
| Subnets | Address prefixes of all subnets must fall within the VNet address space. Subnet CIDRs cannot overlap. |
| VNet Peering | Peered VNets cannot have overlapping address spaces. |
| Azure Firewall | Requires a subnet named exactly AzureFirewallSubnet with minimum /26 prefix. |
| Azure Bastion | Requires a subnet named exactly AzureBastionSubnet with minimum /26 prefix (recommended /26). |
| VPN Gateway | Requires a subnet named exactly GatewaySubnet with minimum /27 prefix (recommended /27). |
| Application Gateway | Requires a dedicated subnet (no mandatory name, but must not contain other resource types). |
| AKS | AKS subnet must have enough IP addresses for nodes + pods. With Azure CNI, each node reserves IPs for max pods. |
Subnet
| Paired With | Constraint |
|---|---|
| NSG | Cannot attach NSG to GatewaySubnet — NSGs are not supported for either VPN or ExpressRoute gateways. NSG on AzureBastionSubnet requires specific required rules. |
| Delegations | A subnet can only be delegated to one service. Delegated subnets cannot host other resource types. |
| Service Endpoints | Must match the service being accessed (e.g., Microsoft.Sql for SQL Server VNet rules). |
| Private Endpoints | Set privateEndpointNetworkPolicies: 'Enabled' to apply NSG/route table to private endpoints (default is Disabled). |
| AKS | AKS subnet needs enough IPs for all nodes + pods. Cannot be delegated or have conflicting service endpoints. |
| Application Gateway | Dedicated subnet required — cannot coexist with other resources except other App Gateways. Cannot mix v1 and v2 App Gateway SKUs on the same subnet. |
| Azure Firewall | Subnet must be named AzureFirewallSubnet, minimum /26. Cannot have other resources. |
| App Service VNet Integration | Subnet must be delegated to Microsoft.Web/serverFarms. Minimum size /28 (or /26 for multi-plan subnet join). This subnet must be different from any subnet used for App Service Private Endpoints. |
| GatewaySubnet UDR | Do not apply UDR with 0.0.0.0/0 next hop on GatewaySubnet. ExpressRoute gateways require management controller access. BGP route propagation must remain enabled on GatewaySubnet. |
NSG
| Paired With | Constraint |
|---|---|
| GatewaySubnet | NSGs are not supported on GatewaySubnet. Associating an NSG may cause VPN and ExpressRoute gateways to stop functioning. |
| AzureBastionSubnet | NSG on Bastion subnet requires specific inbound/outbound rules (see Azure Bastion NSG). |
| Application Gateway | NSG on App Gateway subnet must allow GatewayManager service tag on ports 65200–65535 (v2) and health probe traffic. |
| Load Balancer | Must allow AzureLoadBalancer service tag for health probes. Standard LB requires NSG — it is secure by default and blocks inbound traffic without an NSG. |
| Virtual Network | NSG is associated to subnets, not directly to VNets. Each subnet can have at most one NSG. |
Route Table
| Paired With | Constraint |
|---|---|
| Subnet | Route table is associated on the subnet side: set subnet.properties.routeTable.id to the route table resource ID. Each subnet can have at most one route table. |
| Azure Firewall | For forced tunneling, create a default route (0.0.0.0/0) with nextHopType: 'VirtualAppliance' pointing to the firewall private IP. |
| VPN Gateway | Set disableBgpRoutePropagation: true to prevent BGP routes from overriding UDRs on the subnet. |
| GatewaySubnet | UDRs on GatewaySubnet have restrictions — cannot use 0.0.0.0/0 route pointing to a virtual appliance. |
| AKS | AKS subnets with UDRs require careful route design. Must allow traffic to Azure management APIs. kubenet and Azure CNI have different routing requirements. |
| Virtual Appliance | nextHopIpAddress must be a reachable private IP in the same VNet or a peered VNet. The appliance NIC must have enableIPForwarding: true. |
Network Interface
| Paired With | Constraint |
|---|---|
| Virtual Machine | Each VM requires at least one NIC. NIC must be in the same region and subscription as the VM. |
| Subnet | NIC must reference a subnet. The subnet determines the VNet, NSG, and route table that apply. |
| NSG | NSG can be associated at the NIC level or at the subnet level (or both). NIC-level NSG is evaluated after subnet-level NSG. |
| Public IP | Public IP and NIC must be in the same region. When associated with a Load Balancer, Public IP SKU must match the LB SKU (Basic with Basic, Standard with Standard). |
| Load Balancer | NIC IP configuration can reference loadBalancerBackendAddressPools and loadBalancerInboundNatRules. Load balancer and NIC must be in the same VNet. |
| Accelerated Networking | Not all VM sizes support accelerated networking. Must verify VM size compatibility. |
| VM Scale Set | NICs for VMSS instances are managed by the scale set — do not create standalone NICs for VMSS. |
| Application Gateway | NIC IP configuration can reference applicationGatewayBackendAddressPools. |
Public IP
| Paired With | Constraint |
|---|---|
| Standard SKU | Must use Static allocation method. Dynamic only works with Basic SKU. |
| Load Balancer | Public IP SKU must match Load Balancer SKU (Standard ↔ Standard, Basic ↔ Basic). |
| Application Gateway | Standard_v2 App Gateway requires Standard SKU public IP with Static allocation. |
| Azure Bastion | Requires Standard SKU with Static allocation. |
| VPN Gateway | Basic VPN Gateway SKU requires Basic public IP. Standard+ gateway SKUs require Standard public IP. |
| Azure Firewall | Requires Standard SKU with Static allocation. |
| Zones | Standard SKU is zone-redundant by default. Specify zones only to pin to specific zone(s). |
NAT Gateway
| Paired With | Constraint |
|---|---|
| Subnet | NAT Gateway is associated on the subnet side: set subnet.properties.natGateway.id to the NAT Gateway resource ID. A subnet can have at most one NAT Gateway. |
| Public IP | Public IP must use Standard SKU and Static allocation. Public IP and NAT Gateway must be in the same region. |
| Public IP Prefix | Public IP prefix must use Standard SKU. Provides contiguous outbound IPs. |
| Availability Zones | NAT Gateway can be zonal (pinned to one zone) or non-zonal. Public IPs must match the same zone or be zone-redundant. |
| Load Balancer | NAT Gateway takes precedence over outbound rules of a Standard Load Balancer when both are on the same subnet. |
| VPN Gateway / ExpressRoute | GatewaySubnet does not support NAT Gateway association. |
| Azure Firewall | NAT Gateway can be associated with the AzureFirewallSubnet for deterministic outbound IPs in SNAT scenarios. |
Networking (Traffic) Pairing Constraints
Application Gateway
| Paired With | Constraint |
|---|---|
| Subnet | Requires a dedicated subnet — no other resources allowed in the subnet (except other App Gateways). Cannot mix v1 and v2 SKUs on the same subnet — separate subnets required for each. |
| Public IP | v2 SKU requires Standard SKU public IP with Static allocation. |
| NSG | NSG on App Gateway subnet must allow GatewayManager service tag on ports 65200–65535 (v2) or 65503–65534 (v1). |
| WAF | WAF configuration only available with WAF_v2 or WAF_Large/WAF_Medium SKUs. WAF v2 cannot disable request buffering — chunked file transfer requires path-rule workaround. |
| Zones | v2 supports availability zones. Specify zones: ['1','2','3'] for zone-redundant deployment. |
| Key Vault | For SSL certificates, use sslCertificates[].properties.keyVaultSecretId to reference Key Vault certificates. User-assigned managed identity required. |
| v1 Limitations | v1 does not support: autoscaling, zone redundancy, Key Vault integration, mTLS, Private Link, WAF custom rules, or header rewrite. Must use v2 for these features. v1 SKUs are being retired April 2026. |
| Private-only (no public IP) | Requires EnableApplicationGatewayNetworkIsolation feature registration. Only available with Standard_v2 or WAF_v2. |
| Global VNet Peering | Backend via private endpoint across global VNet peering causes traffic to be dropped — results in unhealthy backend status. |
| kubenet (AKS) | Kubenet is not supported by Application Gateway for Containers. Must use CNI or CNI Overlay. |
Front Door
| Paired With | Constraint |
|---|---|
| Origins (backends) | Origins are defined in child originGroups/origins. Supported origin types: App Service, Storage, Application Gateway, Public IP, custom hostname. |
| Private Link Origins | Only available with Premium_AzureFrontDoor SKU. Enable private origin connections to App Service, Storage, Internal Load Balancer, etc. |
| WAF Policy | WAF policies are separate Microsoft.Network/FrontDoorWebApplicationFirewallPolicies resources. Linked via security policy child resource on the profile. |
| Custom Domains | Custom domains are child resources of the profile. Require DNS CNAME/TXT validation and certificate (managed or custom). |
| Application Gateway | Front Door in front of App Gateway: use App Gateway public IP as origin. Set X-Azure-FDID header restriction on App Gateway to accept only Front Door traffic. |
| App Service | Restrict App Service to Front Door traffic using access restrictions with AzureFrontDoor.Backend service tag and X-Azure-FDID header check. |
Load Balancer
| Paired With | Constraint |
|---|---|
| Public IP | Public IP SKU must match LB SKU. Basic LB requires Basic public IP; Standard LB requires Standard public IP. No cross-SKU mixing. |
| Standard SKU | Backend pool VMs must be in the same VNet. No VMs from different VNets. Standard LB blocks outbound traffic by default — requires explicit outbound rules, NAT gateway, or instance-level public IPs. Standard LB requires an NSG (secure by default; inbound traffic blocked without NSG). |
| Basic SKU | Backend pool VMs must be in the same availability set or VMSS. |
| Availability Zones | Standard SKU is zone-redundant by default. Frontend IPs inherit zone from public IP. |
| VMs / VMSS | VMs in backend pool cannot have both Basic and Standard LBs simultaneously. |
| Outbound Rules | Only Standard SKU supports outbound rules. Basic SKU has implicit outbound. |
API Management
| Paired With | Constraint |
|---|---|
| VNet (External) | Only available with Developer, Premium, or Isolated SKU. Subnet must be dedicated with an NSG allowing APIM management traffic. |
| VNet (Internal) | Same as External but no public gateway endpoint. Requires Private DNS or custom DNS for resolution. |
| Application Gateway | Common pattern: App Gateway in front of Internal-mode APIM. App Gateway uses the APIM private IP as backend. |
| Key Vault | Named values and certificates can reference Key Vault secrets. Requires managed identity with Key Vault Secrets User role. |
| Application Insights | Set properties.customProperties with Microsoft.WindowsAzure.ApiManagement.Gateway.Protocols.Server.Http2 and logger resource for diagnostics. |
| NSG (VNet mode) | Subnet NSG must allow: inbound on ports 3443 (management), 80/443 (client); outbound to Azure Storage, SQL, Event Hub, and other dependencies. |
Pairing Constraints Index
| Sub-Category | File | Resources |
|---|---|---|
| AI & ML | ai-ml.md | AI Search, Cognitive Services, ML Workspace |
| Compute (PaaS) | compute-apps.md | App Service, ASP, Function App, Container App, CAE, ACR, Static Web App |
| Compute (IaaS) | compute-infra.md | AKS, VM, VMSS, Availability Set, Managed Disk |
| Data (Relational) | data-relational.md | SQL Server, SQL Database, MySQL, PostgreSQL |
| Data (Analytics) | data-analytics.md | Cosmos DB, Redis, Storage, Data Factory, Synapse |
| Messaging | messaging.md | Event Grid, Event Hub, Service Bus |
| Monitoring | monitoring.md | App Insights, Log Analytics |
| Networking (Core) | networking-core.md | VNet, Subnet, NSG, Route Table, NIC, Public IP, NAT Gateway |
| Networking (Traffic) | networking-traffic.md | App Gateway, Front Door, LB, APIM |
| Networking (Connectivity) | networking-connectivity.md | Bastion, Firewall, VPN GW, DNS, Private DNS, PE |
| Security | security.md | Key Vault, Managed Identity |
Security Pairing Constraints
Key Vault
| Paired With | Constraint |
|---|---|
| Storage Account (CMK) | Must have enableSoftDelete: true AND enablePurgeProtection: true. |
| Storage Account (CMK at creation) | Storage must use user-assigned managed identity — system-assigned only works for existing accounts. |
| SQL Server (TDE) | Must enable enablePurgeProtection. Key Vault and SQL Server must be in the same Azure AD tenant. |
| AKS (secrets) | Use enableRbacAuthorization: true with Azure RBAC for secrets access. AKS needs azureKeyvaultSecretsProvider addon. |
| Disk Encryption | Must set enabledForDiskEncryption: true. Premium SKU required for HSM-protected keys. |
| Private Endpoint | Set publicNetworkAccess: 'Disabled' and networkAcls.defaultAction: 'Deny' when using private endpoints. |
| CMK Firewall | When any Azure service uses CMK from Key Vault, the Key Vault firewall must enable "Allow trusted Microsoft services to bypass this firewall" — unless using private endpoints to Key Vault. |
| CMK Key Type | Key must be RSA or RSA-HSM, 2048/3072/4096-bit. Other key types are not supported for customer-managed keys. |
| CMK Cross-Tenant | Key Vault and consuming service must be in the same Azure AD tenant. Cross-tenant CMK requires separate configuration. |
Managed Identity
| Paired With | Constraint |
|---|---|
| Any Resource (identity assignment) | Reference the identity resource ID in the resource's identity.userAssignedIdentities object as { '${managedIdentity.id}': {} }. |
| Key Vault (CMK) | Storage accounts using CMK at creation require a user-assigned identity — system-assigned only works for existing accounts. |
| Container Registry (ACR pull) | Assign AcrPull role to the identity's principalId. Reference the identity in the pulling resource (AKS, Container App, etc.). |
| AKS (workload identity) | Create a federated identity credential on the managed identity. Map it to a Kubernetes service account via OIDC issuer. |
| Role Assignments | Use properties.principalId with principalType: 'ServicePrincipal' in Microsoft.Authorization/roleAssignments. |
| Function App / App Service | Set identity.type to 'UserAssigned' and reference the identity resource ID. Use for Key Vault references, storage access, etc. |
Deployment Execution
Execute infrastructure deployment after plan approval and IaC generation.
Status Gate
Before executing any deployment command, verify:
meta.status === "approved"If status is not approved, stop and inform the user. Do not manually change the status.
Pre-Deployment Checklist
1. Plan approved — meta.status is approved 2. IaC generated — Bicep or Terraform files exist in <project-root>/infra/ 3. Azure context confirmed — subscription and resource group selected 4. User confirmation — explicit "yes, deploy" from the user 5. Syntax validated — az bicep build or terraform validate passed
Bicep Deployment
Scope selection: use resource-group scope when your template deploys into an existing resource group. Use subscription scope when your template creates resource groups or other subscription-level resources (policies, role assignments, etc.).
# Validate first (applies to both scopes)
az bicep build --file infra/main.bicepChoose the command based on the targetScope set in main.bicep (see bicep-generation.md Bicep Conventions):
targetScope | When to use | Command |
|---|---|---|
resourceGroup (default) | All resources in one resource group | az deployment group create |
subscription | Resources span multiple resource groups, or includes subscription-level resources (policy, RBAC, resource group creation) | az deployment sub create |
Resource Group Scope
# What-if preview
az deployment group create \
--resource-group <resource-group-name> \
--template-file infra/main.bicep \
--parameters infra/main.bicepparam \
--what-if
# Deploy
az deployment group create \
--resource-group <resource-group-name> \
--template-file infra/main.bicep \
--parameters infra/main.bicepparam \
--name <deployment-name>PowerShell:
az deployment group create `
--resource-group <resource-group-name> `
--template-file infra/main.bicep `
--parameters infra/main.bicepparam `
--name <deployment-name>Subscription Scope
# What-if preview
az deployment sub create \
--location <location> \
--template-file infra/main.bicep \
--parameters infra/main.bicepparam \
--what-if
# Deploy
az deployment sub create \
--location <location> \
--template-file infra/main.bicep \
--parameters infra/main.bicepparam \
--name <deployment-name>PowerShell:
az deployment sub create `
--location <location> `
--template-file infra/main.bicep `
--parameters infra/main.bicepparam `
--name <deployment-name>Terraform Deployment
cd infra
# Initialize
terraform init
# Preview changes
terraform plan -var-file=prod.tfvars -out=tfplan
# Apply (requires confirmation)
terraform apply tfplanPowerShell:
Set-Location infra
terraform init
terraform plan -var-file=prod.tfvars -out=tfplan
terraform apply tfplanPost-Deployment
After successful deployment:
1. Update status — set meta.status to deployed in <project-root>/.azure/infrastructure-plan.json 2. Verify resources — list resources in the target resource group using Azure CLI: az resource list -g <resource-group-name> -o table 3. Report to user — list deployed resources, endpoints, and any follow-up actions
Error Handling
| Error | Action |
|---|---|
| Authentication failure | Run az login and retry |
| Quota exceeded | Check limits with mcp_azure_mcp_quota, select different SKU or region |
| Name conflict | Resource name already taken; append unique suffix or choose new name |
| Region unavailable | Service not available in chosen region; select alternative |
| Validation failure | Fix IaC syntax errors before retrying deployment |
Property & Pairing Checks
Cross-check each new resource's properties against every already-written resource it connects to. Only run the checks relevant to this resource's type. Consult the resource file's Pairing Constraints section for type-specific rules.
SKU Compatibility
| # | Check | Fix |
|---|---|---|
| 1 | Public IP SKU matches Load Balancer SKU (both Standard or both Basic) | Align to Standard (Basic retiring Sep 2025) |
| 2 | Application Gateway v1/v2 on separate subnets; v2 if zone redundancy, autoscaling, or Key Vault integration needed | Upgrade to v2 or split subnets |
| 3 | VPN Gateway SKU supports required features (BGP, IPv6, coexistence) — not Basic if any advanced feature is needed | Upgrade SKU |
| 4 | App Service Plan SKU meets feature requirements (VNet integration ≥ Basic, slots ≥ Standard, isolation ≥ IsolatedV2) | Upgrade plan SKU |
| 5 | Redis Cache tier supports required features (VNet injection = Premium, clustering = Premium/Enterprise) | Upgrade tier |
Subnet & Network Conflicts
| # | Check | Fix |
|---|---|---|
| 1 | No already-written service with exclusive subnet requirements shares the same subnet as this resource | Assign a separate subnet |
| 2 | Subnet delegation matches service requirement — delegated for App Service/Container Apps Workload Profiles; NOT delegated for AKS, Consumption-only Container Apps | Fix delegation setting |
| 3 | App Service VNet Integration subnet ≠ App Service Private Endpoint subnet | Split into two subnets |
| 4 | Subnet CIDR size meets minimum (/26 for Firewall/Bastion, /27 for Gateway/Container Apps WP, /23 for Container Apps Consumption) | Expand CIDR |
| 5 | GatewaySubnet has no NSG; AzureBastionSubnet has an NSG | Add or remove NSG resource |
Storage Pairing
| # | Check | Fix |
|---|---|---|
| 1 | Functions storage account uses StorageV2 or Storage kind (not BlobStorage/BlockBlob/FileStorage) | Change kind to StorageV2 |
| 2 | Functions on Consumption plan do not reference network-secured storage | Remove network rules or upgrade to Premium plan |
| 3 | Zone-redundant Functions use ZRS storage (not LRS/GRS) | Change storage SKU to Standard_ZRS |
| 4 | VM boot diagnostics storage is not Premium or ZRS | Use Standard_LRS or Standard_GRS |
Cosmos DB
| # | Check | Fix |
|---|---|---|
| 1 | Multi-region writes + Strong consistency not configured together | Switch to Session consistency or single-region writes |
| 2 | Serverless accounts are single-region only, no shared-throughput databases | Remove multi-region config or switch to provisioned throughput |
Key Vault & CMK
| # | Check | Fix |
|---|---|---|
| 1 | Any service using CMK has its Key Vault with enableSoftDelete: true and enablePurgeProtection: true | Add properties to Key Vault (or fix the already-written Key Vault entry) |
| 2 | CMK at storage creation uses user-assigned managed identity (not system-assigned) | Add a user-assigned identity resource before this resource |
SQL Database
| # | Check | Fix |
|---|---|---|
| 1 | Zone redundancy not configured on Basic/Standard DTU tiers | Upgrade to Premium, Business Critical, or GP vCore |
| 2 | Hyperscale zone-redundant elastic pools use ZRS/GZRS backup storage | Set backup storage redundancy |
AKS Networking
| # | Check | Fix |
|---|---|---|
| 1 | Pod CIDR does not overlap with cluster subnet, peered VNets, or gateway ranges already in the plan | Adjust CIDR |
| 2 | Reserved CIDR ranges (169.254.0.0/16, 172.30.0.0/16, 172.31.0.0/16, 192.0.2.0/24) not used | Change to allowed range |
| 3 | CNI Overlay not combined with VM availability sets, virtual nodes, or DCsv2 VMs | Switch CNI plugin or VM series |
Phase 1: Extract Insights
The goal of this phase is to extract insights from the user's existing Azure environment. These insights will be used to guide the planning process in later phases.
1. Check whether insights already exist at <project-root>/.azure/insights.json. If they do, reuse them and skip the rest of this phase. 2. Check whether the insights_get tool is available. If it is not, skip this phase. 3. Ask the user which scope to use for generating insights. Present these three options: a. "Subscription-scoped (default subscription)" — use this as the default if the user does not respond. b. "Subscription-scoped (choose a subscription)" — if selected, ask the user to provide a subscription name or ID. c. "Tenant-scoped (slower)" 4. Ask the user whether there are specific areas they want the insights to focus on. Present these options: a. "General" — use this as the default if the user does not respond. b. "Cost" c. "Reliability" d. "Security" e. "Performance" f. "Other" — this should be a custom input field. 5. Run the insights_get tool using a general-purpose subagent. Pass a one-line summary via the --query option that describes the user's infrastructure and the types of insights to prioritise. Do not pass the --nocache flag unless the user has explicitly asked for it. Begin Phase 2 while this tool runs. 6. Once the tool finishes, save the resulting JSON to <project-root>/.azure/insights.json. Do not include tool call metadata. If the tool errors or returns no insights, write an empty array [] to the file instead.
Gate
insights.jsonmust exist and match the Insights Schema defined in schema.md. If the tool errored or returned no insights, the file should contain an empty array[].
Phase 2: Research WAF
The goal of this phase is to understand user intent and gather WAF guidance using MCP tools.
Step 1 - Clarify Requirements
Clarify the user's requirements until you can confidently describe what they want to build. Do NOT proceed to Step 2 until all critical gaps are resolved. Stay focused on what the user needs — do not make architectural decisions or propose specific services yet.
1. Extract what's explicitly stated in the user's prompt: workload purpose, traffic expectations, data storage needs, security requirements, and budget constraints. 2. Identify gaps across: workload purpose, data/storage needs, networking requirements, security/compliance constraints, availability expectations, environments, expected scale, and budget. A gap is critical if it would fundamentally change the scope of the infrastructure. 3. Ask the user focused questions (≤5 per round) for critical gaps only. Repeat until no critical gaps remain. Defer region and SKU related questions until insights have been generated; only ask the user directly if the insights do not address them. 4. Summarize your understanding of the user's requirements and wait for confirmation before proceeding.
Step 2 - Identify Sub-Goals
Derive sub-goals and include them in inputs.subGoals. Sub-goals are implicit constraints the user hasn't stated but the workload clearly requires. Examples:
- "assume all defaults" -> Cost-optimized: consumption/serverless tiers, minimal complexity.
- "production system" -> Production-grade: zone redundancy, private networking, managed identity.
- "secure" -> Security-first: no public IPs on workload VMs; Bastion + Key Vault SSH key; Trusted Launch; managed identity over keys.
- "observable" -> Operational excellence baseline: Log Analytics + VM Insights, NSG flow logs, boot diagnostics, NAT Gateway for deterministic egress.
Step 3 - Research WAF
Mandatory: Call WAF MCP tools before reading local resource files.
1. Call get_azure_bestpractices with resource: "general", action: "all" for baseline guidance. Call once only. 2. Call wellarchitectedframework_serviceguide_get with service: "<name>" for each core service (in parallel). Examples: "Container Apps", "Cosmos DB", "App Service", "Event Grid", "Key Vault". Return URLs only. 3. Dispatch sub-agents in parallel to fetch every WAF URL (never inline — guides are 20–60 KB) and summarize in ≤500 tokens. Focus on: additional resources needed, required properties for security and reliability, and key design decisions. Do not skip this step to keep token usage down, even if the core WAF principles for these services are already well-established and captured in your plan. 4. Collect all WAF findings: missing resources, property hardening, architecture patterns.
Gate
- All tool calls must be completed and all WAF guides summarized.
Phase 3: Research Resources
The goal of this phase is to research Azure resources before generating the plan.
Step 1 - Resource Refinement
Cross reference WAF
Read WAF cross-cutting checklist. For every checklist item, either:
- Add missing resources / harden properties, or;
- Document the intentional omission in
overallReasoning.tradeoffsandinputs.subGoals.
Insights Integration
Read .azure/insights.json produced by Phase 1 and evaluate each insight against the current workload and sub-goals identified in Phase 2:
- If an insight applies, prefer it over defaults — especially for region, SKU tier, security posture, naming, and tagging.
- If an insight doesn't apply, document the intentional omission in
overallReasoning.tradeoffs. - Insights can shape both resource selection and property configuration.
- Track each insight you apply in
inputs.insightsAppliedso the user can trace why a decision was made.
Mandatory Security rule: only apply a security-related insight if it results in an equal or stronger security posture than the alternatives. A weaker security posture from an insight is only acceptable when the user has explicitly requested it in the initial prompt.
Step 2 - Resource Lookup
Mandatory: Complete this step for every resource before generating the plan. WAF tools from Phase 2 provide architecture guidance, but do not provide ARM types, naming rules, or pairing constraints. This step fills those gaps.
For each resource identified since Phase 1: 1. Read the relevant resource reference file to get its ARM type, API version, and CAF prefix. Use resources/README.md as the index to help you find the right file (e.g., resources/compute-infra.md for AKS, resources/data-analytics.md for Cosmos DB). 2. Read the relevant pairing constraint file using constraints/README.md as the index. Each category file is <2K tokens, you must read the whole file for all resources in that category. 3. Required — for every resource, spawn a general-purpose sub-agent to fetch its naming rules. Pass the naming rules URL from the resource file and instruct the sub-agent to call microsoft_docs_fetch and return only the min/max length, allowed characters, and uniqueness scope. The resource file's CAF prefix is a style convention only — it does not capture these ARM-enforced constraints, so this step cannot be skipped.
Important Tip: Only load the category files you need. For a plan with AKS + Cosmos DB + VNet + Key Vault, you'd load 4 constraint files and 4 resource files (~5.5K tokens total) instead of the full catalog (~22K tokens).
After completing the steps above, verify from the tool results:
1. Type — Correct Microsoft.* resource type and API version 2. SKU — Available in target region, appropriate for workload 3. Region — Service available, data residency met 4. Name — CAF-compliant naming constraints 5. Dependencies — All prerequisites identified and ordered 6. Properties — Required properties per resource schema 7. Alternatives — At least one alternative with tradeoff documented
Gate
- Every resource has an ARM type, naming rules, and pairing constraints checked.
- Present the preliminary resource list to the user with brief justifications and wait for approval before proceeding.
Phase 4: Generate Plan
Build <project-root>/.azure/infrastructure-plan.json using the schema in schema.md. Set meta.status to draft.
Use the user requirements and the research gathered from previous phases to assist:
- Phase 1: insights from
<project-root>/.azure/insights.json(existing environment, user-selected focus areas). - Phase 2: clarified requirements, derived sub-goals (
inputs.subGoals), and WAF summaries covering missing resources, property hardening, and architecture patterns. - Phase 3: refined resource list, including ARM types, naming rules, and pairing constraints.
Important: Write the plan to file progressively using inline edits - never hold the full plan in a single tool-call output.
Gate
- The plan is fully written to file.
Phase 5: Verify Plan
Thoroughly and objectively verify the generated plan based on the following checklists:
- verification.md
- pairing-checks.md
Other mandatory areas to check:
- Goal coverage — does every user requirement map to a resource?
- Dependency completeness — every
dependencies[]entry resolves - Pairing constraints — SKU compatibility, subnet conflicts, storage pairing
You must fix any issue in-place in the plan JSON.
Gate
- Every item in both checklists pass (or have been fixed).
- Present plan to user and wait for manual and explicit approval before proceeding.
- Edit
meta.statustoapprovedif approved. - Otherwise, ask the user for improvements, and return to Phase 2, 3, or 4 based on the nature of their request.
Phase 6: Generate IaC
Important: Before continuing this phase,meta.statusmust be set toapprovedas required by Phase 5.
1. Ask the user whether to generate Bicep, Terraform, or stop here. Never accept vague statements such as "continue", "yes", "go ahead", "proceed", or "make it". Only continue if the user instructs you to generate IaC and names the flavor (e.g. "yes, generate the Bicep" or "go ahead with Terraform"). 2. Generate IaC from the approved plan. Refer to bicep-generation.md for Bicep or terraform-generation.md for Terraform.
Gate
- All required IaC files generated and saved to disk.
Phase 7: Deployment
Destructive Action Gate
This phase is destructive and has irreversible effects. Explicitly confirm with the user whether to deploy, and mention the risks of altering live environments. Never accept implicit or vague intent; only continue if the user acknowledges the risks and instructs you to proceed (e.g. "I understand the risks, continue with deployment") in a reply sent after you have presented the risks. The original task prompt never satisfies this gate, even if it says "deploy" or "run all phases". Stop if no such reply is received. Do not accept vague statements such as "continue", "yes", "deploy now" (without risk acknowledgement), or "go ahead".
---
Important: Before continuing this phase,meta.statusmust be set toapprovedas required by Phase 5. Each destructive action requires explicit user confirmation.
Refer to deployment.md for executing deployment commands.
1. Confirm subscription and resource group with user 2. Select the correct deployment scope based on targetScope in main.bicep (resource group, subscription, management group, or tenant) 3. Run az bicep build to validate, then execute the matching scope command (az deployment group create, az deployment sub create, etc.) or terraform apply
AI & ML Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Cognitive Services | Microsoft.CognitiveServices/accounts | 2025-06-01 | varies by kind | Resource group | Mainstream |
| ML Workspace | Microsoft.MachineLearningServices/workspaces | 2025-06-01 | mlw/hub/proj | Resource group | Mainstream |
| AI Search | Microsoft.Search/searchServices | 2025-05-01 | srch | Global | Mainstream |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Cognitive Services | 2025-06-01 | Custom subdomain names | Naming rules | All API versions |
| ML Workspace | 2025-06-01 | ML Services | Naming rules | All API versions |
| AI Search | 2025-05-01 | Service limits | Naming rules | All API versions |
Compute (PaaS) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| App Service | Microsoft.Web/sites | 2024-11-01 | app | Global | Mainstream |
| App Service Plan | Microsoft.Web/serverfarms | 2024-11-01 | asp | Resource group | Mainstream |
| Container App | Microsoft.App/containerApps | 2025-01-01 | ca | Environment | Strategic |
| Container Apps Environment | Microsoft.App/managedEnvironments | 2025-01-01 | cae | Resource group | Strategic |
| Container Registry | Microsoft.ContainerRegistry/registries | 2025-04-01 | cr | Global | Mainstream |
| Function App | Microsoft.Web/sites | 2024-11-01 | func | Global | Mainstream |
| Static Web App | Microsoft.Web/staticSites | 2024-11-01 | stapp | Resource group | Mainstream |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| App Service | 2024-11-01 | App Service overview | Naming rules | Hosting plans |
| App Service Plan | 2024-11-01 | Plan overview | Naming rules | Pricing |
| Container App | 2025-01-01 | Container Apps overview | Naming rules | Environments |
| Container Apps Environment | 2025-01-01 | Environments overview | Naming rules | Workload profiles |
| Container Registry | 2025-04-01 | ACR overview | Naming rules | SKU tiers |
| Function App | 2024-11-01 | Functions overview | Naming rules | Hosting plans |
| Static Web App | 2024-11-01 | Static Web Apps overview | Naming rules | Hosting plans |
Compute (IaaS) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| AKS Cluster | Microsoft.ContainerService/managedClusters | 2025-05-01 | aks | Resource group | Foundational |
| Availability Set | Microsoft.Compute/availabilitySets | 2024-11-01 | avail | Resource group | Foundational |
| Managed Disk | Microsoft.Compute/disks | 2025-01-02 | osdisk/disk | Resource group | Foundational |
| Virtual Machine | Microsoft.Compute/virtualMachines | 2024-11-01 | vm | Resource group | Foundational |
| VM Scale Set | Microsoft.Compute/virtualMachineScaleSets | 2024-11-01 | vmss | Resource group | Foundational |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| AKS Cluster | 2025-05-01 | AKS overview | Naming rules | Networking concepts |
| Availability Set | 2024-11-01 | Overview | Naming rules | — |
| Managed Disk | 2025-01-02 | Managed disks overview | Naming rules | — |
| Virtual Machine | 2024-11-01 | VMs overview | Naming rules | VM sizes |
| VM Scale Set | 2024-11-01 | VMSS overview | Naming rules | — |
Data (Analytics) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Cosmos DB | Microsoft.DocumentDB/databaseAccounts | 2025-04-15 | cosmos | Global | Foundational |
| Data Factory | Microsoft.DataFactory/factories | 2018-06-01 | adf | Global | Mainstream |
| Redis Cache | Microsoft.Cache/redis | 2024-11-01 | redis | Global | Mainstream |
| Storage Account | Microsoft.Storage/storageAccounts | 2025-01-01 | st | Global | Foundational |
| Synapse Workspace | Microsoft.Synapse/workspaces | 2021-06-01 | synw | Global | Strategic |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Cosmos DB | 2025-04-15 | Cosmos DB overview | Naming rules | Consistency levels |
| Data Factory | 2018-06-01 | ADF overview | Naming rules | ADF naming rules |
| Redis Cache | 2024-11-01 | Redis overview | Naming rules | Service tiers |
| Storage Account | 2025-01-01 | Storage overview | Naming rules | Storage redundancy |
| Synapse Workspace | 2021-06-01 | Synapse overview | Naming rules | All API versions |
Data (Relational) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| SQL Server | Microsoft.Sql/servers | 2023-08-01 | sql | Global | Foundational |
| SQL Database | Microsoft.Sql/servers/databases | 2023-08-01 | sqldb | Parent server | Foundational |
| MySQL Flexible Server | Microsoft.DBforMySQL/flexibleServers | 2023-12-30 | mysql | Global | Mainstream |
| PostgreSQL Flexible Server | Microsoft.DBforPostgreSQL/flexibleServers | 2024-08-01 | psql | Global | Mainstream |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| SQL Server | 2023-08-01 | SQL Server overview | Naming rules | TDE with Key Vault |
| SQL Database | 2023-08-01 | SQL Database overview | Naming rules | DTU vs vCore |
| MySQL Flexible Server | 2023-12-30 | MySQL overview | Naming rules | Compute and storage |
| PostgreSQL Flexible Server | 2024-08-01 | PostgreSQL overview | Naming rules | Compute and storage |
Messaging Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Event Grid Topic | Microsoft.EventGrid/topics | 2025-02-15 | evgt | Region | Mainstream |
| Event Hub | Microsoft.EventHub/namespaces | 2024-01-01 | evhns | Global | Foundational |
| Service Bus | Microsoft.ServiceBus/namespaces | 2024-01-01 | sbns | Global | Foundational |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Event Grid Topic | 2025-02-15 | Event Grid overview | Naming rules | Security and auth |
| Event Hub | 2024-01-01 | Event Hubs overview | Naming rules | Event Hubs tiers |
| Service Bus | 2024-01-01 | Service Bus overview | Naming rules | Service Bus tiers |
Monitoring Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Application Insights | Microsoft.Insights/components | 2020-02-02 | appi | Resource group | Mainstream |
| Log Analytics | Microsoft.OperationalInsights/workspaces | 2025-02-01 | log | Resource group | Mainstream |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Application Insights | 2020-02-02 | App Insights overview | Naming rules | Workspace-based |
| Log Analytics | 2025-02-01 | Log Analytics overview | Naming rules | Pricing |
Networking (Connectivity) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Azure Bastion | Microsoft.Network/bastionHosts | 2024-07-01 | bas | Resource group | Mainstream |
| Azure Firewall | Microsoft.Network/azureFirewalls | 2024-07-01 | afw | Resource group | Mainstream |
| DNS Zone | Microsoft.Network/dnsZones | 2018-05-01 | (domain) | Resource group | Foundational |
| VPN Gateway | Microsoft.Network/virtualNetworkGateways | 2024-07-01 | vpng | Resource group | Foundational |
| Private DNS Zone | Microsoft.Network/privateDnsZones | 2024-06-01 | (domain) | Resource group | Foundational |
| Private Endpoint | Microsoft.Network/privateEndpoints | 2024-07-01 | pep | Resource group | Foundational |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Azure Bastion | 2024-07-01 | Bastion overview | Naming rules | Configuration settings |
| Azure Firewall | 2024-07-01 | Firewall overview | Naming rules | SKU comparison |
| DNS Zone | 2018-05-01 | Azure DNS overview | Naming rules | Delegate a domain |
| VPN Gateway | 2024-07-01 | VPN Gateway overview | Naming rules | Gateway SKUs |
| Private DNS Zone | 2024-06-01 | Private DNS overview | Naming rules | PE DNS config |
| Private Endpoint | 2024-07-01 | PE overview | Naming rules | DNS zone values |
Networking (Core) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Virtual Network | Microsoft.Network/virtualNetworks | 2024-07-01 | vnet | Resource group | Foundational |
| Subnet | Microsoft.Network/virtualNetworks/subnets | 2024-07-01 | snet | Parent VNet | Foundational |
| NSG | Microsoft.Network/networkSecurityGroups | 2024-07-01 | nsg | Resource group | Foundational |
| Route Table | Microsoft.Network/routeTables | 2024-07-01 | rt | Resource group | Foundational |
| Network Interface | Microsoft.Network/networkInterfaces | 2024-07-01 | nic | Resource group | Foundational |
| Public IP | Microsoft.Network/publicIPAddresses | 2024-07-01 | pip | Resource group | Foundational |
| NAT Gateway | Microsoft.Network/natGateways | 2024-07-01 | ng | Resource group | Foundational |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Virtual Network | 2024-07-01 | VNet overview | Naming rules | VNet planning |
| Subnet | 2024-07-01 | Subnets | Naming rules | Subnet delegation |
| NSG | 2024-07-01 | NSG overview | Naming rules | Security rules |
| Route Table | 2024-07-01 | Traffic routing | Naming rules | Forced tunneling |
| Network Interface | 2024-07-01 | NIC overview | Naming rules | Accelerated networking |
| Public IP | 2024-07-01 | Public IP overview | Naming rules | Basic SKU retirement |
| NAT Gateway | 2024-07-01 | NAT Gateway overview | Naming rules | Availability zones |
Networking (Traffic) Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| API Management | Microsoft.ApiManagement/service | 2024-05-01 | apim | Global | Mainstream |
| Application Gateway | Microsoft.Network/applicationGateways | 2024-07-01 | agw | Resource group | Foundational |
| Front Door | Microsoft.Cdn/profiles | 2025-06-01 | afd | Resource group | Foundational |
| Load Balancer | Microsoft.Network/loadBalancers | 2024-07-01 | lbi/lbe | Resource group | Foundational |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| API Management | 2024-05-01 | APIM overview | Naming rules | VNet integration |
| Application Gateway | 2024-07-01 | App Gateway overview | Naming rules | v2 features |
| Front Door | 2025-06-01 | Front Door overview | Naming rules | Routing architecture |
| Load Balancer | 2024-07-01 | LB overview | Naming rules | Standard LB |
Resource Reference Index
Region Categories
Resources fall into region-scoped or global categories. Check individual files for details.
Globally-Unique Names
Some resources require globally unique names (e.g., Storage Accounts, Key Vaults). See individual category files.
Shared ARM Types
Resources share the Microsoft.* ARM type namespace. Each file documents the relevant ARM types and documentation URLs.
| Sub-Category | File | Resources |
|---|---|---|
| AI & ML | ai-ml.md | AI Search, Cognitive Services, ML Workspace |
| Compute (PaaS) | compute-apps.md | App Service, ASP, Function App, Container App, CAE, ACR, Static Web App |
| Compute (IaaS) | compute-infra.md | AKS, VM, VMSS, Availability Set, Managed Disk |
| Data (Relational) | data-relational.md | SQL Server, SQL Database, MySQL, PostgreSQL |
| Data (Analytics) | data-analytics.md | Cosmos DB, Redis, Storage, Data Factory, Synapse |
| Messaging | messaging.md | Event Grid, Event Hub, Service Bus |
| Monitoring | monitoring.md | App Insights, Log Analytics |
| Networking (Core) | networking-core.md | VNet, Subnet, NSG, Route Table, NIC, Public IP, NAT Gateway |
| Networking (Traffic) | networking-traffic.md | App Gateway, Front Door, LB, APIM |
| Networking (Connectivity) | networking-connectivity.md | Bastion, Firewall, VPN GW, DNS, Private DNS, PE |
| Security | security.md | Key Vault, Managed Identity |
Security Resources
| Resource | ARM Type | API Version | CAF Prefix | Naming Scope | Region |
|---|---|---|---|---|---|
| Key Vault | Microsoft.KeyVault/vaults | 2024-11-01 | kv | Global | Foundational |
| Managed Identity | Microsoft.ManagedIdentity/userAssignedIdentities | 2024-11-30 | id | Resource group | Foundational |
Documentation
| Resource | Bicep Reference | Service Overview | Naming Rules | Additional |
|---|---|---|---|---|
| Key Vault | 2024-11-01 | Key Vault overview | Naming rules | Soft-delete |
| Managed Identity | 2024-11-30 | Managed identities | Naming rules | Workload identity federation |
Infrastructure Plan Schema
{
meta: {
planId: string // Unique identifier (e.g., "plan-1")
generatedAt: string // ISO 8601 timestamp
version: string // Schema version (e.g., "0.1-draft")
status: "draft" | "approved" | "deployed" // Lifecycle state
}
inputs: {
userGoal: string // User's stated objective or workload description, matches user query exactly
subGoals?: string[] // Inferred architectural constraints and priorities derived from the user's request and research phase. Examples: "Cost-optimized: user chose defaults, avoid premium networking", "Security-first: encrypt all data, use managed identity", "Minimal complexity: single region, no VNet". These help evaluators understand intentional tradeoffs. Should be short list of 0-3 points.
insightsApplied: string[] // For each insight that influenced this plan, cite the insight ID and explain how and why it was applied. Set to an empty array if no insights were applied. Document any unapplied insights in plan.overallReasoning.tradeoffs.
}
plan: {
resources: {
name: string // Logical resource name (CAF-compliant)
type: string // ARM resource type (e.g., "Microsoft.Storage/storageAccounts")
subtype?: string // Exact subtype (e.g., "Blob Storage", "Azure Function")
location: string // Azure region (e.g., "eastus")
sku: string // SKU tier (e.g., "Standard_LRS", "Consumption")
properties?: Record<string, unknown> // Resource-specific properties
reasoning: {
whyChosen: string // Justification referencing WAF pillars (see phases/2-research-best-practices.md and phases/3-research-resources.md) or requirements
alternativesConsidered: string[] // Other options evaluated
tradeoffs: string // Key tradeoffs in this choice
}
dependencies: string[] // Names of resources this depends on (empty if none)
dependencyReasoning?: string // Why these dependencies exist
references: { title: string, url: string }[] // Links to Azure docs
}[]
overallReasoning: {
summary: string // Overall architecture rationale
tradeoffs: string // Top-level tradeoffs and gaps
}
validation: string // Deployment coherence statement
architecturePrinciples: string[] // Guiding principles (e.g., "Highly available", "Secure")
references: { title: string, url: string }[] // Architecture-level doc links
}
}Insights Schema
{
id: string // Stable identifier (e.g., "insight-001"); cited from inputs.insightsApplied
pattern: string // Observed fact from the tenant scan (what is true today)
implication: string // Recommended planning action derived from the pattern
}[]Terraform Generation
Generate Terraform IaC files from the approved infrastructure plan.
File Structure
Generate files under <project-root>/infra/:
infra/
├── main.tf # Root module — calls child modules
├── variables.tf # Input variable declarations
├── outputs.tf # Output values
├── terraform.tfvars # Default variable values
├── providers.tf # Provider configuration
├── backend.tf # State backend configuration
└── modules/
├── storage/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
├── compute/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── networking/
├── main.tf
├── variables.tf
└── outputs.tfGeneration Steps
1. Create infra/ directory — create <project-root>/infra/ and <project-root>/infra/modules/ directories. All files in subsequent steps go here. 2. Read plan — load <project-root>/.azure/infrastructure-plan.json, verify meta.status === "approved" 3. Generate providers.tf — write infra/providers.tf to configure azurerm provider with required features 4. Generate modules — group resources by category; one module per group under infra/modules/ 5. Generate root main.tf — write infra/main.tf that calls all modules, wire outputs to inputs 6. Generate variables.tf — write infra/variables.tf with all configurable parameters 7. Generate terraform.tfvars — write infra/terraform.tfvars with default values from the plan 8. Generate backend.tf — write infra/backend.tf for Azure Storage backend remote state
Terraform Conventions
- Use
azurermprovider (latest stable version) - Set
features {}block in provider configuration - Use
variableblocks withdescription,type, anddefaultwhere appropriate - Use
localsfor computed values and naming patterns - Use
depends_ononly when implicit dependencies are insufficient - Tag all resources with
environment,workload, andmanaged-by = "terraform"
Provider Configuration
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 4.0"
}
}
}
provider "azurerm" {
features {}
subscription_id = var.subscription_id
}Multi-Environment
For multi-environment plans, generate one .tfvars file per environment:
infra/
├── main.tf
├── variables.tf
├── dev.tfvars
├── staging.tfvars
└── prod.tfvarsDeploy with: terraform apply -var-file=prod.tfvars
Validation Before Deployment
Run terraform validate and terraform plan to verify before applying.
Resource Verification
Run these checks immediately after writing each resource to plan.resources[]. Fix issues in-place before moving to the next resource. Load the relevant category file from resources/ for naming constraints, valid SKUs, and pairing rules.
1. Name Checks
| # | Check | Fix |
|---|---|---|
| 1 | Follows CAF pattern from resource file Identity/Naming section | Rewrite using correct abbreviation |
| 2 | Length within min/max for type | Truncate or restructure |
| 3 | Only allowed characters for type | Strip disallowed characters |
| 4 | Globally-unique names avoid collisions | Add distinguishing suffix |
| 5 | Required subnet names exact (AzureFirewallSubnet, GatewaySubnet, AzureBastionSubnet) | Use exact required string |
| 6 | Function Apps sharing Storage diverge within first 32 chars | Rename or separate storage |
| 7 | AKS MC_{rg}_{cluster}_{region} ≤ 80 chars | Shorten names |
2. Dependency Checks
| # | Check | Fix |
|---|---|---|
| 1 | Every dependencies entry references an existing resource name in the plan | Add missing resource or remove stale ref |
| 2 | Implicit dependencies are explicit (subnet→VNet, App Service→Plan) | Add missing entries |
| 3 | No circular dependencies | Break weaker edge |
3. Property & Pairing Checks
Read pairing-checks.md in full. It covers SKU compatibility, subnet/network conflicts, storage pairing, Cosmos DB, Key Vault/CMK, SQL Database, and AKS networking. For every connected pair of resources in the plan, walk through each applicable rule, confirm compliance, and fix any violation in-place before moving on to the next pair.
4. Insights Checks
Skip this section when insights.json does not exist or contains no insights.
| # | Check | Fix |
|---|---|---|
| 1 | Every insight in insights.json is either justified in inputs.insightsApplied or has a documented reason for non-application in plan.overallReasoning.tradeoffs. An insight must not appear in both. | Add the insight to insightsApplied or document why it was not followed. |
| 2 | Every entry in inputs.insightsApplied cites the insight ID correctly, and its description of how and why it was applied references the insight's pattern and planning implication. | Correct the entry or remove it if it was applied incorrectly. |
| 3 | No insight should result in a weaker security posture than available alternatives, unless it is explicitly requested in the user prompt or stated in the sub-goals. | Revert to the stronger alternative and move the insight to plan.overallReasoning.tradeoffs with an explanation. |
WAF Cross-Cutting Checklist
Walk through every row and decide if resources or properties are needed.
| Concern | Question | Resources / Properties to Add |
|---|---|---|
| Identity | How do services authenticate to each other? | Managed identity, RBAC role assignments |
| Secrets | Are there connection strings, API keys, credentials? | Key Vault with RBAC authorization, soft-delete, and purge protection enabled |
| Monitoring | How will operators observe the system? | Application Insights for compute, Log Analytics workspace, diagnostic settings on data resources |
| Network | Should resources have public endpoints? | Prefer private connectivity (VNet integration, private endpoints, publicNetworkAccess: "Disabled"). Only expose endpoints publicly when the workload requires it, and document the decision as a tradeoff. |
| Encryption | Is data encrypted at rest and in transit? | HTTPS-only, modern minimum TLS, Key Vault for customer-managed keys |
| Resilience | Single points of failure? | Zone-redundant SKUs where supported; compute distributed across ≥2 zones for production. Document deviations as tradeoffs. |
| Auth hardening | Can local/key-based auth be disabled? | Disable local auth on services that support it (e.g. Event Grid, Service Bus, Storage) |
| Tagging | Resources tagged for cost tracking? | Tags on every resource |
Common Additions
Most workloads should include these unless sub-goals justify omission:
- Key Vault — secrets, certificates, customer-managed keys
- Managed Identity — prefer over keys for service-to-service auth
- Application Insights — for App Service, Functions, Container Apps, AKS
- Log Analytics — centralized log aggregation
- Diagnostic Settings — wire data resources to Log Analytics
If you intentionally skip a concern (e.g., no VNet for cost reasons), document it in overallReasoning.tradeoffs and inputs.subGoals.
Workflow
Mandatory Rules
- You must execute the seven phases in sequential order. Follow the instructions precisely as defined. Do not continue to the next phase until the current phase is complete.
- You must stop on all "gate" conditions and only continue when the conditions have been met.
- Destructive actions require explicit user confirmation.
- You must read each phase's reference file in full before executing it.
- Never assume knowledge and cut corners or skip research steps.
Overview
Starting from Phase 1, execute all phases in sequential order. Do not advance to the next phase until the current phase is complete and all of its gate conditions have been met.
| Phase | Action | Reference | Key Gate |
|---|---|---|---|
| 1 | Extract insights | 1-extract-insights.md | Insights written to <project-root>/.azure/insights.json |
| 2 | Research best practices | 2-research-best-practices.md | All MCP tool calls complete and WAF guides summarized |
| 3 | Research resources | 3-research-resources.md | All resources have ARM type, naming rules, and pairing constraints; user approves resource list |
| 4 | Generate plan | 4-generate-plan.md | Plan JSON written to disk |
| 5 | Verify plan | 5-verify.md | All checks pass, user approves |
| 6 | Generate IaC | 6-generate-iac.md | All IaC files generated and saved to disk |
| 7 | Deploy to Azure | 7-deploy.md | User confirms destructive actions |
Plan Status Lifecycle
draft → approved → deployed
draft— set by Phase 4 when the plan is written.approved— set by Phase 5 only after the user explicitly approves. Required before Phase 6 and Phase 7.deployed— set by Phase 7 after a successfulaz deployment ... createorterraform apply.
Outputs
| Artifact | Location |
|---|---|
| Insights | <project-root>/.azure/insights.json |
| Infrastructure Plan | <project-root>/.azure/infrastructure-plan.json |
| Bicep files | <project-root>/infra/main.bicep, <project-root>/infra/modules/*.bicep |
| Terraform files | <project-root>/infra/main.tf, <project-root>/infra/modules/**/*.tf |
Before writing any .bicep or .tf files in Phase 6:
1. Create the infra/ directory at <project-root>/infra/. 2. Create infra/modules/ for child modules. 3. Write main.bicep (or main.tf) inside infra/, not in the project root or .azure/.
Related skills
How it compares
Choose azure-enterprise-infra-planner for subscription-scope enterprise topology planning; use azure-prepare for application-centric azd flows.
FAQ
What IaC formats does azure-enterprise-infra-planner output?
azure-enterprise-infra-planner generates Bicep or Terraform directly for subscription-scope enterprise deployments. The skill does not use Azure Developer CLI (azd); choose azure-prepare for app-centric azd workflows.
Which Azure patterns does azure-enterprise-infra-planner target?
azure-enterprise-infra-planner designs hub-spoke networks, VNets, firewalls, private endpoints, multi-region DR topologies, identity and security controls, and Azure Backup for VM workloads with Well-Architected Framework alignment.
Is Azure Enterprise Infra Planner safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.