azure-deploy

Deploy Azure infrastructure, BFF API, and configure App Service settings

SKILL.md

GitHub

Azure Deploy

Category: Operations Last Reviewed: 2026-05-17 Reviewed By: ai-procedure-quality-r1 (Phase 2b Wave 2c — refactored: removed stale BFF deploy section [defer to bff-deploy]; extracted Office Add-ins to new office-addins-deploy skill; fixed 2 broken workflow filename references; renumbered Key Vault from Type 4 to Type 2 since only Infrastructure + Key Vault remain in scope) Exemplar rationale: infrastructure/bicep/stacks/ai-foundry-stack.bicep is a comprehensive Bicep stack demonstrating module composition, parameter passing, and Key Vault wiring.


Quick Reference — Scope of THIS skill

Deployment Type Tool Where to Find
Azure Infrastructure (Bicep) Azure CLI + Bicep THIS SKILL
Key Vault Secrets Azure CLI + Bicep THIS SKILL
BFF API to App Service Deploy-BffApi.ps1 + hash-verify bff-deploy skill (the canonical authority — incident-grounded with May 2026 silent-failure hardening)
Office Add-ins to SWA SWA CLI + Deploy-OfficeAddins.ps1 office-addins-deploy skill
Dataverse / PCF / solutions PAC CLI dataverse-deploy, pcf-deploy skills
Power Pages Code Site PAC CLI + Vite build power-page-deploy skill

For Dataverse deployments (PCF, solutions, web resources): Use the dataverse-deploy skill instead.

Required Reading: Load azure-deployment.md for required App Settings before deploying.


Prerequisites

Required Tools

# Verify installations
az --version          # Azure CLI 2.50+
az bicep version      # Bicep CLI 0.39+
dotnet --version      # .NET SDK 8.0+

Required Access

Resource Access Level
Azure Subscription Contributor role
Azure AD Application Administrator (for app registrations)

Authentication

# Login to Azure
az login

# Set subscription
az account set --subscription "Spaarke SPE Subscription 1"

# Verify
az account show --query "{Name:name, Id:id}" -o table

Environment Reference

Subscriptions & Resource Groups

Environment Subscription Resource Group
Dev Spaarke SPE Subscription 1 spe-infrastructure-westus2
Prod (TBD) rg-spaarke-{customer}-prod

Azure Resource Endpoints (Dev)

Service Endpoint
BFF API https://spe-api-dev-67e2xz.azurewebsites.net
Azure OpenAI https://spaarke-openai-dev.openai.azure.com/
AI Search https://spaarke-search-dev.search.windows.net/
Document Intelligence https://westus2.api.cognitive.microsoft.com/
Key Vault https://sprkspaarkedev-aif-kv.vault.azure.net/
AI Foundry Hub sprkspaarkedev-aif-hub
AI Foundry Project sprkspaarkedev-aif-proj

Key Vault Secrets

Secret Name Purpose
openai-api-key Azure OpenAI API key
search-admin-key AI Search admin key
docintel-api-key Document Intelligence key
redis-connection Redis connection string
appinsights-key Application Insights key
BFF-API-ClientSecret 🔴 DELETED 2026-08-24 (auth-v4 task 033, ADR-028 A4; E-3 closed). The BFF identity is secret-free — including OBO — and authenticates with a managed-identity federated credential. Do not create or reference this secret. Set Graph__Credentials__Order__0=ManagedIdentityFederated + Graph__Credentials__RequireSecretFreeIdentity=true instead.
Communication-WebhookSigningKey HMAC-SHA256 key for Communication webhooks (48-byte base64)
EmailProcessing-WebhookSigningKey HMAC-SHA256 key for Email webhooks (48-byte base64)

Full environment reference: See docs/guides/ENVIRONMENT-DEPLOYMENT-GUIDE.md → Environment Configuration Auth-specific runbook: See docs/guides/SPAARKE-CUSTOMER-DEPLOYMENT-GUIDE.md — §6.5 App Service configuration, §7.7 Graph app roles + Dataverse Application User, §7.9 Exchange mailbox access (auth-deployment-setup.md is a retired stub) Canonical auth ADR: ADR-028 — function-based contract, MI for outbound, HMAC webhooks, named API keys


