name: azure-bicep-patterns description: 'UTILITY SKILL — Reusable Azure Bicep patterns: hub-spoke, private endpoints, diagnostics, AVM composition. WHEN: "hub-spoke Bicep", "private endpoint module", "diagnostic settings", "AVM Bicep composition". USE FOR: Bicep template design, hub-spoke networking, private endpoint patterns, AVM modules. DO NOT USE FOR: Terraform code (use terraform-patterns), architecture decisions (use azure-adr), troubleshooting, diagram generation (use drawio).' compatibility: Requires Azure CLI with Bicep extension
Azure Bicep Patterns Skill
Reusable infrastructure patterns for Azure Bicep templates. Complements
iac-bicep-best-practices.instructions.md (style) and azure-defaults skill (naming, tags, regions).
Canonical sources — the security baseline, AVM-first mandate, naming conventions, required tags, and unique-suffix rule live in
azure-defaults/SKILL.mdandiac-policy-compliance.md. This skill restates the rules tersely below for IaC-output convenience only; in conflict, the canonical sources win.
Quick Reference
| Pattern | When to Use | Reference |
|---|---|---|
| Hub-Spoke Networking | Multi-workload environments with shared services | hub-spoke-pattern |
| Private Endpoint Wiring | Any PaaS service requiring private connectivity | private-endpoint-pattern |
| Diagnostic Settings | Every deployed resource (mandatory) | common-patterns |
| Conditional Deployment | Optional resources controlled by parameters | common-patterns |
| Module Composition | Breaking main.bicep into reusable modules | common-patterns |
| Managed Identity Binding | Any service-to-service authentication | common-patterns |
| Budget & Cost Monitoring | Every deployment (mandatory) | budget-pattern |
| What-If / AVM Pitfalls | Pre-deployment validation & AVM gotchas | avm-pitfalls |
| Batch Bicep Formatting | After generating/editing the Bicep tree | npm run format:bicep -- infra/bicep/{project} (wraps bicep format) |
Canonical Example — Module Interface
Every Bicep module in this repo follows the same input/output contract:
- Inputs (required):
name,location,tags,logAnalyticsWorkspaceName - Outputs (required):
resourceId,resourceName,principalId(use.?principalId ?? ''so modules without managed identity still expose the output)
Full code sample and rationale: references/module-interface.md.
Steps
Applying a pattern in a Bicep template:
- Identify the pattern — match your need to a row in Quick Reference (hub-spoke, private endpoint, diagnostics, conditional, identity, budget)
- Load the reference — read the linked
references/*.mdfor the chosen pattern; do not load all at once - Compose the module — follow the Module Interface contract above (
name/location/tags/logAnalyticsWorkspaceNamein;resourceId/resourceName/principalIdout) - Pin AVM versions to the latest stable — at plan time, query MCR (
https://mcr.microsoft.com/v2/bicep/avm/res/{path}/tags/list) and pin the highest non-prerelease semver; never reuse a version from training data, a prior project, orreferences/avm-modules.md. Stale pins require apin_policy.mode = "exception"block in04-iac-contract.json(seeazure-defaultsskill). Enforced bynpm run validate:avm-versions:freeze. - Add diagnostics + budget — every deployed resource gets a diagnostic setting; every deployment gets a budget with 80%/100%/120% forecast alerts
- What-if before deploy — run
az deployment group what-ifand review for unexpected deletes, SKU downgrades, or auth changes - Validate —
bicep build+bicep lint+npm run validate:iac-security-baseline
Rules
- Hub-Spoke: Hub holds shared infra; spokes peer to hub only; NSGs per subnet
- Private Endpoints: Always wire PE + DNS Zone Group + DNS Zone; see group ID table in reference
- Diagnostics:
categoryGroup: 'allLogs'+AllMetrics; pass workspace name not ID - Conditional:
boolparams with defaults; guard outputs with ternary - Identity:
guid()for idempotent role names;principalType: 'ServicePrincipal'; scope narrowly - Budget: 3 forecast thresholds (80%/100%/120%); amount and emails MUST be parameters
- What-If: Run before every deploy; watch for unexpected deletes and SKU downgrades
- AVM: ALWAYS pin to the latest published stable version (resolve at plan time via MCR
tags/list); wrap modules to override defaults; verify outputs in README. Stale pins require apin_policyexception block — seeazure-defaultsskill. - AVM Version Source of Truth: MCR tag listing (
mcr.microsoft.com/v2/bicep/{module}/tags/list) is authoritative. Helpers and doc tables are NOT — they go stale. Validator:npm run validate:avm-versions.
Gotchas
- AVM output shapes vary across modules — Different AVM modules expose different outputs. Always check the module README before referencing outputs.
- Tag merging in AVM modules — Some AVM modules merge tags internally. Verify deployed tags include all required policy tags after deployment.
- What-If red flags — Watch for unexpected deletes, SKU downgrades, public access changes, authentication mode changes, or identity removal. Always run what-if before deploy.
- MCR version discovery — When AVM version helpers are incomplete,
query
mcr.microsoft.com/v2/bicep/{module}/tags/listfor authoritative published versions. - Cross-RG module
scope:ARM ID split indexes — Splitting a full resource ID (/subscriptions/{sub}/resourceGroups/{rg}/providers/...) on/yields['', 'subscriptions', '{sub}', 'resourceGroups', '{rg}', ...]. Subscription is at index 2, RG name is at index 4. Use:scope: resourceGroup(split(resId, '/')[2], split(resId, '/')[4]). Indexes[1]/[3]are the literals'subscriptions'/'resourceGroups'and only fail ataz deployment ... validatetime. - AVM
insights/metric-alert:0.4.1+requirescriteria.allof[].name— Each entry incriteria.allOf[]needs anamefield; omission passesbicep buildbut failsaz deployment ... validate:allOf: [{ name: 'HighCpu' // REQUIRED metricName: 'Percentage CPU' operator: 'GreaterThan' threshold: 80 timeAggregation: 'Average' }] bicep buildpoisons tree-hash folders — Runningbicep build main.bicepemitsmain.jsonnext to the source. If the folder is hashed byvalidate-iac-handoff.mjs, that compiled output drifts the hash. The validator now excludes<stem>.jsonsiblings of<stem>.bicep, but if you must build manually inside a handoff tree,rm -f main.jsonimmediately after.- AKS
outboundTypemust match the egress topology — a NAT Gateway on the node subnet requiresuserAssignedNATGateway, NOTuserDefinedRouting(UDR needs a 0.0.0.0/0 route table and is rejected when public network access is restricted). BYO-VNet clusters also needNetwork Contributoron the VNet, and fixed-size node pools must setminCount/maxCounttonull. See avm-pitfalls § AKS. - MySQL Flexible Server: PE not delegated subnet; engine version 8.4 — on a
shared PE subnet use
privateEndpoints[](notdelegatedSubnetResourceId); pinversion: '8.4'(latest GA LTS → 8.4.7), never the stale 8.0 or an innovation 9.x;aad_auth_onlyis read-only (enforce post-deploy). See avm-pitfalls § MySQL.
Reference Index
| File | Content |
|---|---|
| hub-spoke-pattern.md | Hub-spoke VNet orchestration with peering |
| private-endpoint-pattern.md | PE wiring + DNS zone groups + group ID table |
| common-patterns.md | Diagnostics, conditional deploy, module composition, managed identity |
| budget-pattern.md | Consumption budget, forecast alerts, anomaly detection |
| avm-pitfalls.md | What-if interpretation, AVM gotchas, learn more links |
| module-interface.md | Canonical module input/output contract |
Learn More
| Topic | How to Find |
|---|---|
| AVM module catalog | mcp_azure-mcp_documentation — command: "microsoft_docs_search", query: "Azure Verified Modules registry Bicep" |
| Resource type schema | mcp_azure-mcp_documentation — command: "microsoft_docs_search", query: "{resource-type} Bicep template reference" |