Step 5 — Infra-as-Code Gen
- 📁 IaC Templates Location
- 🗂️ File Structure
- ✅ Validation Status
- 🏗️ Resources Created
- 🚀 Deployment Instructions
- 📝 Key Implementation Notes
Generated by 06b-Bicep CodeGen agent | 2025-07-13
| ⬅️ Previous | 📑 Index | Next ➡️ |
|---|---|---|
| Implementation Plan | Demo Index | Deployment Summary |
📁 IaC Templates Location
Section titled “📁 IaC Templates Location”📁 Code Location: Bicep templates repository folder
🗂️ File Structure
Section titled “🗂️ File Structure”infra/bicep/nordic-fresh-foods/├── main.bicep # Main orchestration — uniqueSuffix, phased deployment├── main.bicepparam # Production parameters├── main.dev.bicepparam # Development parameters├── deploy.ps1 # PowerShell deployment script (5 phases)└── modules/ ├── budget.bicep # Consumption budget + forecast alerts ├── compute.bicep # App Service Plan + App Service + RBAC + Autoscale ├── dns.bicep # Private DNS Zones (SQL, Blob, KV) + VNet links ├── keyvault.bicep # Key Vault + PE + diagnostics ├── monitoring.bicep # Log Analytics + Application Insights ├── network.bicep # VNet + Subnets + NSGs (AVM) ├── sql.bicep # SQL Server + Database + PE └── storage.bicep # Storage Account + containers + PE✅ Validation Status
Section titled “✅ Validation Status”| Check | Result | Details |
|---|---|---|
bicep build | ✅ | 0 errors, ⚠️ 34 warnings (BCP318 conditional modules, BCP321 nullable MI outputs, no-hardcoded-env-urls DNS) |
bicep lint | ✅ | 0 errors |
bicep-lint-subagent | ✅ PASS | 0 errors, 34 warnings (all acceptable) |
bicep-review-subagent | ✅ APPROVED | ❌ NEEDS_REVISION → all must_fix items resolved, re-validated |
Review Findings Applied
Section titled “Review Findings Applied”| Finding | Severity | Description | Resolution |
|---|---|---|---|
| H2 | HIGH | NSGs used raw Bicep instead of AVM | Replaced with br/public:avm/res/network/network-security-group:0.5.2 |
| H3 | HIGH | NSG names missing project identifier | Updated to nsg-${projectName}-{role}-${environment} |
| H4 | HIGH | deploy.ps1 missing ARM token validation | Added az account get-access-token check |
| H5 | HIGH | deploy.ps1 wildcard in deployment name query | Track phase-2 name explicitly via $phase2DeploymentName |
| M3 | MEDIUM | ftpsState set to FtpsOnly | Changed to Disabled per security baseline |
| M6 | MEDIUM | Hardcoded technical contact email in deploy.ps1 | Parameterized as $TechnicalContact |
| H1 | HIGH (FP) | dailyQuotaGb type — reviewer claimed int but BCP036 confirmed null | string | No change needed — string is correct |
| M2 | MEDIUM (FP) | availabilityZone: -1 questioned — build confirmed int works | No change needed |
Findings Deferred (Non-Blocking)
Section titled “Findings Deferred (Non-Blocking)”| Finding | Severity | Description | Rationale |
|---|---|---|---|
| M1 | MEDIUM | SQL missing diagnosticSettings | AVM SQL Server module does not support diagnosticSettings parameter (build error confirmed) |
| M4 | MEDIUM | Standard_LRS in prod | Implementation plan specifies Standard_LRS; aligns with cost-optimized architecture |
| M5 | MEDIUM | Budget startDate resets on each deploy | utcNow() in param default is acceptable pattern; deployer can override |
| M7 | MEDIUM | PE subnet network policies | Enabled is correct GA behavior for API 2024-01-01 |
| L1-L5 | LOW | Health probe, log retention, blob diagnostics, autoscale ceiling, dev KV access | Non-blocking; addressable in subsequent iteration |
🏗️ Resources Created
Section titled “🏗️ Resources Created”| Resource | AVM Module | Module File |
|---|---|---|
| Virtual Network | br/public:avm/res/network/virtual-network:0.7.2 | network.bicep |
| NSG (App) | br/public:avm/res/network/network-security-group:0.5.2 | network.bicep |
| NSG (Data) | br/public:avm/res/network/network-security-group:0.5.2 | network.bicep |
| NSG (PE) | br/public:avm/res/network/network-security-group:0.5.2 | network.bicep |
| Log Analytics Workspace | br/public:avm/res/operational-insights/workspace:0.15.0 | monitoring.bicep |
| Application Insights | br/public:avm/res/insights/component:0.7.1 | monitoring.bicep |
| Key Vault | br/public:avm/res/key-vault/vault:0.13.3 | keyvault.bicep |
| Private DNS Zones (×3) | br/public:avm/res/network/private-dns-zone:0.8.1 | dns.bicep |
| SQL Server + Database | br/public:avm/res/sql/server:0.21.1 | sql.bicep |
| Storage Account | br/public:avm/res/storage/storage-account:0.32.0 | storage.bicep |
| App Service Plan | br/public:avm/res/web/serverfarm:0.7.0 | compute.bicep |
| App Service | br/public:avm/res/web/site:0.22.0 | compute.bicep |
| Private Endpoints (×3) | br/public:avm/res/network/private-endpoint:0.12.0 | keyvault/sql/storage.bicep |
| Consumption Budget | Raw Bicep (Microsoft.Consumption/budgets) | budget.bicep |
graph TD
MAIN["main.bicep"] --> NET["network.bicep"]
MAIN --> MON["monitoring.bicep"]
MAIN --> DNS["dns.bicep"]
MAIN --> KV["keyvault.bicep"]
MAIN --> SQL["sql.bicep"]
MAIN --> ST["storage.bicep"]
MAIN --> COMP["compute.bicep"]
MAIN --> BUD["budget.bicep"]
NET --> VN["🌐 VNet + Subnets"]
NET --> NSG["🛡️ NSGs (×3)"]
MON --> LAW["📊 Log Analytics"]
MON --> AI["📈 App Insights"]
DNS --> PDNS["🔗 DNS Zones (×3)"]
KV --> KVR["🔐 Key Vault + PE"]
SQL --> SQLR["💾 SQL Server + DB + PE"]
ST --> STR["📦 Storage + PE"]
COMP --> ASP["⚙️ App Service Plan"]
COMP --> APP["💻 App Service"]
COMP --> RBAC["🔑 RBAC Assignments"]
COMP --> AUTO["📏 Autoscale"]
BUD --> BUDR["💰 Budget + Alerts"]
🚀 Deployment Instructions
Section titled “🚀 Deployment Instructions”cd infra/bicep/nordic-fresh-foods./deploy.ps1 -ResourceGroup "rg-nordic-fresh-foods-prod" -Environment "prod"Deploys in 5 phases with approval gates between each phase.
cd infra/bicep/nordic-fresh-foods./deploy.ps1 -ResourceGroup "rg-nordic-fresh-foods-dev" -Environment "dev"Single-pass deployment (no private endpoints, reduced SKUs).
./deploy.ps1 -ResourceGroup "rg-nordic-fresh-foods-prod" -Environment "prod" -WhatIf./deploy.ps1 -ResourceGroup "rg-nordic-fresh-foods-prod" -Environment "prod" -StartFromPhase 3Supported phases: 1 (Foundation), 2 (Observability), 3 (Security), 4 (Data), 5 (Compute)
az deployment group create \ --resource-group "rg-nordic-fresh-foods-prod" \ --template-file main.bicep \ --parameters main.bicepparam \ --parameters phase=foundationDeployment Phases
Section titled “Deployment Phases”| Phase | Name | Resources | Approx. Time |
|---|---|---|---|
| 1 | Foundation | VNet, Subnets, NSGs | ~2 min |
| 2 | Observability | Log Analytics, App Insights | ~3 min |
| 3 | Security | Key Vault, DNS Zones, KV PE | ~5 min |
| 4 | Data | SQL Server, Database, Storage, PEs | ~8 min |
| 5 | Compute | App Service Plan, App Service, Budget, RBAC, Autoscale | ~5 min |
Pre-Deployment Checklist
Section titled “Pre-Deployment Checklist”- Replace
<replace-with-sql-admin-group-object-id>in parameter files - Replace
<replace-with-sql-admin-group-name>in parameter files - Replace
<replace-with-budget-contact-email>in parameter files - Replace
<replace-with-technical-contact>in parameter files - Verify Azure AD group exists for SQL admin
- Confirm subscription
00858ffc-dded-4f0f-8bbf-e17fff0d47d9is targeted
📝 Key Implementation Notes
Section titled “📝 Key Implementation Notes”| Note | Impact | Reference |
|---|---|---|
Unique suffix via uniqueString(resourceGroup().id) | All resource names (KV, Storage, SQL, App) | main.bicep |
| 11 mandatory tags (9 governance Deny + 2 baseline) | All resources — Azure Policy enforced | main.bicep var tags |
| Azure AD-only SQL auth | No SQL password management; MI-based access | sql.bicep |
Phased deployment with @allowed phase parameter | Supports incremental rollout and re-entry | main.bicep |
Private endpoints conditional on enablePrivateEndpoints | Prod: full PE isolation; Dev: public access | all PE modules |
| FTPS disabled on App Service | Security baseline — no FTP attack surface | compute.bicep |
| Budget alerts at 80%/100%/120% forecast + 90% actual | Cost governance with anomaly detection | budget.bicep |
var uniqueSuffix = uniqueString(resourceGroup().id)// Example: kv-nff-prod-ab1c → 24-char limit respected via take()Governance Compliance
Section titled “Governance Compliance”All 21 Azure Policy assignments from 04-governance-constraints.json have been mapped and satisfied:
- 9 Deny-policy tags: Applied via
var tagsin main.bicep, inherited by all modules - Azure AD-only SQL auth:
azureADOnlyAuthentication: truein sql.bicep - Tag inheritance (Modify): 4 tags auto-inherited from resource group
- MFA for write operations: Enforced at Azure AD level (not IaC-scoped)
Implementation reference generated from Bicep templates.