New "Azd best practices" skill (#2549)

* Add Azure Developer CLI skill and related documentation

* Add Azure Developer CLI skill to README with usage instructions and bundled assets

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Massimo Bonanni
2026-08-06 05:19:37 +02:00
committed by GitHub
parent 9db369d00f
commit 6c7fe1b15f
7 changed files with 744 additions and 0 deletions
+1
View File
@@ -72,6 +72,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to
| [azure-architecture-autopilot](../skills/azure-architecture-autopilot/SKILL.md)<br />`gh skills install github/awesome-copilot azure-architecture-autopilot` | Design Azure infrastructure using natural language, or analyze existing Azure resources to auto-generate architecture diagrams, refine them through conversation, and deploy with Bicep.<br />When to use this skill: - "Create X on Azure", "Set up a RAG architecture" (new design) - "Analyze my current Azure infrastructure", "Draw a diagram for rg-xxx" (existing analysis) - "Foundry is slow", "I want to reduce costs", "Strengthen security" (natural language modification) - Azure resource deployment, Bicep template generation, IaC code generation - Microsoft Foundry, AI Search, OpenAI, Fabric, ADLS Gen2, Databricks, and all Azure services | `.gitignore`<br />`assets/06-architecture-diagram.png`<br />`assets/07-azure-portal-resources.png`<br />`assets/08-deployment-succeeded.png`<br />`references/ai-data.md`<br />`references/architecture-guidance-sources.md`<br />`references/azure-common-patterns.md`<br />`references/azure-dynamic-sources.md`<br />`references/bicep-generator.md`<br />`references/bicep-reviewer.md`<br />`references/phase0-scanner.md`<br />`references/phase1-advisor.md`<br />`references/phase4-deployer.md`<br />`references/service-gotchas.md`<br />`scripts/cli.py`<br />`scripts/generator.py`<br />`scripts/icons.py` |
| [azure-container-registry-cli](../skills/azure-container-registry-cli/SKILL.md)<br />`gh skills install github/awesome-copilot azure-container-registry-cli` | Manage Azure Container Registry via the az acr CLI including registries, images, cloud builds, ACR Tasks, authentication, tokens, geo-replication, and networking. Use when working with ACR, az acr commands, pushing/importing/purging container images in Azure, or when the user mentions Azure Container Registry. | `references/auth-and-security.md`<br />`references/build-and-tasks.md`<br />`references/images-and-artifacts.md`<br />`references/networking-and-geo.md` |
| [azure-deployment-preflight](../skills/azure-deployment-preflight/SKILL.md)<br />`gh skills install github/awesome-copilot azure-deployment-preflight` | Performs comprehensive preflight validation of Bicep deployments to Azure, including template syntax validation, what-if analysis, and permission checks. Use this skill before any deployment to Azure to preview changes, identify potential issues, and ensure the deployment will succeed. Activate when users mention deploying to Azure, validating Bicep files, checking deployment permissions, previewing infrastructure changes, running what-if, or preparing for azd provision. | `references/ERROR-HANDLING.md`<br />`references/REPORT-TEMPLATE.md`<br />`references/VALIDATION-COMMANDS.md` |
| [azure-developer-cli](../skills/azure-developer-cli/SKILL.md)<br />`gh skills install github/awesome-copilot azure-developer-cli` | Design, create, review, migrate, or troubleshoot Azure Developer CLI (azd) projects using current Microsoft guidance. Use for azd, azure.yaml, AZD templates, Bicep or Terraform under infra, AZD environments and secrets, hooks, deployment workflows, and azd-managed CI/CD. | `examples`<br />`references/iac-and-environments.md`<br />`references/official-docs.md`<br />`references/project-structure.md`<br />`references/security-cicd-operations.md` |
| [azure-devops-cli](../skills/azure-devops-cli/SKILL.md)<br />`gh skills install github/awesome-copilot azure-devops-cli` | Manage Azure DevOps resources via CLI including projects, repos, pipelines, builds, pull requests, work items, artifacts, and service endpoints. Use when working with Azure DevOps, az commands, devops automation, CI/CD, or when user mentions Azure DevOps CLI. | `references/advanced-usage.md`<br />`references/boards-and-iterations.md`<br />`references/long-comments-on-windows.md`<br />`references/org-and-security.md`<br />`references/pipelines-and-builds.md`<br />`references/repos-and-prs.md`<br />`references/variables-and-agents.md`<br />`references/workflows-and-patterns.md` |
| [azure-pricing](../skills/azure-pricing/SKILL.md)<br />`gh skills install github/awesome-copilot azure-pricing` | Fetches real-time Azure retail pricing using the Azure Retail Prices API (prices.azure.com) and estimates Copilot Studio agent credit consumption. Use when the user asks about the cost of any Azure service, wants to compare SKU prices, needs pricing data for a cost estimate, mentions Azure pricing, Azure costs, Azure billing, or asks about Copilot Studio pricing, Copilot Credits, or agent usage estimation. Covers compute, storage, networking, databases, AI, Copilot Studio, and all other Azure service families. | `references/COPILOT-STUDIO-RATES.md`<br />`references/COST-ESTIMATOR.md`<br />`references/REGIONS.md`<br />`references/SERVICE-NAMES.md` |
| [azure-resource-health-diagnose](../skills/azure-resource-health-diagnose/SKILL.md)<br />`gh skills install github/awesome-copilot azure-resource-health-diagnose` | Analyze Azure resource health, diagnose issues from logs and telemetry, and create a remediation plan for identified problems. | None |
+134
View File
@@ -0,0 +1,134 @@
---
name: azure-developer-cli
description: 'Design, create, review, migrate, or troubleshoot Azure Developer CLI (azd) projects using current Microsoft guidance. Use for azd, azure.yaml, AZD templates, Bicep or Terraform under infra, AZD environments and secrets, hooks, deployment workflows, and azd-managed CI/CD.'
license: MIT
---
# Azure Developer CLI best practices
Use this skill to produce maintainable, secure, environment-aware `azd` projects. Prefer repository conventions when they are already coherent, and make the smallest complete change that improves the project.
## Start with repository discovery
Before editing:
1. Find `azure.yaml`, the configured `infra.path`, source projects, deployment scripts, `.gitignore`, and pipeline definitions.
2. Read `azure.yaml` before inferring services or the IaC provider.
3. Identify whether the task is to create, migrate, review, deploy, or troubleshoot.
4. Identify the active environment only when an environment-specific operation is required.
5. Read the relevant reference:
- Repository layout or `azure.yaml`: [references/project-structure.md](references/project-structure.md)
- Bicep, Terraform, parameters, outputs, or environments: [references/iac-and-environments.md](references/iac-and-environments.md)
- Secrets, hooks, CI/CD, deployment, or troubleshooting: [references/security-cicd-operations.md](references/security-cicd-operations.md)
- Product details that may have changed: [references/official-docs.md](references/official-docs.md)
Do not assume the default `infra` path, the default Bicep provider, or a single service when `azure.yaml` says otherwise.
## Apply safety guardrails
- Never commit `.azure`, environment `.env` files, credentials, deployment outputs containing secrets, local Terraform state, or generated deployment artifacts.
- Never put literal secrets in `azure.yaml`, IaC parameter files, hooks, source control, command arguments that will be logged, or IaC outputs.
- Prefer managed identities and RBAC. Use Key Vault references and `azd env set-secret` when a secret is unavoidable.
- Before a command that can create, modify, or delete Azure resources, confirm the target environment, subscription, tenant, region, and expected scope.
- Treat an explicit user request to deploy, provision, destroy, or configure a pipeline as approval for that named action. Otherwise, ask before running `azd up`, `azd provision`, `azd deploy`, `azd down`, or `azd pipeline config`.
- Do not replace Bicep with Terraform, Terraform with Bicep, or an established hosting service unless the user requests that architectural change.
- Preserve resources and state owned outside the current `azd` project.
## Use these defaults
| Concern | Preferred default |
| --- | --- |
| Project manifest | One `azure.yaml` at the repository root |
| Application code | `src/<service-name>` per independently deployable service |
| Infrastructure | `infra` with a thin entry point and reusable modules |
| IaC provider | Bicep unless the repository or user chooses Terraform |
| Deployment environments | Separate named environments for dev, test, staging, and production |
| Local AZD state | `.azure/<environment-name>` and excluded from source control |
| Shared environment state | AZD remote environments backed by Azure Blob Storage |
| Secrets | Managed identity/RBAC first, then Key Vault references |
| Automation scripts | Short, idempotent scripts under `scripts/azd` |
| CI authentication | Workload identity federation/OIDC where supported |
| Routine development | `azd up` for simple workflows; separate phases for controlled workflows |
## Implementation workflow
### 1. Model the application
- Define one `services` entry for each independently deployable component.
- Keep service keys stable because they participate in resource discovery and deployment.
- Map each service to its actual `project`, `language`, and `host`.
- Keep shared infrastructure in IaC rather than inventing a fake deployable service.
- Declare dependencies with supported `azure.yaml` fields instead of relying on file order.
### 2. Model infrastructure
- Keep `main.bicep` or `main.tf` as the orchestration entry point.
- Split reusable or independently understandable infrastructure into modules.
- Parameterize environment-specific values; do not fork the IaC tree per environment.
- Output only stable, nonsecret values required by deployment or application configuration.
- Use deterministic naming and consistent tags that include the project and environment.
- Add role assignments to identities rather than distributing service keys.
- Use infrastructure layers only when separate scopes or lifecycle dependencies justify them.
### 3. Model environments
- Use predictable names such as `<project>-dev` for shared environments and `<alias>-dev` for personal environments.
- Use `azd env set`, `azd env unset`, and `azd env set-secret` rather than editing `.env` directly.
- Use `-e` or `--environment` in scripts and automation so the target is explicit.
- Use `azd env refresh` to synchronize deployment outputs after another actor changes an environment.
- Configure AZD remote state when a team shares environment state.
### 4. Add hooks only for lifecycle gaps
- Prefer declarative IaC and native service configuration over hooks.
- Use root hooks for project-wide behavior and service hooks for service-specific behavior.
- Keep nontrivial hook logic in versioned scripts under `scripts/azd`.
- Set `shell` explicitly. Provide `windows` and `posix` variants when necessary.
- Make hooks idempotent, noninteractive in CI, and fail on errors unless failure is intentionally nonblocking.
- Test a hook independently with `azd hooks run <hook-name>`.
### 5. Build CI/CD deliberately
- Keep the pipeline definition with the template and review generated changes from `azd pipeline config`.
- Use short-lived federated credentials where the provider supports them.
- Run tests and IaC validation before provisioning.
- Use explicit environments and `--no-prompt` in automation.
- Add protected production environments and approval gates.
- For Terraform, configure protected remote state before pipeline setup and account for current AZD authentication limitations.
## Validate before finishing
Run only checks applicable to the repository:
```text
Application: existing formatter, linter, type-check, build, and tests
Bicep: az bicep build --file infra/main.bicep
Terraform: terraform fmt -check -recursive
terraform init -backend=false
terraform validate
AZD hooks: azd hooks run <hook-name>
Packaging: azd package
```
For a Bicep what-if or Terraform plan, choose the correct deployment scope and environment. These checks can authenticate to Azure or read remote state, so follow the safety guardrails.
Verify that:
- `azure.yaml` paths exist and service settings match the source projects.
- The IaC entry point and provider agree with `azure.yaml`.
- Required deployment outputs match the variables consumed by services, hooks, and pipelines.
- `.gitignore` excludes `.azure`, secrets, local state, and generated artifacts.
- No secret appears in tracked content or command output.
- Documentation explains prerequisites, environment creation, deployment, verification, and cleanup.
## Report the result
State:
- The files and behavior changed.
- The IaC provider and environment assumptions.
- The checks performed.
- Any cloud-changing command deliberately not run.
- Any beta or preview feature the solution relies on.
Do not claim deployment success unless the target environment was actually deployed and verified.
@@ -0,0 +1,33 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
name: sample-app
infra:
provider: bicep
path: ./infra
module: main
services:
api:
project: ./src/api
language: ts
host: appservice
web:
project: ./src/web
dist: dist
language: ts
host: staticwebapp
# Add hooks only when the default lifecycle cannot express the requirement.
# Keep nontrivial commands in scripts/azd and provide both OS variants.
hooks:
preprovision:
windows:
shell: pwsh
run: ./scripts/azd/validate.ps1
interactive: false
continueOnError: false
posix:
shell: sh
run: ./scripts/azd/validate.sh
interactive: false
continueOnError: false
@@ -0,0 +1,212 @@
# Infrastructure as code and environments
## Choose the provider deliberately
### Bicep
Use Bicep when:
- The project is Azure-only.
- Native Azure resource coverage and immediate API support matter.
- The team wants a stateless deployment model.
- Azure Verified Modules cover common resource patterns.
Bicep is AZD's default IaC provider.
### Terraform
Use Terraform when:
- The repository already uses Terraform.
- The team has established Terraform module, state, policy, and review practices.
- Cross-provider infrastructure is a real requirement.
Current Microsoft documentation marks AZD Terraform support as beta. Surface this constraint and do not migrate a project to Terraform merely for familiarity.
## Bicep structure
Keep `main.bicep` as an orchestration layer:
```text
infra/
|-- main.bicep
|-- main.parameters.json
|-- modules/
| |-- core/
| |-- data/
| |-- identity/
| |-- observability/
| |-- services/
```
### Bicep practices
- Declare the deployment `targetScope` intentionally.
- Use modules for cohesive capabilities and repeated patterns.
- Prefer Azure Verified Modules when they meet the requirement and the team accepts their versioning model.
- Pin module versions; review upgrades rather than floating automatically.
- Add descriptions and validation decorators to parameters.
- Pass parameters down through modules instead of reading AZD environment variables inside every module.
- Use deterministic names that respect each resource type's length and character constraints.
- Use `uniqueString` with stable scope inputs where global uniqueness is required.
- Apply consistent project, environment, owner, and cost tags when policy allows.
- Use managed identities and narrowly scoped role assignments.
- Avoid keys and connection strings when identity-based access is available.
- Output resource IDs, names, and endpoints required by later phases.
- Never output secret values. Deployment outputs are copied into the AZD environment.
### Parameter flow
Use `main.parameters.json` to map AZD environment values into Bicep:
```json
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"environmentName": {
"value": "${AZURE_ENV_NAME}"
},
"location": {
"value": "${AZURE_LOCATION}"
}
}
}
```
Match those values in the entry point:
```bicep
@description('Stable name of the AZD deployment environment.')
@minLength(1)
param environmentName string
@description('Primary Azure region for this deployment.')
param location string
```
Use outputs as the contract between provisioning and later AZD phases:
```bicep
output SERVICE_API_ENDPOINT_URL string = api.outputs.endpoint
```
Choose stable output names because services, hooks, and pipelines may consume them as environment variables.
When using AZD environment secrets with Bicep:
- Mark the Bicep input with `@secure()`.
- Map the AZD secret reference through `main.parameters.json`.
- Do not output the secure value.
- Be aware that current AZD documentation says environment secrets are not supported with `.bicepparam` files.
## Terraform structure and state
### Terraform practices
- Set `infra.provider: terraform` explicitly in `azure.yaml`.
- Keep all AZD-managed `.tf` files under the configured infrastructure path.
- Pin Terraform and provider versions and commit the dependency lock file.
- Use modules with clear inputs and outputs.
- Mark sensitive variables and outputs as `sensitive`, but remember that sensitive values can still exist in state.
- Do not commit `.tfstate`, plan files, crash logs, or provider credentials.
- Avoid splitting ownership of the same Azure resource between AZD and an unrelated Terraform root module.
### Authentication
Terraform's Azure provider uses Azure CLI authentication by default and does not use the AZD credential cache. Prefer the documented single-sign-in configuration:
```text
azd config set auth.useAzCliAuth true
az login
```
Otherwise, both `azd auth login` and `az login` are required.
### Remote state
Configure a protected remote backend before `azd pipeline config` or collaborative deployments:
- Use a dedicated storage account and private container where appropriate.
- Restrict access with RBAC and network controls.
- Enable platform protections such as versioning, soft delete, and resource locks according to organizational policy.
- Use a distinct state key per project and environment.
- Treat state as sensitive data.
- Do not store backend access keys in source control.
AZD reads Terraform backend settings from `infra/provider.conf.json` when configured according to the official Terraform integration.
## Environment strategy
AZD stores local environment state under:
```text
.azure/
|-- config.json
|-- <environment-name>/
|-- .env
|-- config.json
```
The entire `.azure` directory should remain out of source control.
### Naming
Use names that make ownership and lifecycle clear:
- Shared: `<project>-dev`, `<project>-test`, `<project>-prod`
- Personal: `<alias>-<purpose>` or `<alias>-dev`
- Ephemeral: `<project>-pr-<number>` when automation also guarantees cleanup
Keep the name short enough to support resources with restrictive naming limits.
### Management
Use AZD commands rather than manual file editing:
```text
azd env new <name>
azd env list
azd env select <name>
azd env set <key> <value>
azd env get-value <key>
azd env unset <key>
azd env refresh
```
In automation and potentially destructive operations, target the environment explicitly:
```text
azd provision -e <environment> --no-prompt
azd deploy -e <environment> --no-prompt
```
### Configuration rules
- Keep one IaC codebase and vary behavior through parameters.
- Keep nonsecret defaults in reviewed configuration or IaC, not in committed `.azure` files.
- Use `azd env set` for deployment-specific nonsecret settings.
- Allow IaC outputs to populate computed resource names and endpoints.
- Avoid environment-name conditionals scattered across modules. Prefer explicit feature or SKU parameters.
- Use `azd env refresh` after another actor changes deployment outputs.
- Do not assume the currently selected environment in scripts.
## Shared and remote environments
Configure `state.remote` when teammates or automation need a shared AZD environment:
```yaml
state:
remote:
backend: AzureBlobStorage
config:
accountName: <storage-account-name>
containerName: <project-container-name>
```
Remote AZD state synchronizes `.env` and AZD `config.json`; it is separate from Terraform remote state. A Terraform project that collaborates through AZD can require both:
- AZD remote state for environment configuration.
- Terraform remote state for managed infrastructure state.
Protect both stores with least-privilege RBAC and appropriate data-protection settings.
@@ -0,0 +1,45 @@
# Official references
Use Microsoft Learn as the source of truth for AZD behavior and schema details. These references were reviewed on 2026-08-05.
## Core concepts and structure
- [Azure Developer CLI documentation](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/)
- [What is the Azure Developer CLI?](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview)
- [Azure Developer CLI templates overview](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/azd-templates)
- [Create Azure Developer CLI templates overview](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/make-azd-compatible)
- [Azure Developer CLI schema reference](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/azd-schema)
- [`azure.yaml` JSON schema](https://aka.ms/azure.yaml.json)
- [Explore the `azd up` workflow](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/azd-up-workflow)
- [Full-stack deployment with Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/full-stack-deployment)
## Infrastructure as code
- [Use Terraform as an infrastructure as code tool for Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/use-terraform-for-azd)
- [Azure Verified Modules](https://azure.github.io/Azure-Verified-Modules/)
- [Bicep documentation](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/)
- [Terraform on Azure documentation](https://learn.microsoft.com/en-us/azure/developer/terraform/)
## Environments and secrets
- [Azure Developer CLI environments overview](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/environments-overview)
- [Work with Azure Developer CLI environments](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/work-with-environments)
- [Work with Azure Developer CLI environment variables](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/manage-environment-variables)
- [Remote environments support](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/remote-environments-support)
- [Use environment secrets with Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/environment-secrets)
## Hooks, pipelines, and operations
- [Customize Azure Developer CLI workflows using hooks](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/azd-extensibility)
- [Explore Azure Developer CLI support for CI/CD pipelines](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/configure-devops-pipeline)
- [Create a GitHub Actions CI/CD pipeline using Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/pipeline-github-actions)
- [Advanced pipeline features and configurations](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/pipeline-advanced-features)
- [Azure Developer CLI command reference](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/reference)
- [Troubleshoot Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/troubleshoot)
## Skill format
- [Adding agent skills for GitHub Copilot](https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/customize-cloud-agent/add-skills)
- [About agent skills](https://docs.github.com/en/copilot/concepts/agents/about-agent-skills)
When a field, command flag, host type, preview status, or authentication behavior is uncertain, consult the relevant current reference before changing code. Do not rely on remembered syntax for fast-moving preview features.
@@ -0,0 +1,134 @@
# Project structure and `azure.yaml`
## Recommended repository layout
Use this as a default, not as a reason to reorganize an already coherent repository:
```text
.
|-- .azure/ # Generated local AZD environment state; ignored
|-- .devcontainer/ # Optional reproducible developer environment
|-- .github/
| |-- workflows/
| |-- azure-dev.yml # Optional GitHub Actions pipeline
|-- infra/
| |-- main.bicep # Bicep orchestration entry point
| |-- main.parameters.json # AZD environment-to-Bicep parameter mapping
| |-- modules/
| |-- core/ # Shared platform resources
| |-- app/ # Application-specific resources
|-- scripts/
| |-- azd/ # Hook and deployment helper scripts
|-- src/
| |-- api/ # Independently deployable service
| |-- web/ # Independently deployable service
|-- tests/
|-- .gitignore
|-- azure.yaml
|-- README.md
```
For Terraform, use a conventional `infra` layout:
```text
infra/
|-- main.tf
|-- providers.tf
|-- variables.tf
|-- outputs.tf
|-- provider.conf.json # AZD remote backend configuration, when used
|-- modules/
```
### Structure rules
- Place `azure.yaml` at the project root.
- Keep application source independent from deployment assets.
- Keep the IaC entry point small; move resource details into modules.
- Organize modules by responsibility or lifecycle, not one arbitrary file per resource.
- Keep hook scripts outside `infra` unless a script belongs exclusively to an infrastructure layer.
- Avoid committed environment-specific source trees such as `infra/dev`, `infra/test`, and `infra/prod`. Use parameters.
- Keep tests near their normal language conventions; do not move them merely to fit this example.
- Include `.devcontainer` only when it is maintained and tested.
## `azure.yaml` baseline
Add the schema directive for editor validation:
```yaml
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
name: sample-app
infra:
provider: bicep
path: ./infra
module: main
services:
api:
project: ./src/api
language: ts
host: appservice
web:
project: ./src/web
dist: dist
language: ts
host: staticwebapp
```
The explicit `infra` block is useful when clarity matters, even though Bicep, `infra`, and `main` are defaults.
## Manifest design checklist
### Top-level configuration
- `name` is lowercase, starts and ends with an alphanumeric character, and uses only alphanumerics and hyphens.
- `metadata.template` identifies the source template and version when the repository is distributed as a template.
- `infra.provider`, `infra.path`, and `infra.module` match the actual repository.
- `requiredVersions` is used when the project depends on a minimum AZD or extension version.
- `workflows` overrides defaults only when deployment ordering genuinely requires it.
- `state.remote` is configured at project scope when teams share AZD environments.
### Services
- A service represents deployable application code, not a database, Key Vault, or other shared resource.
- Service names are short, meaningful, and stable.
- `project` points to the service root and uses a relative path.
- `language`, `host`, `dist`, container, and remote-build settings match how the service is built.
- A Container Apps service uses either `project` or `image`, not both.
- `resourceName` is set only when standard AZD discovery through the `azd-service-name` tag is unavailable or intentionally bypassed.
- Dependencies use supported `uses` relationships rather than implicit assumptions.
- Environment variables use substitutions or IaC outputs rather than hard-coded environment values.
### Resources and infrastructure
- Shared Azure resources stay in IaC.
- Service modules and AZD service names align so resource discovery is predictable.
- Custom resource group names include environment identity and comply with Azure naming constraints.
- Infrastructure layers are reserved for independently provisioned units, different scopes, or hook-mediated dependencies.
- Layer dependencies are explicit with `dependsOn` when AZD cannot infer them.
### Pipelines and hooks
- `pipeline.variables` contains nonsecret configuration.
- `pipeline.secrets` is used only when the pipeline must store the resolved value instead of a Key Vault reference.
- Root hooks handle project-wide work; service hooks handle one service.
- Hook scripts use explicit shells and portable paths.
- Hooks do not duplicate application tests or declarative IaC behavior.
## README requirements for a reusable AZD project
Document:
1. Architecture and deployed Azure services.
2. Local prerequisites, including AZD and provider-specific tools.
3. Authentication requirements.
4. How to create or select an environment.
5. Required nonsecret variables and how to set them.
6. How secrets are supplied without exposing their values.
7. How to run, test, provision, deploy, monitor, and troubleshoot.
8. Expected cost-bearing resources.
9. How to clean up safely.
10. Any beta or preview dependencies, including Terraform or pipeline features when applicable.
Do not put actual subscription IDs, tenant IDs, secret names that reveal sensitive systems, or production endpoints in reusable documentation.
@@ -0,0 +1,185 @@
# Security, hooks, CI/CD, and operations
## Identity and secret handling
Use this order of preference:
1. Managed identity with least-privilege RBAC.
2. Workload identity federation for CI/CD.
3. Key Vault reference through `azd env set-secret`.
4. Short-lived secret material only when no identity-based option exists.
Never:
- Store a plaintext secret in `.azure/<environment>/.env`.
- Commit environment files, credentials, certificates, or Terraform state.
- Put secrets in IaC outputs.
- Echo environment values indiscriminately in hooks or pipelines.
- Pass a secret directly on a command line when the shell or CI system can record it.
- Grant broad subscription roles when resource-group or resource scope is enough.
`azd env set-secret <name>` stores a Key Vault reference in the AZD environment. Resolve it only where needed:
- Map it to an `@secure()` Bicep parameter.
- Use a hook `secrets` mapping for a hook process.
- Choose between a pipeline variable containing the Key Vault reference or a pipeline secret containing the resolved value.
Prefer the reference approach when the pipeline identity can read Key Vault because rotation does not require republishing a resolved pipeline secret.
## Hooks
Use hooks for validation, generated runtime configuration, data preparation, smoke checks, or lifecycle coordination that IaC and native AZD behavior cannot express.
### Hook rules
- Prefer external scripts over long inline commands.
- Store scripts under `scripts/azd`.
- Set `shell: sh` or `shell: pwsh` explicitly.
- Supply `windows` and `posix` implementations when syntax differs.
- Use paths relative to the documented hook working directory.
- Make scripts idempotent and safe to rerun.
- Keep `continueOnError` false unless the operation is observability-only or genuinely optional.
- Use noninteractive behavior in CI.
- Do not install unpinned dependencies on every run if a reproducible tool setup can do it once.
- Do not log secret values or all environment variables.
- Test with `azd hooks run <hook-name>` before coupling the hook to a complete deployment.
Example:
```yaml
hooks:
preprovision:
windows:
shell: pwsh
run: ./scripts/azd/validate.ps1
interactive: false
continueOnError: false
posix:
shell: sh
run: ./scripts/azd/validate.sh
interactive: false
continueOnError: false
```
Use root hooks for the whole project. Put service-specific hooks under that service's `azure.yaml` entry.
## Deployment workflow
The normal AZD lifecycle is:
1. Package application artifacts.
2. Provision or update infrastructure.
3. Deploy application artifacts.
`azd up` is the convenient combined workflow and is appropriate for routine development and simple deployments.
Use separate commands when:
- Infrastructure review or approval must happen before deployment.
- The application is redeployed frequently without infrastructure changes.
- Troubleshooting requires isolating package, provision, or deploy failures.
- A complex dependency requires a custom order.
```text
azd package
azd provision -e <environment>
azd deploy -e <environment>
```
Customize `workflows.up.steps` only when a real dependency requires another order, such as provisioning before a build that needs a generated endpoint. Do not customize the workflow merely to mirror a pipeline's naming conventions.
## Full-stack and multi-service dependencies
- Map service dependencies before implementation.
- Let Bicep or Terraform handle one-directional infrastructure dependencies.
- Use provisioning outputs for endpoints and names needed during deployment.
- Use runtime configuration, such as Azure App Configuration or a generated config file, when settings must change without rebuilding.
- Avoid circular compile-time dependencies between front-end and back-end services.
- Use hooks or a custom workflow only when outputs and runtime configuration cannot resolve the dependency.
- Test the strategy independently in development, test, and production-like environments.
## CI/CD
### Pipeline design
A robust pipeline separates:
1. Application format, lint, build, and tests.
2. IaC format and static validation.
3. What-if or plan review at the correct scope.
4. Provisioning with an explicit AZD environment.
5. Deployment.
6. Smoke or health verification.
7. Production approval and rollback/cleanup procedures.
Use:
- `--no-prompt` in automation.
- A fixed `-e` or `--environment`.
- Protected environments and required reviewers for production.
- Concurrency controls to prevent simultaneous writes to one environment.
- Least-privilege identities scoped to the target environment.
- Pinned action and tool versions with a managed update process.
### `azd pipeline config`
Current Microsoft documentation marks `azd pipeline config` as beta. Before running it:
- Review the pipeline definition bundled with the template.
- Confirm repository, organization, environment, subscription, and authentication mode.
- Expect repository, identity, variable, secret, commit, push, and pipeline side effects.
- Review generated workflow and permission changes before production use.
- Rerun it when `pipeline.variables` or `pipeline.secrets` changes.
For GitHub Actions, AZD configures OIDC/federated credentials by default for supported scenarios. Current documentation says the AZD Terraform pipeline flow does not support OIDC, so evaluate the authentication tradeoff explicitly rather than silently falling back to a long-lived credential.
For Terraform, configure protected remote state before pipeline setup.
## Validation and preview
Run local checks before Azure-changing commands:
### Bicep
```text
az bicep build --file infra/main.bicep
```
Use an Azure deployment what-if at the scope declared by the template. Do not assume resource-group scope.
### Terraform
```text
terraform fmt -check -recursive
terraform init -backend=false
terraform validate
```
Use `terraform plan` only after confirming the backend, workspace/state key, variables, and Azure identity.
### AZD and application
- Run existing application checks.
- Run relevant hooks independently.
- Run `azd package` to verify service paths and packaging.
- Confirm IaC outputs match variables consumed during deployment.
- Inspect the environment name before provision, deploy, or down.
## Troubleshooting sequence
1. Identify whether the failure is package, provision, deploy, hook, authentication, or resource discovery.
2. Re-run the smallest failing phase rather than `azd up`.
3. Check the selected environment and expected subscription, tenant, and region.
4. Check `azure.yaml` paths, provider, service names, host types, and resource discovery tags.
5. Refresh environment outputs with `azd env refresh` when Azure state changed elsewhere.
6. For Terraform, verify both AZD and Azure CLI authentication and the correct remote state.
7. For hooks, run the hook directly and verify its shell, working directory, and environment dependencies.
8. Use debug logging only when needed, and redact sensitive values before sharing logs.
## Cleanup
- Confirm the exact environment before `azd down`.
- Explain that cleanup can delete data-bearing resources.
- Preserve externally owned or shared resources.
- For ephemeral environments, automate cleanup and include a fallback for failed pipeline runs.
- Verify deletion rather than assuming command success.