Azure Workload Generator
Generate complete Azure spoke workload infrastructure in both Bicep and Terraform, following enterprise naming conventions and IP addressing standards.
Overview
This skill creates production-ready infrastructure code for Azure spoke workloads including:
- •Virtual Network (VNet) with custom address space
- •Subnet with configurable size
- •Virtual Machine (Windows or Linux)
- •Optional data disk
- •Proper resource naming and tagging
Output: Both Bicep and Terraform code with proper directory structure under azure-workloads/Customer/<customerCode>/
⛔ MANDATORY REQUIREMENTS GATE - DO NOT SKIP
CRITICAL: You MUST gather ALL required inputs from the user BEFORE generating ANY code. NEVER assume, guess, or use placeholder values for required inputs. ALWAYS use the
AskUserQuestiontool to collect missing information.
Why This Matters
The naming convention (docs/standards/naming-convention.md) requires specific inputs to generate valid resource names:
| Input | Used In Naming Pattern | Example |
|---|---|---|
| Customer Code | {customerCode}- prefix on ALL resources | cc-vnet-... |
| Workload Name | {workload} component | cc-vnet-webapp-... |
| Environment | {environment} code (d/t/a/p) | cc-vnet-webapp-p-... |
| Region | {region} code (default: weu) | cc-vnet-webapp-p-weu-01 |
Without these inputs, you CANNOT generate compliant resource names.
Minimum Required Inputs (MUST HAVE)
Before proceeding to code generation, you MUST have explicit user confirmation for:
- •✅ Customer Code - 2-4 character lowercase identifier
- •✅ Workload Name - Purpose/name of this workload
- •✅ Environment Code - d (dev), t (test), a (acceptance), p (production)
- •✅ VM Operating System - Windows or Linux
- •✅ Resources Needed - What resources to create (VNet, VM, disks, etc.)
Recommended Additional Inputs
These have sensible defaults but should be confirmed:
- •📋 VNet Address Space (default: from ip-addressing-scheme.md)
- •📋 Subnet Name and Size
- •📋 VM SKU (default: Standard_D2s_v3)
- •📋 Data Disk requirements (yes/no, size)
- •📋 Tag values (CostCenter, Owner, Criticality)
STOP AND ASK
If the user's request is missing ANY of the 5 required inputs above:
STOP → Use AskUserQuestion → Gather missing inputs → THEN proceed
Example: If user says "create an exact-financials workload", you are MISSING:
- •Customer code ❌
- •Environment ❌
- •OS type ❌
- •Resources needed ❌
You MUST ask for these before generating any code.
Instructions
Phase 1: Gather Required Information (MANDATORY - NEVER SKIP)
Use the AskUserQuestion tool to collect the following information from the user:
- •
Customer Code (e.g., "contoso", "fabrikam")
- •Used for directory structure and resource naming
- •Should be lowercase, alphanumeric
- •
Workload Name (e.g., "webapp", "database", "api")
- •Describes the purpose of this workload
- •Used in resource naming
- •
Environment Code
- •
d= Development - •
t= Test - •
a= Acceptance - •
p= Production
- •
- •
VNet Address Space (e.g., "10.10.0.0/16", "172.16.0.0/16")
- •CIDR notation for the virtual network
- •Should align with IP addressing scheme (but not validated)
- •
Subnet Name (e.g., "app", "data", "web")
- •Logical name for the subnet
- •
Subnet Size (e.g., "/24", "/26")
- •CIDR suffix only (e.g., "/24" for 256 addresses)
- •
VM Operating System
- •
WindowsorLinux
- •
- •
VM SKU (e.g., "Standard_D2s_v3", "Standard_B2ms")
- •Azure VM size
- •
Data Disk Required
- •
yesorno
- •
- •
Data Disk Size in GB (if data disk required)
- •Size in GB (e.g., 128, 256, 512)
- •
Instance Number (default: "01")
- •Two-digit instance identifier per naming-convention.md
- •Default to "01" for first instance
- •
Tag Values (for mandatory tags)
- •CostCenter: Department or cost allocation code
- •Owner: Team or individual responsible
- •Criticality: Low, Medium, High, Critical
Phase 2: Read Standards Documentation
Before generating code, read the following standards:
- •
Read
docs/standards/naming-convention.mdto understand:- •Resource naming patterns
- •Character limits
- •Tagging requirements
- •Environment codes
- •Region codes (default:
weufor West Europe)
- •
Reference
docs/standards/ip-addressing-scheme.mdfor context:- •Hub-spoke topology patterns
- •Subscription-based VNet allocation
- •Platform vs workload IP ranges
Phase 3: Generate Resource Names
Based on the naming convention standard, generate resource names following these patterns:
Resource Naming Format: <resourceType>-<workload>-<environment>-<region>-<instance>
- •
VNet:
vnet-<workload>-<environment>-weu-<instance>- •Example:
vnet-webapp-p-weu-01
- •Example:
- •
Subnet:
snet-<subnetName>-<environment>-weu-<instance>- •Example:
snet-app-p-weu-01
- •Example:
- •
VM:
vm<workload><environment>weu<instance>(no hyphens, max 15 chars for Windows)- •Example:
vmwebapppweu01 - •For Linux:
vm-<workload>-<environment>-weu-<instance>(up to 64 chars)
- •Example:
- •
NIC:
nic-<workload>-<environment>-weu-<instance>- •Example:
nic-webapp-p-weu-01
- •Example:
- •
Data Disk (if required):
disk-<workload>-data-<environment>-weu-<instance>- •Example:
disk-webapp-data-p-weu-01
- •Example:
- •
Public IP (if required):
pip-<workload>-<environment>-weu-<instance>- •Example:
pip-webapp-p-weu-01
- •Example:
- •
NSG:
nsg-<workload>-<environment>-weu-<instance>- •Example:
nsg-webapp-p-weu-01
- •Example:
Validate Name Lengths:
- •Windows VM names: Max 15 characters (remove hyphens if needed)
- •Linux VM names: Max 64 characters
- •Other resources: Check naming-convention.md for specific limits
Phase 4: Prepare Mandatory Tags
Create a tags object with all mandatory tags:
{
"Environment": "<d|t|a|p - full name>",
"CostCenter": "<from user input or placeholder>",
"Owner": "<from user input or placeholder>",
"ManagedBy": "Terraform" or "Bicep",
"Workload": "<workload name>",
"Criticality": "<from user input or placeholder>"
}
Tag Values:
- •Environment: "Development", "Test", "Acceptance", "Production"
- •ManagedBy: "Bicep" or "Terraform" depending on file
- •Use placeholders like "TO_BE_DEFINED" if user doesn't provide values
Phase 5: Create Directory Structure
Create the following directory structure under azure-workloads/:
azure-workloads/ ├── Customer/ │ ├── bicep-modules/ (for reusable modules) │ ├── terraform-modules/ (for reusable modules) │ └── <customerCode>/ (e.g., contoso/) │ ├── bicep/ │ │ ├── <workloadname>.bicep │ │ └── <workloadname>.bicepparam │ └── terraform/ │ ├── <workloadname>.tf │ ├── variables.tf │ └── terraform.tfvars
Use the Write tool to create directories and files.
Phase 6: Generate Bicep Code
Create two files in azure-workloads/Customer/<customerCode>/bicep/:
File 1: <workloadname>.bicep
Structure:
// Azure Spoke Workload: <workload>
// Generated by azure-workload-generator
// Customer: <customerCode>
// Environment: <environment>
targetScope = 'resourceGroup'
// ============================================================================
// PARAMETERS
// ============================================================================
@description('Location for all resources')
param location string = 'westeurope'
@description('VNet address space')
param vnetAddressSpace string
@description('Subnet address prefix')
param subnetAddressPrefix string
@description('Virtual Machine SKU')
param vmSize string
@description('Admin username for the VM')
@secure()
param adminUsername string
@description('Admin password for the VM')
@secure()
param adminPassword string
@description('Data disk size in GB (0 for no data disk)')
param dataDiskSizeGB int
@description('Resource tags')
param tags object
// ============================================================================
// VARIABLES
// ============================================================================
var vnetName = '<generated-vnet-name>'
var subnetName = '<generated-subnet-name>'
var vmName = '<generated-vm-name>'
var nicName = '<generated-nic-name>'
var nsgName = '<generated-nsg-name>'
var osDiskName = '${vmName}-osdisk'
var dataDiskName = '<generated-datadisk-name>'
// ============================================================================
// RESOURCES
// ============================================================================
// Network Security Group
resource nsg 'Microsoft.Network/networkSecurityGroups@2023-05-01' = {
name: nsgName
location: location
tags: tags
properties: {
securityRules: [
// Add security rules based on OS type
]
}
}
// Virtual Network
resource vnet 'Microsoft.Network/virtualNetworks@2023-05-01' = {
name: vnetName
location: location
tags: tags
properties: {
addressSpace: {
addressPrefixes: [
vnetAddressSpace
]
}
subnets: [
{
name: subnetName
properties: {
addressPrefix: subnetAddressPrefix
networkSecurityGroup: {
id: nsg.id
}
}
}
]
}
}
// Network Interface
resource nic 'Microsoft.Network/networkInterfaces@2023-05-01' = {
name: nicName
location: location
tags: tags
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
subnet: {
id: vnet.properties.subnets[0].id
}
privateIPAllocationMethod: 'Dynamic'
}
}
]
}
}
// Virtual Machine
resource vm 'Microsoft.Compute/virtualMachines@2023-03-01' = {
name: vmName
location: location
tags: tags
properties: {
hardwareProfile: {
vmSize: vmSize
}
osProfile: {
computerName: vmName
adminUsername: adminUsername
adminPassword: adminPassword
}
storageProfile: {
imageReference: {
// Set based on OS type (Windows or Linux)
publisher: '<publisher>'
offer: '<offer>'
sku: '<sku>'
version: 'latest'
}
osDisk: {
name: osDiskName
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'Premium_LRS'
}
}
dataDisks: dataDiskSizeGB > 0 ? [
{
name: dataDiskName
diskSizeGB: dataDiskSizeGB
lun: 0
createOption: 'Empty'
managedDisk: {
storageAccountType: 'Premium_LRS'
}
}
] : []
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
}
]
}
}
}
// ============================================================================
// OUTPUTS
// ============================================================================
output vnetId string = vnet.id
output vnetName string = vnet.name
output subnetId string = vnet.properties.subnets[0].id
output vmId string = vm.id
output vmName string = vm.name
output privateIPAddress string = nic.properties.ipConfigurations[0].properties.privateIPAddress
Key Considerations:
- •Reference shared Bicep modules from
bicep-modules/directory if they exist - •Use conditional logic for data disk (only create if dataDiskSizeGB > 0)
- •Set correct image reference based on OS type:
- •Windows: publisher='MicrosoftWindowsServer', offer='WindowsServer', sku='2022-datacenter-azure-edition'
- •Linux: publisher='Canonical', offer='0001-com-ubuntu-server-jammy', sku='22_04-lts-gen2'
- •Include comprehensive comments
- •Use latest API versions
File 2: <workloadname>.bicepparam
Structure:
using './<workloadname>.bicep'
param location = 'westeurope'
param vnetAddressSpace = '<user-provided-vnet-address>'
param subnetAddressPrefix = '<calculated-subnet-cidr>'
param vmSize = '<user-provided-vm-sku>'
param adminUsername = '<placeholder-or-keyvault-reference>'
param adminPassword = '<placeholder-or-keyvault-reference>'
param dataDiskSizeGB = <user-provided-size-or-0>
param tags = {
Environment: '<Development|Test|Acceptance|Production>'
CostCenter: 'TO_BE_DEFINED'
Owner: 'TO_BE_DEFINED'
ManagedBy: 'Bicep'
Workload: '<workload-name>'
Criticality: 'TO_BE_DEFINED'
}
Subnet Calculation:
- •Calculate subnet CIDR from VNet address space and subnet size
- •Example: VNet "10.10.0.0/16" + subnet size "/24" = "10.10.0.0/24"
Phase 7: Generate Terraform Code
Create three files in azure-workloads/Customer/<customerCode>/terraform/:
File 1: <workloadname>.tf
Structure:
# Azure Spoke Workload: <workload>
# Generated by azure-workload-generator
# Customer: <customerCode>
# Environment: <environment>
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
# ============================================================================
# LOCAL VARIABLES
# ============================================================================
locals {
vnet_name = "<generated-vnet-name>"
subnet_name = "<generated-subnet-name>"
vm_name = "<generated-vm-name>"
nic_name = "<generated-nic-name>"
nsg_name = "<generated-nsg-name>"
os_disk_name = "${local.vm_name}-osdisk"
data_disk_name = "<generated-datadisk-name>"
common_tags = {
Environment = var.environment
CostCenter = var.cost_center
Owner = var.owner
ManagedBy = "Terraform"
Workload = var.workload_name
Criticality = var.criticality
}
}
# ============================================================================
# RESOURCE GROUP
# ============================================================================
# Assumes resource group already exists
data "azurerm_resource_group" "main" {
name = var.resource_group_name
}
# ============================================================================
# NETWORK SECURITY GROUP
# ============================================================================
resource "azurerm_network_security_group" "main" {
name = local.nsg_name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
tags = local.common_tags
# Add security rules based on OS type
}
# ============================================================================
# VIRTUAL NETWORK
# ============================================================================
resource "azurerm_virtual_network" "main" {
name = local.vnet_name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
address_space = [var.vnet_address_space]
tags = local.common_tags
}
resource "azurerm_subnet" "main" {
name = local.subnet_name
resource_group_name = data.azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [var.subnet_address_prefix]
}
resource "azurerm_subnet_network_security_group_association" "main" {
subnet_id = azurerm_subnet.main.id
network_security_group_id = azurerm_network_security_group.main.id
}
# ============================================================================
# NETWORK INTERFACE
# ============================================================================
resource "azurerm_network_interface" "main" {
name = local.nic_name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
tags = local.common_tags
ip_configuration {
name = "ipconfig1"
subnet_id = azurerm_subnet.main.id
private_ip_address_allocation = "Dynamic"
}
}
# ============================================================================
# VIRTUAL MACHINE
# ============================================================================
resource "azurerm_<windows|linux>_virtual_machine" "main" {
name = local.vm_name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
size = var.vm_size
admin_username = var.admin_username
admin_password = var.admin_password
tags = local.common_tags
network_interface_ids = [
azurerm_network_interface.main.id
]
os_disk {
name = local.os_disk_name
caching = "ReadWrite"
storage_account_type = "Premium_LRS"
}
# Set source_image_reference based on OS type
source_image_reference {
publisher = "<publisher>"
offer = "<offer>"
sku = "<sku>"
version = "latest"
}
}
# ============================================================================
# DATA DISK (CONDITIONAL)
# ============================================================================
resource "azurerm_managed_disk" "data" {
count = var.data_disk_size_gb > 0 ? 1 : 0
name = local.data_disk_name
location = data.azurerm_resource_group.main.location
resource_group_name = data.azurerm_resource_group.main.name
storage_account_type = "Premium_LRS"
create_option = "Empty"
disk_size_gb = var.data_disk_size_gb
tags = local.common_tags
}
resource "azurerm_virtual_machine_data_disk_attachment" "data" {
count = var.data_disk_size_gb > 0 ? 1 : 0
managed_disk_id = azurerm_managed_disk.data[0].id
virtual_machine_id = azurerm_<windows|linux>_virtual_machine.main.id
lun = 0
caching = "ReadWrite"
}
# ============================================================================
# OUTPUTS
# ============================================================================
output "vnet_id" {
description = "The ID of the Virtual Network"
value = azurerm_virtual_network.main.id
}
output "vnet_name" {
description = "The name of the Virtual Network"
value = azurerm_virtual_network.main.name
}
output "subnet_id" {
description = "The ID of the Subnet"
value = azurerm_subnet.main.id
}
output "vm_id" {
description = "The ID of the Virtual Machine"
value = azurerm_<windows|linux>_virtual_machine.main.id
}
output "vm_name" {
description = "The name of the Virtual Machine"
value = azurerm_<windows|linux>_virtual_machine.main.name
}
output "private_ip_address" {
description = "The private IP address of the VM"
value = azurerm_network_interface.main.private_ip_address
}
Key Considerations:
- •Use
azurerm_windows_virtual_machinefor Windows,azurerm_linux_virtual_machinefor Linux - •Reference shared Terraform modules from
terraform-modules/directory if they exist - •Use
countfor conditional data disk creation - •Set correct image reference based on OS type:
- •Windows: publisher='MicrosoftWindowsServer', offer='WindowsServer', sku='2022-datacenter-azure-edition'
- •Linux: publisher='Canonical', offer='0001-com-ubuntu-server-jammy', sku='22_04-lts-gen2'
- •For Windows VMs, add
disable_password_authentication = falseis not applicable - •For Linux VMs, consider SSH key authentication instead of password
File 2: variables.tf
Structure:
# Variable definitions for <workload> workload
variable "resource_group_name" {
description = "Name of the resource group"
type = string
}
variable "vnet_address_space" {
description = "Address space for the virtual network"
type = string
}
variable "subnet_address_prefix" {
description = "Address prefix for the subnet"
type = string
}
variable "vm_size" {
description = "Size of the virtual machine"
type = string
}
variable "admin_username" {
description = "Admin username for the VM"
type = string
sensitive = true
}
variable "admin_password" {
description = "Admin password for the VM"
type = string
sensitive = true
}
variable "data_disk_size_gb" {
description = "Size of the data disk in GB (0 for no data disk)"
type = number
default = 0
}
variable "environment" {
description = "Environment name (Development, Test, Acceptance, Production)"
type = string
}
variable "cost_center" {
description = "Cost center tag value"
type = string
default = "TO_BE_DEFINED"
}
variable "owner" {
description = "Owner tag value"
type = string
default = "TO_BE_DEFINED"
}
variable "workload_name" {
description = "Workload name for tagging"
type = string
}
variable "criticality" {
description = "Criticality level (Low, Medium, High, Critical)"
type = string
default = "TO_BE_DEFINED"
}
File 3: terraform.tfvars
Structure:
# Terraform variables for <workload> workload # Customer: <customerCode> # Environment: <environment> resource_group_name = "rg-<workload>-<environment>-weu-01" vnet_address_space = "<user-provided-vnet-address>" subnet_address_prefix = "<calculated-subnet-cidr>" vm_size = "<user-provided-vm-sku>" admin_username = "azureadmin" # Change as needed admin_password = "CHANGE_ME_SECURE_PASSWORD" # Use Key Vault or environment variable data_disk_size_gb = <user-provided-size-or-0> environment = "<Development|Test|Acceptance|Production>" workload_name = "<workload-name>" cost_center = "TO_BE_DEFINED" owner = "TO_BE_DEFINED" criticality = "TO_BE_DEFINED"
Phase 8: Validation and Summary
After generating all files:
- •Validate that all files are created in the correct directory structure
- •Verify resource names follow naming-convention.md patterns
- •Check that all mandatory tags are included
- •Confirm that both Bicep and Terraform code are consistent
- •Review subnet CIDR calculation is correct
Provide a summary to the user:
✓ Generated Azure Workload: <workload> ✓ Customer: <customerCode> ✓ Environment: <environment> Files Created: - azure-workloads/Customer/<customerCode>/bicep/<workloadname>.bicep - azure-workloads/Customer/<customerCode>/bicep/<workloadname>.bicepparam - azure-workloads/Customer/<customerCode>/terraform/<workloadname>.tf - azure-workloads/Customer/<customerCode>/terraform/variables.tf - azure-workloads/Customer/<customerCode>/terraform/terraform.tfvars Resources: - VNet: <vnet-name> (<vnet-address-space>) - Subnet: <subnet-name> (<subnet-cidr>) - VM: <vm-name> (<vm-sku>, <os-type>) - Data Disk: <Yes/No> (<size-if-yes>) Next Steps: 1. Review and update placeholder tag values (CostCenter, Owner, Criticality) 2. Update admin credentials in parameter files 3. Create resource group: rg-<workload>-<environment>-weu-01 4. Deploy using: - Bicep: az deployment group create --resource-group <rg-name> --parameters <workloadname>.bicepparam - Terraform: terraform init && terraform plan && terraform apply
Examples
Example 1: Web Application Workload
User Input:
- •Customer Code:
contoso - •Workload Name:
webapp - •Environment:
p(Production) - •VNet Address Space:
10.10.0.0/16 - •Subnet Name:
app - •Subnet Size:
/24 - •VM OS:
Linux - •VM SKU:
Standard_D2s_v3 - •Data Disk:
yes - •Data Disk Size:
128GB - •Instance:
01 - •Tags: CostCenter=
CC-12345, Owner=WebTeam, Criticality=High
Generated Resources:
- •VNet:
vnet-webapp-p-weu-01 - •Subnet:
snet-app-p-weu-01 - •VM:
vm-webapp-p-weu-01(Linux, up to 64 chars allowed) - •NIC:
nic-webapp-p-weu-01 - •NSG:
nsg-webapp-p-weu-01 - •Data Disk:
disk-webapp-data-p-weu-01
Files Created:
azure-workloads/Customer/contoso/
├── bicep/
│ ├── webapp.bicep
│ └── webapp.bicepparam
└── terraform/
├── webapp.tf
├── variables.tf
└── terraform.tfvars
Example 2: Database Workload (Windows)
User Input:
- •Customer Code:
fabrikam - •Workload Name:
sqldb - •Environment:
t(Test) - •VNet Address Space:
172.16.0.0/16 - •Subnet Name:
data - •Subnet Size:
/26 - •VM OS:
Windows - •VM SKU:
Standard_E4s_v3 - •Data Disk:
yes - •Data Disk Size:
512GB - •Instance:
01 - •Tags: CostCenter=
CC-67890, Owner=DataTeam, Criticality=Critical
Generated Resources:
- •VNet:
vnet-sqldb-t-weu-01 - •Subnet:
snet-data-t-weu-01 - •VM:
vmsqldbtweu01(Windows, max 15 chars, no hyphens) - •NIC:
nic-sqldb-t-weu-01 - •NSG:
nsg-sqldb-t-weu-01 - •Data Disk:
disk-sqldb-data-t-weu-01
Files Created:
azure-workloads/Customer/fabrikam/
├── bicep/
│ ├── sqldb.bicep
│ └── sqldb.bicepparam
└── terraform/
├── sqldb.tf
├── variables.tf
└── terraform.tfvars
Requirements
Documentation References
- •CRITICAL: Must read
docs/standards/naming-convention.mdbefore generating names - •REFERENCE:
docs/standards/ip-addressing-scheme.mdfor network context
Azure Permissions
Users deploying the generated code need:
- •Contributor role on target resource group
- •Network Contributor for VNet operations
Tools Required for Deployment
- •Bicep: Azure CLI 2.20.0+ with Bicep
- •Terraform: Terraform 1.5.0+, Azure CLI for authentication
Best Practices
Security
- •Never hardcode credentials in generated files
- •Use Azure Key Vault references for secrets in production
- •Implement network security group rules appropriate for workload type
- •Consider using managed identities instead of passwords where possible
Naming
- •Strictly follow naming-convention.md patterns
- •Validate Windows VM names are ≤15 characters (remove hyphens)
- •Linux VM names can be up to 64 characters (keep hyphens)
- •Use instance number
01as default, increment for additional instances
Network Design
- •Ensure VNet address space doesn't overlap with existing networks
- •Subnet should be appropriately sized for expected resources
- •Consider future growth when selecting address spaces
- •Follow ip-addressing-scheme.md for subscription-based allocation
Tagging
- •All resources must have mandatory tags
- •Use placeholder values if user doesn't provide tag information
- •ManagedBy tag should reflect IaC tool (Bicep or Terraform)
- •Environment tag should use full name, not code
Code Quality
- •Include comprehensive comments in generated code
- •Use latest stable API versions
- •Implement conditional logic for optional resources (data disk)
- •Generate consistent code across Bicep and Terraform
- •Reference shared modules when available
Advanced Usage
Module References
If reusable Bicep or Terraform modules exist in the bicep-modules/ or terraform-modules/ directories, the skill should reference them instead of inline resources:
Bicep Module Reference Example:
module vnet '../../../bicep-modules/vnet/main.bicep' = {
name: 'vnet-deployment'
params: {
vnetName: vnetName
addressSpace: vnetAddressSpace
location: location
tags: tags
}
}
Terraform Module Reference Example:
module "vnet" {
source = "../../../terraform-modules/vnet"
vnet_name = local.vnet_name
address_space = var.vnet_address_space
location = data.azurerm_resource_group.main.location
tags = local.common_tags
}
Multi-Instance Deployments
For deploying multiple instances of the same workload:
- •Use instance number
01,02,03, etc. - •Ensure each instance has unique IP ranges
- •Consider creating separate parameter files per instance
Integration with CI/CD
The generated code can be integrated into CI/CD pipelines:
- •Bicep: Use Azure DevOps or GitHub Actions with
az deployment group create - •Terraform: Use Terraform Cloud, Azure DevOps, or GitHub Actions with
terraform apply
Troubleshooting
Common Issues
Issue: VM name exceeds 15 characters for Windows
Solution: Remove hyphens and shorten workload name. Example: vmsqldbtweu01 instead of vm-sqldb-t-weu-01
Issue: Subnet CIDR calculation incorrect Solution: Ensure subnet size suffix is applied to VNet base address correctly
Issue: IP address space conflicts Solution: Verify VNet address doesn't overlap with existing networks or hub VNets
Issue: Mandatory tags missing Solution: Ensure all six mandatory tags are included in tags object
Issue: Module references not found
Solution: Check if shared modules exist in bicep-modules/ or terraform-modules/ directories
Summary
The azure-workload-generator skill automates the creation of production-ready Azure spoke workload infrastructure following enterprise standards. It generates both Bicep and Terraform code with proper:
- •Resource naming per naming-convention.md
- •Mandatory tagging
- •Network topology aligned with ip-addressing-scheme.md
- •Security best practices
- •Conditional resource creation
- •Comprehensive documentation
Use this skill whenever you need to create new Azure workload infrastructure for customers.