Back to Home
Securing Applications and Automation - Training Series
Section 6 of 6
Reference Guide

Packaging Tools and azd

ARM Templates, Bicep, and the Azure Developer CLI


Section purpose

This section bridges the full course into deployable outputs. You will learn Azure Resource Manager and Bicep as the infrastructure foundation, the Azure Developer CLI (azd) as the packaging layer that combines infrastructure, code, and CI/CD into a single deployable unit, and then deploy and explore real security tools using these patterns. By the end of the lab you will have deployed a working security testing framework using a single azd up command.

Learning Objectives

Deployment Pipeline 1 Write .psm1, .psd1, and Pester tests 2 Package module manifest and NuGet package 3 Sign Authenticode certificate and hash check 4 Publish private feed or PowerShell Gallery 5 Deploy Install-Module or CI/CD pipeline rollout package once, deploy repeatedly

Learning journey: package once, deploy repeatedly through the five-stage pipeline.

Azure Resource Manager

Azure Resource Manager (ARM) is the management and deployment layer for Azure resources. Azure portal, Azure CLI, Az PowerShell, Bicep, and ARM templates all rely on it for control-plane operations against https://management.azure.com/.

Understanding ARM explains:

ARM REST API

Every resource you create in the portal is a PUT request to an ARM REST API endpoint. The endpoint format is:

PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProvider}/{resourceType}/{resourceName}?api-version={version}

When something fails during deployment, the ARM REST API returns an error code and message. Understanding the ARM layer helps you interpret error messages from az deployment group create and from the Azure portal's deployment history.

Portal CLI / PS SDK / API Azure Resource Manager management.azure.com RBAC · Authentication · Throttling Subscription / Resource Group Resource providers register here Token scope: management.azure.com Graph tokens (graph.microsoft.com) are separate Azure RBAC governs ARM · OAuth consent governs Graph

ARM is the shared control plane for Azure management and deployment tooling.

Azure Subscription Microsoft.Automation automationAccounts aa-secops-prod runbooks Microsoft.KeyVault vaults kv-secops-prod secrets keys Microsoft.Web sites (Function Apps) func-secops-prod serverfarms (App Service Plans) Provider not registered? → ARM deployment fails before creating anything ARM errors reference: provider / type / apiVersion / property path

Resource providers and types: every Azure resource lives under a provider/type hierarchy.

ARM Templates (JSON)

ARM templates are JSON documents that declare the desired state of Azure resources. They are the original Infrastructure as Code format for Azure.

Four core authoring sections:

{
  "parameters": {
    "automationAccountName": {
      "type": "string",
      "metadata": { "description": "Name of the Automation Account" }
    }
  },
  "variables": {
    "location": "[resourceGroup().location]"
  },
  "resources": [
    {
      "type": "Microsoft.Automation/automationAccounts",
      "apiVersion": "2023-11-01",
      "name": "[parameters('automationAccountName')]",
      "location": "[variables('location')]",
      "identity": { "type": "SystemAssigned" },
      "properties": { "sku": { "name": "Basic" } }
    }
  ],
  "outputs": {
    "principalId": {
      "type": "string",
      "value": "[reference(parameters('automationAccountName'), '2023-11-01', 'full').identity.principalId]"
    }
  }
}

ARM JSON is verbose: a simple Automation Account with a managed identity and a Reader role assignment takes approximately 80 lines with nested resourceId() functions and dependsOn arrays. Understanding its structure is useful because Bicep compiles to it, and ARM deployment errors reference JSON structure.