Deployment Type 1: Azure Infrastructure (Bicep)

When to Use

  • Creating new Azure resources
  • Deploying AI Foundry stack
  • Setting up customer environments

Bicep Stack Locations

Stack Path Purpose
AI Foundry infrastructure/bicep/stacks/ai-foundry-stack.bicep AI Hub, Project, Storage, KV
Model 1 Shared infrastructure/bicep/stacks/model1-shared.bicep 🔴 RETIRED 2026-09-28 (D-12); file deleted by task 225a (2026-10-01) with model1-customer.bicep and parameters/{dev,staging,prod}.bicepparam. Model 1 customers are dedicated stamps built by the L2 control plane (H2a deploys them with customer.bicep since task 228).
Customer stamp (both models) infrastructure/bicep/customer.bicep — the ONLY customer-stamp template, deployed by L2 handler H2a (task 249, owner D19, 2026-10-02: stacks/model2-full.bicep and its parameter files were deleted) Dedicated per-customer deployment — one Azure subscription + resource group per customer (ADR-027 amended 2026-09-28). Not deployed by any GitHub workflow — deploy-infrastructure.yml only validates.

Deploy Infrastructure

# Navigate to infrastructure directory
cd infrastructure/bicep

# Deploy AI Foundry stack
az deployment group create `
  --resource-group spe-infrastructure-westus2 `
  --template-file stacks/ai-foundry-stack.bicep `
  --parameters customerId=spaarke environment=dev location=westus2

Verify Deployment

# List deployed resources
az resource list `
  --resource-group spe-infrastructure-westus2 `
  --output table

Expected Resources (AI Foundry Stack)

Resource Type Name Pattern Purpose
Storage Account sprk{customer}{env}aifsa AI Foundry storage
Key Vault sprk{customer}{env}-aif-kv Secrets
Log Analytics sprk{customer}{env}-aif-logs Monitoring
App Insights sprk{customer}{env}-aif-insights APM
ML Workspace (Hub) sprk{customer}{env}-aif-hub AI Foundry Hub
ML Workspace (Project) sprk{customer}{env}-aif-proj AI Foundry Project

Deployment Type 2: Key Vault Secrets

Store Secrets

# Store OpenAI API key
az keyvault secret set `
  --vault-name sprkspaarkedev-aif-kv `
  --name openai-api-key `
  --value "YOUR-API-KEY"

# Store from Azure resource (auto-retrieve)
az keyvault secret set `
  --vault-name sprkspaarkedev-aif-kv `
  --name openai-api-key `
  --value "$(az cognitiveservices account keys list --name spaarke-openai-dev --resource-group spe-infrastructure-westus2 --query key1 -o tsv)"

Retrieve Secrets

# Get secret value
az keyvault secret show `
  --vault-name sprkspaarkedev-aif-kv `
  --name openai-api-key `
  --query value -o tsv

Verification Procedures

API Health Check

# Check API is running
curl https://spe-api-dev-67e2xz.azurewebsites.net/healthz
# Expected: "Healthy"

curl https://spe-api-dev-67e2xz.azurewebsites.net/ping
# Expected: "pong"

Azure Resource Verification

# List resources in resource group
az resource list --resource-group spe-infrastructure-westus2 -o table

# Check specific resource
az webapp show --name spe-api-dev-67e2xz --resource-group spe-infrastructure-westus2 --query state

AI Services Verification

# Check OpenAI deployments
az cognitiveservices account deployment list `
  --name spaarke-openai-dev `
  --resource-group spe-infrastructure-westus2 `
  -o table

# Check AI Search index
az search index list `
  --service-name spaarke-search-dev `
  --resource-group spe-infrastructure-westus2 `
  -o table

Error Handling

