**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, diagrams (use python-diagrams).
Scanned 9/4/2026
Install to Claude Code
npx -y skills add jonathan-vella/apex --skill azure-bicep-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Azure Bicep Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/jonathan-vella-azure-bicep-patterns-apex)More formats (shields.io, HTML) on the badges page.
---
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, diagrams (use 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 `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.md`](../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 `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**: Always wire PE + DNS Zone Group + DNS Zone; see group ID table in reference
- **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 `<stem>.json` siblings of `<stem>.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"` |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!