ARM JSON "resources": [{ "type": "Microsoft.Automation/... "apiVersion": "2023-11-01", "dependsOn": [ "[resourceId(... "principalId": "[reference(res... "roleDefinitionId": "[concat... /subscriptions/[subscription... /providers/Microsoft.Auth... ~80 lines • nested resourceId() calls Bicep resource aa 'Microsoft.Automation/ automationAccounts@2023-11-01' = { identity: { type: 'SystemAssigned' } } resource role 'Microsoft.Auth/ roleAssignments@2022-04-01' = { principalId: aa.identity.principalId } ~25 lines • symbolic refs • IntelliSense

ARM JSON declares desired state; Bicep compiles to the same engine.

arm-template.json (~80 lines) "type": "Microsoft.Automation/..." "apiVersion": "2023-11-01", "dependsOn": [ "[resourceId('Microsoft.KeyVault/...')]" ], explicit deps "principalId": "[reference(...).identity" .principalId]", nested ref() "roleDefinitionId": "[concat( ... )]", "/subscriptions/" + subscription().id concat() about 80 lines of JSON for one Automation Account and RBAC setup

ARM JSON is verbose by design: explicit dependencies, nested references, concat() everywhere.

Deploy ARM Template ARM Template Resource exists? No Created Yes Matches config? Yes Unchanged No Updated Same desired state - always

Idempotent deployment: same template, same outcome - regardless of current state.

PS> New-AzResourceGroupDeployment -WhatIf -TemplateFile main.bicep What-if output + Microsoft.Automation/automationAccounts will be created ~ Microsoft.KeyVault/vaults/myVault sku: Standard -> Premium - Microsoft.Storage/storageAccounts/old will be deleted = 3 resource(s) unchanged Always run what-if on new or modified templates No resources change during a what-if run. Deletions and modifications are flagged before deployment.

What-if preview: every change flagged before deployment runs.

Bicep

Bicep is a Domain Specific Language that compiles to ARM JSON. It provides a much more readable and maintainable authoring experience.

ARM JSON "resources": [{ "type": "Microsoft.Automation/... "apiVersion": "2023-11-01", "dependsOn": [ "[resourceId(... "principalId": "[reference(res... "roleDefinitionId": "[concat... /subscriptions/[subscription... /providers/Microsoft.Auth... ~80 lines • nested resourceId() calls Bicep resource aa 'Microsoft.Automation/ automationAccounts@2023-11-01' = { identity: { type: 'SystemAssigned' } } resource role 'Microsoft.Auth/ roleAssignments@2022-04-01' = { principalId: aa.identity.principalId } ~25 lines • symbolic refs • IntelliSense

Bicep authors cleaner; the same ARM engine deploys.

The same Automation Account in Bicep:

param automationAccountName string
param location string = resourceGroup().location

resource automationAccount 'Microsoft.Automation/automationAccounts@2023-11-01' = {
  name: automationAccountName
  location: location
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    sku: {
      name: 'Basic'
    }
  }
}

output principalId string = automationAccount.identity.principalId

Bicep advantages over ARM JSON:

Bicep modules

Bicep modules allow you to compose large deployments from reusable files:

// main.bicep
module automationModule 'modules/automation.bicep' = {
  name: 'automationDeploy'
  params: {
    accountName: 'my-automation-account'
    location: location
  }
}

A common Bicep pattern is to separate concerns into modules such as compute, storage, and RBAC. In azd-maester, the exact /infra layout varies by solution folder, so inspect the selected solution instead of assuming every template uses the same module breakdown.

main.bicep parent template compute.bicep Automation Account storage.bicep Storage + reports rbac.bicep Role assignments module outputs flow back to parent · chain to next module Separation of concerns Compute · Storage · Identity · RBAC Reusable & testable Pass params · get outputs Common pattern; inspect the chosen solution's /infra for exact layout

Bicep module pattern: parent calls child modules with params, collects outputs.

main.bicep - VS Code + Bicep extension 1 resource aa 'Microsoft.Automation/ 2 automationAccounts@ 2023-11-01 (latest) 2022-08-08 2021-06-22 3 name: aaName 4 location: location 5 identity: { 6 type: 'SystemAssigned' required property surfaced inline by schema 7 } ARM API schema pulled live resource types, API versions, and required properties ARM JSON (manual) little guidance, easy to miss details Bicep + IntelliSense schema-guided authoring in the editor

Bicep VS Code IntelliSense: live schema, valid API versions, required properties surfaced inline.

Idempotent deployments

Running the same Bicep template twice produces the same result without errors. If the resource already exists, ARM updates it to match the desired state. If it does not exist, ARM creates it. This makes Bicep templates safe to run repeatedly and ideal for CI/CD pipelines.

What-if deployments

Before running a deployment, preview what it will create, modify, or delete:

az deployment group what-if \
  --resource-group myRG \
  --template-file main.bicep \
  --parameters automationAccountName=my-aa

Output shows:
- Green: new resources to create
- Yellow: existing resources to modify
- Red: resources to delete

Run what-if before every first deployment of a new template.

Azure Developer CLI (azd)

The Azure Developer CLI bundles infrastructure-as-code (Bicep), application code, and CI/CD pipeline configuration into a single deployable, shareable template.

single command azd up Phase 1 Provision - Bicep deploys Azure resources Phase 2 Deploy - push application code Phase 3 Pipeline - configure CI/CD (WIF) Before azd az deployment group create + deploy code separately + configure GitHub manually 3 steps · error-prone With azd azd up All three phases in sequence Repeatable · shareable

azd up: one command replaces three error-prone manual phases.

my-solution/ (azd root) azure.yaml (service map) /infra (Bicep templates) main.bicep, modules/ /src (app code) runbooks/, functions/ Maps services to infra and codeazd reads this to know what to deploy Infrastructure as Code (Bicep)Defines resources, RBAC, identities Application codeRunbooks, Functions, scripts azd up = provision + deployOne command deploys everything ✓

Three-part azd template structure: azure.yaml manifest, /infra for Bicep, /src for code.

Install:

winget install microsoft.azd   # Windows
brew tap azure/azd && brew install azd   # macOS

Core command set

Command Purpose
azd init -t <template> Clone a template from GitHub
azd auth login Authenticate with Azure
azd provision Deploy infrastructure only (Bicep)
azd deploy Deploy application code only
azd up Provision infrastructure and deploy code in one step
azd down Tear down all provisioned resources
azd pipeline config Configure GitHub Actions or Azure DevOps WIF pipeline
azd env list List environments (dev, staging, prod)

azure.yaml structure

In azd-maester, the repository root is a template chooser. Each solution folder has its own deployable azure.yaml. The recommended automation-account solution looks like this:

name: maester-automation-account
metadata:
  template: maester-automation-account@0.0.1
infra:
  provider: bicep
  path: infra
workflows:
  up:
    - azd: provision
hooks:
  preup:
    shell: pwsh
    run: ./scripts/Run-AzdPreUp.ps1
    interactive: true
  preprovision:
    shell: pwsh
    run: ./scripts/Run-AzdPreProvision.ps1
    interactive: true
  postprovision:
    shell: pwsh
    run: ./scripts/Run-AzdPostProvision.ps1
    interactive: true
  predown:
    shell: pwsh
    run: ./scripts/Run-AzdPreDown.ps1
    interactive: true

The repository-root azure.yaml is intentionally not deployable: it runs a guard script that tells you to cd into automation-account, container-app-job, function-app, or azure-devops before running azd up.

azure.yaml name: maester-automation-account infra: provider: bicep path: infra hooks: preup: shell: pwsh run: ./scripts/Run-AzdPreUp.ps1 postprovision: run: ./scripts/Run-AzdPostProvision.ps1 deploy from a solution folder, not the repo root preup preprovision predown Hook lifecycle preprovision -> provision -> postprovision predeploy -> deploy -> postdeploy

azure.yaml: name, infra, and hooks describe the deployable solution.

azd init-t templateClone template azd authloginAuthenticate azd provision(Bicep deploy)Create resources azd deploy(push code)Deploy app code ✓ Runningin AzureFull solution live azd up = provision + deploy ↑ azd down = teardown azd pipeline config = WIF setup

azd deployment phases: init, auth, provision, deploy, plus pipeline config and teardown shortcuts.

azd init -t template Clone template azd auth login Authenticate azd provision Bicep → ARM Create resources azd deploy Push code Deploy app code ✓ Running in Azure Full solution live azd up = provision + deploy Additional Commands azd down Tear down all provisioned resources azd pipeline config Configure WIF for GitHub/DevOps CI/CD azd monitor Open Application Insights dashboard azd init → azd auth login → azd up → done Three commands to go from zero to a running solution - shareable with anyone

Core azd command set: azd up combines provision and deploy, the rest support the lifecycle.

azd pipeline config

Running azd pipeline config automatically:

  1. Creates an app registration or uses an existing one.
  2. Configures a federated credential with a scoped subject claim for your GitHub repository.
  3. Sets repository variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_SUBSCRIPTION_ID).
  4. Generates a workflow YAML file in .github/workflows/.

This is the same WIF pattern from Section 4, automated for the azd deployment context. The generated subject claim is scoped to the specific repository.

runs once azd pipeline config App Registration Entra ID identity for the pipeline Federated Credential scoped to repo · no client secret Repository Variables set AZURE_CLIENT_ID · AZURE_TENANT_ID · AZURE_SUBSCRIPTION_ID Workflow YAML generated azure/login with WIF · zero secrets in repo No client secrets - anywhere GitHub Actions authenticates via OIDC token exchange subject claim scoped to the specific repository

azd pipeline config automates WIF setup: federated credential replaces client secrets entirely.

Example solutions

Emergency Access CA Exclusion Management

Three implementations ensure break-glass accounts remain excluded from all Conditional Access policies:

  1. Scheduled Logic App (emergency-access-exclusion.json): runs on a schedule to check and remediate CA policy exclusions. Best for: regular remediation with minimal operational complexity.
  2. Sentinel-triggered Logic App (emergency-access-exclusion-sentinel.json): triggers only when a CA policy change event fires in Sentinel. More efficient and near-real-time.
  3. PowerShell runbook (emergency-access-exclusion.ps1): runs in an Automation Account, schedulable or webhook-triggered.

All implementations use managed identity with scoped Graph API permissions to read and modify CA policies.

Source: https://github.com/nathanmcnulty/nathanmcnulty/tree/main/Entra/emergency-access

Identity Governance and Entitlement Management

Automation patterns for Entra Entitlement Management:

Demonstrates: Graph Identity Governance API, access package creation and assignment, attribute-driven access control without manual IT intervention.

Source: https://github.com/PatriotConsultingTech/Community/tree/main/Webinars/2025/AccessManagement

Intune Remediations and Log Analytics data pipeline

Intune Remediations (detection + remediation PowerShell script pairs) function as a lightweight endpoint telemetry pipeline. A detection script collects Defender for Endpoint performance metrics from each managed endpoint and uploads to Log Analytics or Azure Blob Storage via REST API - no additional agent required.

Two upload patterns:
- Log Analytics Data Collector API with workspace shared key
- Azure Monitor Logs Ingestion API (DCR-based) for schema-validated ingestion

This demonstrates that endpoints are API clients like any cloud automation workload - the token and REST API patterns from this course apply at the endpoint layer.

Source: https://github.com/nathanmcnulty/nathanmcnulty/tree/main/DefenderForEndpoint/Performance

Key Vault-backed passkeys and XDRInternals

This advanced pattern enables delegated-user-style automation with phishing-resistant credentials for APIs that require user context rather than app-only access.

Two components:

  1. Key Vault-backed FIDO2 passkeys: instead of a hardware security key, the ECDSA private key material lives in Azure Key Vault. An Automation Account with managed identity access retrieves the key material and performs FIDO2/WebAuthn authentication headlessly.
    - Initialize-PasskeyKeyVault.ps1: configures the vault with the required EC key type
    - Register-KeyVaultPasskeyViaTAP.ps1: registers the passkey using a Temporary Access Pass
    - PasskeyLogin.ps1: performs headless authentication using the vault-stored key

  2. XDRInternals PowerShell module: wraps Defender XDR portal internal APIs for automated advanced hunting, incident management, and security operations tasks not yet exposed through the official Graph Security API.

Key Vault contains the passkey private key Treat it as a credential store access controls, audit logs, and purge protection all apply Key Vault RBAC with least-privilege access soft-delete and purge protection enabled diagnostic logs sent to Log Analytics alerts on unexpected key or secret access private key in Key Vault = credential handling obligations

Key Vault holding the passkey private key carries credential-store obligations.

⚠️Risk - Key Vault as Credential Equivalent

The Key Vault containing the passkey private key is functionally equivalent to the user's credentials. Anyone with access to that Key Vault can authenticate as that user. Apply strict RBAC, audit logging, and Privileged Identity Management to both the Key Vault and the automation account that accesses it.

Source: https://github.com/nathanmcnulty/nathanmcnulty/tree/main/Entra/passkeys/keyvault
Source: https://github.com/MSCloudInternals/XDRInternals

azd + Maester

Maester is a PowerShell security testing framework built on Pester with 286+ automated configuration tests for Microsoft 365 and Entra, mapped to MITRE ATT&CK. The azd-maester project packages Maester into four ready-to-deploy azd templates:

All templates use managed identities - no secrets. After you cd into one of the four solution folders, one azd up command deploys that solution's infrastructure, permissions, and scheduling.

azd-maester deployment options Automation Account Recommended System-Assigned MI No secrets · PS 7.x runtime Container App Job Runs on schedule Managed identity Function App HTTP / timer trigger Managed identity Azure DevOps Pipeline agent Service connection 286+ security tests MITRE ATT&CK mapped findings actionable posture report one command cd solution → azd up → infra + perms + schedule Microsoft 365 · Entra ID · Intune · Teams continuous security posture monitoring

azd-maester: four deployment options, one command, same managed-identity foundation.

command azd up Resource Group Automation Account PowerShell 7.x runtime Hosts Maester runbook System-Assigned MI No secrets, no certificates Created with AA Graph API Permissions Assigned via post-provision hook Read-only: Directory, Policy, etc. Scheduled Trigger Maester Security Report 286+ tests / MITRE ATT&CK mapped Defined across azure.yaml, infra/main.bicep, and postprovision hooks azure.yaml infra/main.bicep scripts/Run-AzdPostProvision.ps1

What azd-maester deploys: Automation Account, MI, Graph permissions, schedule - one command.

Source: https://github.com/nathanmcnulty/azd-maester

New Device and MFA Notifications

Automation that sends real-time notifications to users and security teams when:

Demonstrates: Entra audit log monitoring via Log Analytics or Event Hubs, Logic App or Function App triggered on audit events, Graph API enrichment with device and user details, Teams adaptive card delivery.

Unified Audit Log monitoring

Automation to ensure UAL settings are correct across the tenant:

Demonstrates: Security and Compliance PowerShell, Exchange Online PowerShell, and scheduled Automation Account runbooks for compliance state validation.

Lab readiness notes

🧪Lab Readiness

Have Azure Developer CLI, Azure CLI, Git, PowerShell 7, and Contributor access to the target subscription or lab resource group available. This lab follows the upstream function-app quickstart: initialize the template, stay inside function-app, let the interactive azd up wizard create the environment, then inspect the deployed Function App and cleanup hooks.

Guided lab

Lab goal

Initialize azd-maester with azd init -t nathanmcnulty/azd-maester, move into the function-app solution, deploy it with azd up, re-run azd up with additional options to show that the deployment is idempotent, inspect the Bicep files and azd hook outputs that drove the deployment, and then cleanly remove the environment with azd down.

Prerequisites

Task 1: Initialize azd-maester and enter the function-app solution

Azure Developer CLI:

Initialize from the template, move into the solution folder, and sign in
azd init -t nathanmcnulty/azd-maester
Set-Location .\azd-maester\function-app

azd env new lab-maester-func
azd auth login

If azd init prompts for an environment name at the repository root, enter any disposable placeholder such as lab-maester-root. The deployable function-app folder keeps its own local azd environment, so azd env new lab-maester-func is the environment that the rest of this lab uses.

🧭Multi-solution repo note

The repository root is intentionally not deployable. If you run azd up from the root, the guard script stops the run and tells you to choose a solution folder. Stay inside function-app for the rest of the lab.

Expected outcomes:
- The template is cloned locally into .\azd-maester
- The deployable function-app folder now has a selected local azd environment named lab-maester-func
- You are authenticated to Azure Developer CLI for the current tenant
- Your shell is now scoped to the deployable function-app solution

Task 2: Deploy the function-app solution with azd up

Azure Developer CLI:

Run the interactive quickstart deployment
azd up

# Review the environment values and generated artifacts after deployment finishes.
azd env get-values
Get-ChildItem .\outputs

Recommended wizard responses for the first pass

  1. Azure subscription: choose the lab subscription
  2. Resource group: use the prepared lab resource group, or create a new one if your environment requires it
  3. Include Web App: No
  4. Include Exchange: No
  5. Include Teams: No
  6. Include Azure: No
  7. Optional mail recipient: leave blank

Expected outcomes:
- azd up runs the solution's pre-up, pre-provision, provision, post-provision, and deploy workflow from the function-app folder
- azd env get-values shows the environment-scoped resource names and identifiers
- The outputs folder contains the setup summary produced by the solution hooks

Task 3: Re-run azd up to add the Web App and Azure access

This task demonstrates idempotent deployment behavior. Re-run azd up in the same environment, keep the existing Function App resources, and add only the optional Web App and Azure RBAC pieces.

Azure Developer CLI and Azure CLI:

Prepare the rerun inputs and execute the second deployment
$resourceGroupName = (azd env get-values | Select-String '^AZURE_RESOURCE_GROUP=').Line.Split('=')[1].Trim('"')
$resourceGroupId = az group show --name $resourceGroupName --query id -o tsv
$securityGroupObjectId = "<lab-security-group-object-id>"

azd env set AZURE_RBAC_SCOPES $resourceGroupId
azd up

Recommended rerun responses

  1. Include Web App: Yes
  2. Security group object ID: paste $securityGroupObjectId
  3. Include Exchange: No
  4. Include Teams: No
  5. Include Azure: Yes
  6. Azure RBAC scopes: use $resourceGroupId if prompted
  7. Optional mail recipient: leave blank

Expected outcomes:
- The second azd up is idempotent: unchanged Function App resources stay in place while the optional Web App and Azure RBAC settings are added
- The environment now carries AZURE_RBAC_SCOPES for future reruns and pipeline use
- The rerun proves that azd updates the declared environment instead of creating a second parallel stack

🔁Idempotence Note

This solution is additive across reruns. Turning an include from No to Yes adds the new resources and assignments without breaking the existing deployment. Turning an include back to No later does not revoke previously granted access; cleanup happens during azd down.

Task 4: Inspect the Bicep and function files

Native PowerShell:

Inspect the Bicep files and timer trigger that drove the deployment
Get-ChildItem .\infra -Recurse -Filter *.bicep | Select-Object FullName
Get-Content .\infra\main.bicep
Get-Content .\src\MaesterTimerTrigger\function.json

Azure Portal:

Match the deployed resources to the Bicep definitions
  1. Open the deployed resource group from AZURE_RESOURCE_GROUP.
  2. Open the Function App and review Functions, Identity, and the deployed app settings.
  3. Open the Storage Account and confirm it matches the supporting resources declared in Bicep.
  4. Compare the deployed resources with the Bicep resources, outputs, and timer schedule.

Expected outcomes:
- The resource group contents line up with the Bicep file structure
- The Function App uses managed identity rather than a stored secret or certificate
- The timer trigger schedule in function.json explains when Maester runs after deployment

Task 5: Review the azd hooks and validation outputs

Native PowerShell:

Inspect the scripts and generated files that azd used around the deployment
Get-ChildItem .\scripts | Select-Object Name
Get-ChildItem .\outputs | Select-Object Name
Get-Content .\scripts\Invoke-FunctionValidation.ps1 -TotalCount 80

Expected outcomes:
- You can identify the hook and deployment script files that azd calls before and after provisioning
- The validation script shows how the project checks the Function App after deployment
- The generated setup summary in outputs\<env>-setup-summary.md gives you a readable record of what the solution configured

Task 6: Tear down the environment

Azure Developer CLI:

Remove the Azure resources and the local azd environment state
$environmentName = "lab-maester-func"

azd down -e $environmentName --force --purge
azd env remove $environmentName --force

Expected outcomes:
- The resource group and Function App resources are deleted cleanly
- The solution's best-effort cleanup hooks run before resource deletion
- The local azd environment state is removed after azd env remove

Common pitfalls

Admin takeaways

Key Principles 1. No client secrets for Azure workloads managed identity and WIF replace static credentials 2. ARM is the foundation layer portal, CLI, PowerShell, and SDKs all call management.azure.com 3. Bicep beats raw ARM JSON for authoring same engine, better readability, and IntelliSense guidance 4. azd up makes solutions portable repeatable provisioning, code deployment, and CI/CD setup 5. Key Vault can be a credential store treat private keys, tokens, and secrets with the same controls Apply these patterns directly to production environments

Course key takeaways: the five principles to apply directly in production.

Quick recap questions

  1. What is Azure Resource Manager and why does understanding it matter for automation?
  2. What does Bicep compile to and what are three advantages Bicep has over raw ARM JSON?
  3. What does azd up do in a single command?
  4. What is the structure of an azd template? Name the three main components.
  5. Why must the Key Vault in the Key Vault-backed passkey pattern be treated as a credential store?
  6. What does azd pipeline config configure automatically?

Key reminders

Current source notes

Volatile platform behavior and dated claims in this section were checked against these current sources on April 26, 2026:

References

References Appendix

All links below were reviewed on 2026-03-10. Microsoft Learn and Microsoft documentation are the primary sources. Community and project references are included where they add operational context or point to actively maintained tooling.

Microsoft documentation: Azure Resource Manager

Microsoft documentation: ARM Templates (JSON)

Microsoft documentation: Bicep

Microsoft documentation: Azure Developer CLI (azd)

Microsoft documentation: Azure Automation and managed identity

Microsoft documentation: Key Vault

Microsoft documentation: app-only tokens and management.azure.com

Community and project references: Maester

Community and project references: azd-maester

Community and project references: Key Vault-backed passkeys and XDRInternals

Section 6 - Packaging Tools and azd - Reference Guide