Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Prepare Azure environments for new workloads—subscriptions, networking, identity, and landing zones
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/services/functions/templates/recipes/composition.md
1# Composition Algorithm23Combine multiple templates into a single deployable project.45## Azure MCP Path67```8INPUT: language, user_requirements9OUTPUT: Complete project ready for `azd up`10111. DISCOVER12functions_template_get(language) → template list with descriptions13142. CHECK SINGLE-TEMPLATE MATCH15If one template's description covers ALL requirements → use it alone16173. SELECT TEMPLATES18- Trigger template (REQUIRED) — base project with IaC19- Binding templates (OPTIONAL) — extract patterns only20214. FETCH TEMPLATES22- Single match: 1 call23- Multiple: parallel calls24255. COMPOSE26- Use trigger template as BASE (functionFiles + projectFiles)27- EXTRACT binding patterns from binding templates28- MERGE IaC resources and RBAC roles29- ADD user's custom business logic30316. TRIM unused demo code (keep AzureWebJobsStorage)32337. WRITE files — for each entry { path, content } in functionFiles[] AND projectFiles[]:34a. Create parent directories from path35b. Write content to path36NEVER hand-write Bicep/Terraform and use azd init -t/func init/func new as fallback when composing multiple recipes and required templates are not found37388. DEPLOY: azd up --no-prompt39```4041## Fallback Path (Azure MCP Unavailable)4243```44INPUT: language, user_requirements45OUTPUT: Complete project ready for `azd up`46471. FETCH MANIFEST48GET https://cdn.functions.azure.com/public/templates-manifest/manifest.json49If fetch fails → fall back to: https://github.com/Azure/azure-functions-templates/blob/dev/Functions.Templates/Template-Manifest/manifest.json50If both fail → fall back to known-good Azure-Samples/functions-quickstart-* repos by language+resource51If all fail → report error and ask user to retry later52532. FILTER TEMPLATES54Filter by: language, resource (from selection.md), iac55563. CHECK SINGLE-TEMPLATE MATCH57If one template covers ALL requirements → use it alone58594. SELECT TEMPLATES60- Trigger template (REQUIRED) — base project61- Binding templates (OPTIONAL) — extract patterns only62635. DOWNLOAD TEMPLATES64For each template:65- If folderPath == "." → ZIP download + unzip66- If folderPath != "." → fetch tree + raw github url file downloads67- Fallback: git clone --depth 168696. COMPOSE70- Use trigger template as BASE71- EXTRACT binding patterns from binding templates72- MERGE IaC resources, RBAC roles and settings, README and other files.73- ADD user's custom business logic74757. TRIM unused demo code (keep AzureWebJobsStorage)76778. WRITE all files78799. DEPLOY: azd up --no-prompt80```8182## Example (MCP)8384**User:** "HTTP function that writes to Cosmos DB"8586```871. Discover: functions_template_get(language: "python") → returns template list882. Check: No single template description mentions BOTH HTTP trigger AND Cosmos output893. Select from discovered list:90- Template with resource: "http" (trigger, base)91- Template with resource: "cosmos" and description mentioning "output" (binding)924. Fetch both templates by templateName from discovery results935. Compose:94- Base: HTTP template (has IaC, azure.yaml)95- Extract: Cosmos output binding + RBAC from cosmos template96- Merge: Add Cosmos module to infra/main.bicep976. Trim: Remove HTTP demo response code987. Write files998. Deploy100```101102## Example (Fallback)103104**User:** "HTTP function that writes to Cosmos DB"105106```1071. Fetch: GET manifest.json from CDN1082. Filter: language=Python, resource=http OR resource=cosmos, iac=bicep1093. Check: No single template covers both1104. Select:111- http-trigger-python-azd (trigger, base) → repositoryUrl + folderPath112- cosmos-trigger-python-azd (binding) → repositoryUrl + folderPath1135. Download: ZIP download both repos (folderPath = ".")1146. Compose:115- Base: HTTP template (has infra/, azure.yaml)116- Extract: Cosmos IaC module + RBAC from cosmos template117- Merge: Add cosmos.bicep to infra/app/, wire into main.bicep1187. Trim: Remove demo code1198. Write files1209. Deploy121```122123## Critical Rules1241251. **NEVER hardcode template names** — always discover/fetch manifest first1262. **PRESERVE generated IaC patterns** — keep RBAC roles, managed identity config, and security settings intact when merging1273. **ALWAYS keep AzureWebJobsStorage** — runtime requires it1284. **ALWAYS use `--no-prompt`** — the agent must never elicit user input during azd commands1295. **ALWAYS include ALL THREE UAMI settings for every binding** — see UAMI Configuration below1306. **ALWAYS wait for RBAC propagation** — use two-phase deploy if 403 errors occur1317. **NEVER enable `allowSharedKeyAccess: true`** — correct solution is waiting for RBAC, not disabling security132133## IaC Merge Guidelines134135When composing multiple templates:136137| Action | Allowed | Not Allowed |138|--------|---------|-------------|139| Add resource modules from binding templates | ✅ | |140| Add RBAC role assignments from binding templates | ✅ | |141| Merge environment variables | ✅ | |142| Remove RBAC roles | | ❌ |143| Change managed identity to connection strings | | ❌ |144| Remove security configurations | | ❌ |145| Modify resource SKUs without user request | | ❌ |146147**Merge = additive combination, not modification of security patterns.**148149## UAMI Configuration (CRITICAL)150151Templates use User Assigned Managed Identity (UAMI). ALL service bindings require explicit `credential` and `clientId` app settings. Missing these causes 500/401/403 errors at runtime.152153**Required pattern for EVERY service binding:**154155```bicep156appSettings: {157// Endpoint (varies by service)158EventHubConnection__fullyQualifiedNamespace: eventhubs.outputs.fullyQualifiedNamespace159// UAMI credentials - REQUIRED, prefix vary by example160EventHubConnection__credential: 'managedidentity'161EventHubConnection__clientId: apiUserAssignedIdentity.outputs.clientId162}163```164165**Validation Checklist (MANDATORY before deploy):**166167| Setting Pattern | Required | Example |168|-----------------|:--------:|---------|169| `{Connection}__fullyQualifiedNamespace` or `{Connection}__accountEndpoint` | ✅ | `EventHubConnection__fullyQualifiedNamespace` |170| `{Connection}__credential` | ✅ | `'managedidentity'` (exact case) |171| `{Connection}__clientId` | ✅ | `apiUserAssignedIdentity.outputs.clientId` |172173> ⛔ **STOP if any check fails.** The function WILL fail at runtime with 500/Unauthorized errors.174175## Language-Specific Entry Points176177### Node.js (JavaScript/TypeScript)178179> ⛔ **Do NOT delete `src/index.js` (JS) or `src/index.ts` (TS).**180> This file contains `app.setup()` which initializes the Functions runtime.181> Without it, functions deploy but return 404 on all endpoints.182183> ⛔ **Glob pattern REQUIRED in package.json:**184>185> ```json186> { "main": "src/{index.js,functions/*.js}" }187> ```188>189> Using `"main": "src/index.js"` alone results in 404 on ALL endpoints.190191> ⛔ **package.json must be at project ROOT** (same level as `azure.yaml`), NOT inside `src/`.192193> 📦 **TypeScript:** Run `npm run build` before deployment.194> Use: `"main": "dist/src/{index.js,functions/*.js}"`195196### C# (.NET)197198> ⛔ **Do NOT replace `Program.cs` from the base template.**199> The base template uses `ConfigureFunctionsWebApplication()` with App Insights integration.200> Recipes only ADD trigger function files (`.cs`) and package references (`.csproj`).201202## Deployment Strategy203204**Option A: Single command** (fast, may fail on first deploy due to RBAC propagation)205206```bash207azd up --no-prompt208```209210**Option B: Two-phase** (recommended for reliability)211212```bash213azd provision --no-prompt # Create resources + RBAC assignments214sleep 60 # Wait for RBAC propagation (Azure AD needs 30-60s)215azd deploy --no-prompt # Deploy code (RBAC now active)216```217218## Terraform-Specific Requirements219220> ⚠️ **CRITICAL**: All Terraform must use `sku_name = "FC1"` (Flex Consumption). **NEVER use Y1/Dynamic.**221222### Runtime Versions223224> ⚠️ **ALWAYS QUERY OFFICIAL DOCUMENTATION** — Do NOT use hardcoded versions.225>226> **Primary Source:** [Azure Functions Supported Languages](https://learn.microsoft.com/en-us/azure/azure-functions/supported-languages)227>228> Query for latest GA/LTS versions before generating IaC.229230| Language | `function_runtime` | Version Source |231|----------|-------------------|----------------|232| C# (.NET) | `dotnet-isolated` | Latest LTS from docs |233| TypeScript/JS | `node` | Latest LTS from docs |234| Python | `python` | Latest GA from docs |235| Java | `java` | Latest LTS from docs |236| PowerShell | `powershell` | Latest GA from docs |237238### Flex Consumption (FC1) Requires azapi239240> ⚠️ Use `azapi_resource` instead of `azurerm_linux_function_app` for FC1.241> The AzureRM provider doesn't support FC1's `functionAppConfig` block.242243```hcl244resource "azapi_resource" "function_app" {245type = "Microsoft.Web/sites@2023-12-01"246name = "func-${local.name}"247location = azurerm_resource_group.rg.location248parent_id = azurerm_resource_group.rg.id249250body = {251kind = "functionapp,linux"252properties = {253serverFarmId = azapi_resource.plan.id254functionAppConfig = {255runtime = { name = "node", version = "22" }256scaleAndConcurrency = { maximumInstanceCount = 100, instanceMemoryMB = 2048 }257deployment = {258storage = {259type = "blobContainer"260value = "${azurerm_storage_account.storage.primary_blob_endpoint}deploymentpackage"261authentication = {262type = "UserAssignedIdentity"263userAssignedIdentityResourceId = azurerm_user_assigned_identity.api.id264}265}266}267}268}269}270depends_on = [time_sleep.rbac_propagation]271}272```273274### RBAC Propagation Delay275276Azure RBAC takes 30-60s to propagate. Terraform's `depends_on` only waits for resource creation, not RBAC propagation.277278**Solution 1: Add `time_sleep` resource**279280```hcl281resource "time_sleep" "rbac_propagation" {282depends_on = [azurerm_role_assignment.storage_blob_owner]283create_duration = "60s"284}285286resource "azapi_resource" "function_app" {287depends_on = [time_sleep.rbac_propagation]288# ...289}290```291292**Solution 2: Create deployment container explicitly**293294```hcl295resource "azurerm_storage_container" "deployment" {296name = "deploymentpackage"297storage_account_id = azurerm_storage_account.storage.id298container_access_type = "private"299depends_on = [azurerm_role_assignment.storage_blob_owner]300}301```302303> ⚠️ **Common Failures Without These Fixes:**304>305> - `403 Forbidden` — RBAC not yet propagated306> - `404 Container Not Found` — deployment container not created307> - `Tag Not Found: azd-service-name` — Azure resource tags take time to be queryable308309### Required: azd-service-name Tag310311```hcl312tags = {313"azd-service-name" = "api" # MUST match service name in azure.yaml314}315```316317> ⚠️ **Without this tag, `azd deploy` fails with:**318> `resource not found: unable to find a resource tagged with 'azd-service-name: api'`319320### Disabled Local Auth (Policy Required)321322Azure Policy often enforces RBAC-only authentication. Always disable local auth (connection strings, SAS keys) and use managed identity instead.323324```hcl325# Storage326shared_access_key_enabled = false327328# Service Bus329local_auth_enabled = false330331# Event Hubs332local_authentication_enabled = false333334# Cosmos DB335local_authentication_disabled = true336```337