--- name: apex-azure-bicep-patterns user-invocable: false disable-model-invocation: false 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 apex-terraform-patterns), architecture decisions (use apex-azure-adr), troubleshooting, diagrams (use apex-python-diagrams).' 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 `apex-azure-defaults` skill (naming, tags, regions). > **Canonical sources** — the security baseline, AVM-first mandate, naming > conventions, required tags, and unique-suffix rule live in > [`apex-azure-defaults/SKILL.md`](../apex-azure-defaults/SKILL.md) and > [`iac-policy-compliance.md`](../../instructions/references/iac-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](references/hub-spoke-pattern.md) | | Private Endpoint Wiring | Any PaaS service requiring private connectivity | [private-endpoint-pattern](references/private-endpoint-pattern.md) | | Diagnostic Settings | Every deployed resource (mandatory) | [common-patterns](references/common-patterns.md) | | Conditional Deployment | Optional resources controlled by parameters | [common-patterns](references/common-patterns.md) | | Module Composition | Breaking main.bicep into reusable modules | [common-patterns](references/common-patterns.md) | | Managed Identity Binding | Any service-to-service authentication | [common-patterns](references/common-patterns.md) | | Budget & Cost Monitoring | Every deployment (mandatory) | [budget-pattern](references/budget-pattern.md) | | What-If / AVM Pitfalls | Pre-deployment validation & AVM gotchas | [avm-pitfalls](references/avm-pitfalls.md) | | 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`](references/module-interface.md). ## Steps Applying a pattern in a Bicep template: 1. **Identify the pattern** — match your need to a row in [Quick Reference](#quick-reference) (hub-spoke, private endpoint, diagnostics, conditional, identity, budget) 2. **Load the reference** — read the linked `references/*.md` for the chosen pattern; do not load all at once 3. **Compose the module** — follow the Module Interface contract above (`name`/`location`/`tags`/`logAnalyticsWorkspaceName` in; `resourceId`/`resourceName`/`principalId` out) 4. **Pin AVM versions** — query MCR at plan time and follow the `apex-azure-defaults` live-resolution and exception policy 5. **Add diagnostics + budget** — every deployed resource gets diagnostics; every deployment implements the governed cost-monitoring contract 6. **What-if before deploy** — run `az deployment group what-if` and review for unexpected deletes, SKU downgrades, or auth changes 7. **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**: Apply the canonical private-networking baseline; resolve DNS ownership before wiring zone groups, zones and links per [the private-endpoint pattern](references/private-endpoint-pattern.md). - **Diagnostics**: `categoryGroup: 'allLogs'` + `AllMetrics`; pass workspace **name** not ID - **Conditional**: `bool` params with defaults; guard outputs with ternary - **Identity**: `guid()` for idempotent role names; `principalType: 'ServicePrincipal'`; scope narrowly - **Budget**: Follow the canonical cost-monitoring contract; amount and notification inputs MUST be parameters - **What-If**: Run before every deploy; watch for unexpected deletes and SKU downgrades - **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/list` for 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 at `az deployment ... validate` time. - **AVM `insights/metric-alert:0.4.1+` requires `criteria.allof[].name`** — Each entry in `criteria.allOf[]` needs a `name` field; omission passes `bicep build` but fails `az deployment ... validate`: ```bicep allOf: [{ name: 'HighCpu' // REQUIRED metricName: 'Percentage CPU' operator: 'GreaterThan' threshold: 80 timeAggregation: 'Average' }] ``` - **`bicep build` poisons tree-hash folders** — Running `bicep build main.bicep` emits `main.json` next to the source. If the folder is hashed by `validate-iac-handoff.mjs`, that compiled output drifts the hash. The validator now excludes `.json` siblings of `.bicep`, but if you must build manually inside a handoff tree, `rm -f main.json` immediately after. - **AKS `outboundType` must match the egress topology** — a NAT Gateway on the node subnet requires `userAssignedNATGateway`, NOT `userDefinedRouting` (UDR needs a 0.0.0.0/0 route table and is rejected when public network access is restricted). BYO-VNet clusters also need `Network Contributor` on the VNet, and fixed-size node pools must set `minCount`/`maxCount` to `null`. See [avm-pitfalls § AKS](references/avm-pitfalls.md#aks-managed-cluster-apply-time-gotchas). - **MySQL Flexible Server: PE not delegated subnet; engine version 8.4** — on a shared PE subnet use `privateEndpoints[]` (not `delegatedSubnetResourceId`); pin `version: '8.4'` (latest GA LTS → 8.4.7), never the stale 8.0 or an innovation 9.x; `aad_auth_only` is read-only (enforce post-deploy). See [avm-pitfalls § MySQL](references/avm-pitfalls.md#mysql-flexible-server-apply-time-gotchas). ## Reference Index | File | Content | | --------------------------------------------------------------------- | --------------------------------------------------------------------- | | [hub-spoke-pattern.md](references/hub-spoke-pattern.md) | Hub-spoke VNet orchestration with peering | | [private-endpoint-pattern.md](references/private-endpoint-pattern.md) | PE wiring + DNS zone groups + group ID table | | [common-patterns.md](references/common-patterns.md) | Diagnostics, conditional deploy, module composition, managed identity | | [budget-pattern.md](references/budget-pattern.md) | Consumption budget, forecast alerts, anomaly detection | | [avm-pitfalls.md](references/avm-pitfalls.md) | What-if interpretation, AVM gotchas, learn more links | | [module-interface.md](references/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"` |