Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Prepare applications for Azure deployment by generating infrastructure code, Dockerfiles, and config files.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/recipes/azd/iac-rules.md
1# AZD IAC Rules23IaC rules for AZD projects. **Additive** — for Bicep, apply `mcp_bicep_get_bicep_best_practices`, `mcp_bicep_list_avm_metadata`, and `mcp_bicep_get_az_resource_type_schema` first; for Terraform, apply `mcp_azure_mcp_azureterraformbestpractices` first; then apply these azd-specific rules.45## AVM Module Selection Order (MANDATORY)67Always prefer modules in provider-specific order:89For **Bicep**:101. AVM Bicep Pattern Modules (AVM+AZD first when available)112. AVM Bicep Resource Modules123. AVM Bicep Utility Modules1314For **Terraform**:151. AVM Terraform Pattern Modules162. AVM Terraform Resource Modules173. AVM Terraform Utility Modules1819If no pattern module exists for the active provider, default immediately to AVM modules in the same provider order (resource, then utility) instead of using non-AVM modules.2021## Retrieval Strategy (azure-documentation MCP primary + optional Context7)2223- **Primary (authoritative):** Use `mcp_azure_mcp_documentation` (`azure-documentation`) for current Azure guidance and AVM integration documentation.24- **Primary (module catalog):** Use `mcp_bicep_list_avm_metadata` plus official AVM indexes to select concrete modules.25- **Secondary (supplemental):** Use Context7 only for implementation examples when `mcp_azure_mcp_documentation` does not provide enough detail. If Context7 is not available, instruct the user to install it: `npx -y @upstash/context7-mcp@latest`.2627## Validation Plan2829Before finalizing generated guidance:30311. Verify the selected module path uses the required AVM order above.322. Verify AVM+AZD pattern modules were checked first, and fallback moved to AVM resource/utility modules when no pattern module exists.333. Verify Terraform guidance follows pattern -> resource -> utility ordering.344. Include selected module names and source links in the plan/output for traceability.3536## File Structure3738| Requirement | Details |39|-------------|---------|40| Location | `./infra/` folder |41| Entry point | `main.bicep` with `targetScope = 'subscription'` |42| Parameters | `main.parameters.json` (ARM JSON — see format below) |43| Modules | `./infra/modules/*.bicep` with `targetScope = 'resourceGroup'` |4445## Parameter File Format4647`main.parameters.json` uses ARM JSON syntax. Do **not** use `.bicepparam` syntax (`using`, `param`, `readEnvironmentVariable()`) in this file — `azd` will fail with a JSON parse error.4849```json50{51"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",52"contentVersion": "1.0.0.0",53"parameters": {54"environmentName": { "value": "${AZURE_ENV_NAME}" },55"location": { "value": "${AZURE_LOCATION}" }56}57}58```5960Use `azd env set` to supply values. During `azd provision`, azd substitutes `${VAR}` placeholders with values from the environment.6162## Naming Convention6364> ⚠️ **Before generating any resource name in Bicep, check [Resource naming rules](https://learn.microsoft.com/azure/azure-resource-manager/management/resource-name-rules) for that resource type's valid characters, length limits, and uniqueness scope.** Some resources forbid dashes or special characters, require globally unique names, or have short length limits. Adapt the pattern below accordingly.6566**Default pattern:** `{resourceAbbreviation}-{name}-{uniqueHash}`6768For resources that disallow dashes, omit separators: `{resourceAbbreviation}{name}{uniqueHash}`6970- [Resource abbreviations](https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/resource-abbreviations) — recommended prefixes per resource type7172```bicep73var resourceSuffix = take(uniqueString(subscription().id, environmentName, location), 6)74// Adapt separator/format per resource naming rules75var defaultName = '${name}-${resourceSuffix}'76var alphanumericName = replace('${name}${resourceSuffix}', '-', '')77```7879**Forbidden:** Hard-coded tenant IDs, subscription IDs, resource group names8081## Required Tags8283| Tag | Apply To | Value |84|-----|----------|-------|85| `azd-env-name` | Resource group | `{environmentName}` |86| `azd-service-name` | Hosting resources | Service name from azure.yaml |8788## Module Parameters8990All modules must accept: `name` (string), `location` (string), `tags` (object)9192## Security9394| Rule | Details |95|------|---------|96| No secrets | Use Key Vault references |97| Managed Identity | Least privilege |98| Diagnostics | Enable logging |99| API versions | Use latest |100101## Recommended Outputs102103`azd` reads `output` values from `main.bicep` and stores UPPERCASE names as environment variables (accessible via `azd env get-values`).104105| Output | When |106|--------|------|107| `AZURE_RESOURCE_GROUP` | Always (required) |108| `AZURE_CONTAINER_REGISTRY_ENDPOINT` | If using containers |109| `AZURE_KEY_VAULT_NAME` | If using secrets |110| `AZURE_LOG_ANALYTICS_WORKSPACE_ID` | If using monitoring |111| `API_URL`, `WEB_URL`, etc. | One per service endpoint |112113## Templates114115**main.bicep:**116117```bicep118targetScope = 'subscription'119120param environmentName string121param location string122123var resourceSuffix = take(uniqueString(subscription().id, environmentName, location), 6)124var tags = { 'azd-env-name': environmentName }125126resource rg 'Microsoft.Resources/resourceGroups@2023-07-01' = {127name: 'rg-${environmentName}'128location: location129tags: tags130}131132module resources './modules/resources.bicep' = {133name: 'resources'134scope: rg135params: { location: location, tags: tags }136}137138// Outputs — UPPERCASE names become azd env vars139output AZURE_RESOURCE_GROUP string = rg.name140output API_URL string = resources.outputs.apiUrl141```142143**Child module:**144145```bicep146targetScope = 'resourceGroup'147148param name string149param location string = resourceGroup().location150param tags object = {}151152var resourceSuffix = take(uniqueString(subscription().id, resourceGroup().name, name), 6)153```154155> ⚠️ **Container resources:** CPU must use `json()` wrapper: `cpu: json('0.5')`, memory as string: `memory: '1Gi'`156