Error Cause Solution
AuthorizationFailed Insufficient permissions Verify Contributor role on subscription
ResourceNotFound Wrong resource group or name Check resource names in Environment Reference
DeploymentFailed Bicep template error Check az deployment group show --name {deployment} for details
KeyVault access denied Missing Key Vault policy Add access policy for your identity
App Service 503 API not started Check Application Insights logs
App Service 500 after deploy DI scope mismatch or startup error Check /healthz response body for error details
CLI deploy succeeds but old code runs Deployment didn't register Check Deployment Center logs; use Kudu as fallback

Deployment Not Taking Effect (Rare)

Symptom: az webapp deploy reports success, but the API still runs old code.

Diagnosis:

  1. Check Deployment Center → Logs in Azure Portal
  2. If no new entry with current timestamp, deployment didn't register

Solution (in order of preference):

  1. Restart the App Service - sometimes forces reload of new deployment
  2. Try alternative CLI command: az webapp deployment source config-zip
  3. Use Kudu Zip Push Deploy as manual fallback (see Option C above)
  4. After any method, verify with curl https://{app}.azurewebsites.net/healthz

Root Cause: This is rare and may indicate Azure-side caching or deployment slot issues. For consistent deployments, use GitHub Actions (Option A).

Check Deployment Logs

# API logs (streaming)
az webapp log tail --name spe-api-dev-67e2xz --resource-group spe-infrastructure-westus2

# Deployment logs
az webapp log deployment show --name spe-api-dev-67e2xz --resource-group spe-infrastructure-westus2

Naming Conventions

Resource Type Pattern Example
Resource Group rg-spaarke-{customer}-{env} rg-spaarke-contoso-prod
App Service sprk-{app}-{env} sprk-bff-dev
Key Vault sprk{customer}{env}-{purpose}-kv sprkspaarkedev-aif-kv
Storage Account sprk{customer}{env}sa sprkspaarkedevsa
Azure OpenAI spaarke-openai-{env} spaarke-openai-dev
AI Search spaarke-search-{env} spaarke-search-dev

Full naming conventions: See docs/architecture/AZURE-RESOURCE-NAMING-CONVENTION.md


Related Skills

Skill Use For
dataverse-deploy Dataverse solutions, PCF controls, web resources
ribbon-edit Ribbon customizations (uses solution export/import)
ci-cd CI/CD pipeline status and automated deployment workflows

CI/CD Integration

Automated Deployments via GitHub Actions

This skill documents manual Azure Infrastructure + Key Vault Secrets work. For automated deployments, see the GitHub Actions workflows:

Workflow Trigger What It Deploys
.github/workflows/deploy-infrastructure.yml ("Validate Bicep Infrastructure") PR / push on infrastructure/bicep/**, or workflow_dispatch Nothing — lints every Bicep file and compiles customer.bicep + the remaining stacks (task 249). Customer stamps are deployed by L2 handler H2a.
.github/workflows/deploy-bff-api.yml workflow_dispatch only (never on merge) BFF API — staging slot → swap → verify, with auto-rollback; see bff-deploy skill
.github/workflows/deploy-office-addins.yml Push to master on add-in paths, or workflow_dispatch Office Add-ins SWA — see office-addins-deploy skill
.github/workflows/deploy-promote.yml workflow_dispatch Direct-target deploy to dev / staging / production (production needs reviewer approval)

Note: deploy-staging.yml and deploy-to-azure.yml never existed; deploy-platform.yml and deploy-slot-swap.yml were deleted (commit 902bebc49c). Slot swaps are part of deploy-bff-api.yml. Full current list: docs/procedures/ci-cd-workflow.md (verified 2026-09-30).

When to Use Manual vs Automated

Scenario Use
Customer stamp (new or upgrade) L2 control plane via /provision-environment (H2a deploys customer.bicep) — never a GitHub workflow
Emergency hotfix on Bicep Manual deployment (this skill)
First-time infrastructure stand-up Manual deployment (this skill)
Debugging deployment issues Manual deployment (this skill)
BFF API deploy bff-deploy skill (DO NOT do BFF deploys via this skill)

Run Bicep Validation On Demand

# Lint + compile every Bicep template (deploys nothing — task 249)
gh workflow run deploy-infrastructure.yml

# Monitor the run
gh run watch
gh run list --workflow=deploy-infrastructure.yml --limit 5

Check Workflow Runs

# View recent validation runs
gh run list --workflow=deploy-infrastructure.yml

# View specific run details
gh run view {run-id}

# Download deployment artifacts
gh run download {run-id}

Related Documentation

Document Purpose
docs/guides/ENVIRONMENT-DEPLOYMENT-GUIDE.md Comprehensive deployment reference
docs/guides/CUSTOMER-DEPLOYMENT-GUIDE.md Customer-facing setup guide
docs/architecture/AZURE-RESOURCE-NAMING-CONVENTION.md Naming standards

Operator Notes

  • Avoid discovery queries - Use endpoint values from Environment Reference above
  • Operational commands OK - Deployments, secret management, configuration are permitted
  • For Dataverse - Always use dataverse-deploy skill instead of this one
  • Check health first - Before troubleshooting, verify /healthz endpoint
  • Key Vault references - Use @Microsoft.KeyVault(SecretUri=...) syntax in App Settings
  • Dev deploys - Use deployment scripts for quick iteration; GitHub Actions for production releases
  • Verify deployments - After manual deploy, check /healthz and Deployment Center logs
  • If CLI deploy fails silently - Try restart first, then Kudu as last resort

Deployment Scripts (Preferred for Dev)

Component Script Usage
BFF API .\scripts\Deploy-BffApi.ps1 Full build+deploy in ~1 min
Office Add-ins .\scripts\Deploy-OfficeAddins.ps1 Full build+deploy in ~30 sec

Both scripts support -SkipBuild flag to deploy existing builds faster.

  • 500 errors after deploy - Check /healthz response body for DI scope or startup errors. For BFF-specific errors → use bff-deploy skill.

Out of Scope (defer to other skills)

  • BFF API deploys → bff-deploy skill (canonical authority; includes May 2026 silent-failure hardening with hash-verify + auto-recover)
  • Office Add-ins / SWA deploys → office-addins-deploy skill (extracted from this skill 2026-05-17)
  • Dataverse PCF / solutions → dataverse-deploy / pcf-deploy skills
  • Power Pages Code Sites → power-page-deploy skill

Failure Modes & Recovery

Failure Cause Prevention / Recovery
az deployment group create succeeds but resource doesn't appear in portal Wrong resource group OR provider not registered for the subscription Verify az account show matches expected subscription. Run az provider register --namespace <namespace> for first-time use of a new provider.
Bicep deploy "succeeds" with provisioningState: Succeeded but child resources failed Top-level deployment doesn't always surface child failures Always check az deployment group show --query properties.outputs AND examine the child operations: az deployment operation group list --resource-group <rg> --name <deployment>.
Key Vault secret stored but App Settings reference returns null App Service's managed identity doesn't have Get permission on the Key Vault, OR the reference syntax @Microsoft.KeyVault(SecretUri=...) has a typo Grant the App Service's system-assigned MI Key Vault Secrets User role. Verify reference syntax matches exactly (including the literal @ and proper VaultName/SecretName fields). Test with az webapp config appsettings list to see resolved values.
AI Foundry stack deploy fails with "Hub not found" mid-deploy Resource dependencies aren't ordered correctly in the Bicep The ai-foundry-stack.bicep example wires Hub → Project → Connections in correct order. Don't shortcut to deploy Project before Hub exists.
Workflow deploy-staging.yml or deploy-to-azure.yml doesn't exist Earlier docs referenced these by hopeful name; they were never created Use the actual workflows listed in ## CI/CD Integration (verified 2026-05-17). Fixed in this skill version.
Deployment in slot 'staging' but production users still on old version Slot swap step not run after staging validation Slot deploys to staging are intentional — explicit az webapp deployment slot swap step is required to promote. deploy-bff-api.yml does the swap (and verifies, with rollback); deploy-slot-swap.yml no longer exists.