#!/usr/bin/env python3 """ Azure Bicep template generator. Generates Bicep infrastructure-as-code scaffolds for common Azure architecture patterns. Usage: python bicep_generator.py --arch-type web-app python bicep_generator.py --arch-type microservices --output main.bicep python bicep_generator.py --arch-type serverless --json python bicep_generator.py --help """ import argparse import json import sys from typing import Dict # --------------------------------------------------------------------------- # Bicep templates # --------------------------------------------------------------------------- def _web_app_template() -> str: return r"""// ============================================================================= // Azure Web App Architecture — Bicep Template // App Service + Azure SQL + Front Door + Key Vault + Application Insights // ============================================================================= @description('Environment name') @allowed(['dev', 'staging', 'production']) param environment string = 'dev' @description('Azure region') param location string = resourceGroup().location @description('Application name (lowercase, no spaces)') @minLength(3) @maxLength(20) param appName string @description('SQL admin Entra ID object ID') param sqlAdminObjectId string // --------------------------------------------------------------------------- // Key Vault // --------------------------------------------------------------------------- resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { name: '${environment}-${appName}-kv' location: location properties: { sku: { family: 'A', name: 'standard' } tenantId: subscription().tenantId enableRbacAuthorization: true enableSoftDelete: true softDeleteRetentionInDays: 30 networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' } } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // App Service Plan + App Service // --------------------------------------------------------------------------- resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = { name: '${environment}-${appName}-plan' location: location sku: { name: environment == 'production' ? 'P1v3' : 'B1' tier: environment == 'production' ? 'PremiumV3' : 'Basic' capacity: 1 } properties: { reserved: true // Linux } tags: { environment: environment 'app-name': appName } } resource appService 'Microsoft.Web/sites@2023-01-01' = { name: '${environment}-${appName}-web' location: location properties: { serverFarmId: appServicePlan.id httpsOnly: true siteConfig: { linuxFxVersion: 'NODE|20-lts' minTlsVersion: '1.2' ftpsState: 'Disabled' alwaysOn: environment == 'production' healthCheckPath: '/health' } } identity: { type: 'SystemAssigned' } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Azure SQL (Serverless) // --------------------------------------------------------------------------- resource sqlServer 'Microsoft.Sql/servers@2023-05-01-preview' = { name: '${environment}-${appName}-sql' location: location properties: { administrators: { administratorType: 'ActiveDirectory' azureADOnlyAuthentication: true principalType: 'Group' sid: sqlAdminObjectId tenantId: subscription().tenantId } minimalTlsVersion: '1.2' publicNetworkAccess: environment == 'production' ? 'Disabled' : 'Enabled' } tags: { environment: environment 'app-name': appName } } resource sqlDatabase 'Microsoft.Sql/servers/databases@2023-05-01-preview' = { parent: sqlServer name: '${appName}-db' location: location sku: { name: 'GP_S_Gen5_2' tier: 'GeneralPurpose' } properties: { autoPauseDelay: environment == 'production' ? -1 : 60 minCapacity: json('0.5') zoneRedundant: environment == 'production' } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Application Insights + Log Analytics // --------------------------------------------------------------------------- resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: '${environment}-${appName}-logs' location: location properties: { sku: { name: 'PerGB2018' } retentionInDays: environment == 'production' ? 90 : 30 } tags: { environment: environment 'app-name': appName } } resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: '${environment}-${appName}-ai' location: location kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalytics.id } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Outputs // --------------------------------------------------------------------------- output appServiceUrl string = 'https://${appService.properties.defaultHostName}' output keyVaultUri string = keyVault.properties.vaultUri output appInsightsKey string = appInsights.properties.InstrumentationKey output sqlServerFqdn string = sqlServer.properties.fullyQualifiedDomainName """ def _microservices_template() -> str: return r"""// ============================================================================= // Azure Microservices Architecture — Bicep Template // AKS + API Management + Cosmos DB + Service Bus + Key Vault // ============================================================================= @description('Environment name') @allowed(['dev', 'staging', 'production']) param environment string = 'dev' @description('Azure region') param location string = resourceGroup().location @description('Application name') @minLength(3) @maxLength(20) param appName string @description('AKS admin Entra ID group object ID') param aksAdminGroupId string // --------------------------------------------------------------------------- // Key Vault // --------------------------------------------------------------------------- resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { name: '${environment}-${appName}-kv' location: location properties: { sku: { family: 'A', name: 'standard' } tenantId: subscription().tenantId enableRbacAuthorization: true enableSoftDelete: true } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // AKS Cluster // --------------------------------------------------------------------------- resource aksCluster 'Microsoft.ContainerService/managedClusters@2024-01-01' = { name: '${environment}-${appName}-aks' location: location identity: { type: 'SystemAssigned' } properties: { dnsPrefix: '${environment}-${appName}' kubernetesVersion: '1.29' enableRBAC: true aadProfile: { managed: true adminGroupObjectIDs: [aksAdminGroupId] enableAzureRBAC: true } networkProfile: { networkPlugin: 'azure' networkPolicy: 'azure' serviceCidr: '10.0.0.0/16' dnsServiceIP: '10.0.0.10' } agentPoolProfiles: [ { name: 'system' count: environment == 'production' ? 3 : 1 vmSize: 'Standard_D2s_v5' mode: 'System' enableAutoScaling: true minCount: 1 maxCount: 3 availabilityZones: environment == 'production' ? ['1', '2', '3'] : [] } { name: 'app' count: environment == 'production' ? 3 : 1 vmSize: 'Standard_D4s_v5' mode: 'User' enableAutoScaling: true minCount: 1 maxCount: 10 availabilityZones: environment == 'production' ? ['1', '2', '3'] : [] } ] addonProfiles: { omsagent: { enabled: true config: { logAnalyticsWorkspaceResourceID: logAnalytics.id } } } } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Container Registry // --------------------------------------------------------------------------- resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = { name: '${environment}${appName}acr' location: location sku: { name: environment == 'production' ? 'Standard' : 'Basic' } properties: { adminUserEnabled: false } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Cosmos DB (Serverless for dev, Autoscale for prod) // --------------------------------------------------------------------------- resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2023-11-15' = { name: '${environment}-${appName}-cosmos' location: location kind: 'GlobalDocumentDB' properties: { databaseAccountOfferType: 'Standard' consistencyPolicy: { defaultConsistencyLevel: 'Session' } locations: [ { locationName: location, failoverPriority: 0, isZoneRedundant: environment == 'production' } ] capabilities: environment == 'dev' ? [{ name: 'EnableServerless' }] : [] } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Service Bus // --------------------------------------------------------------------------- resource serviceBus 'Microsoft.ServiceBus/namespaces@2022-10-01-preview' = { name: '${environment}-${appName}-sb' location: location sku: { name: 'Standard', tier: 'Standard' } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Log Analytics + Application Insights // --------------------------------------------------------------------------- resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: '${environment}-${appName}-logs' location: location properties: { sku: { name: 'PerGB2018' } retentionInDays: environment == 'production' ? 90 : 30 } tags: { environment: environment 'app-name': appName } } resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: '${environment}-${appName}-ai' location: location kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalytics.id } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Outputs // --------------------------------------------------------------------------- output aksClusterName string = aksCluster.name output acrLoginServer string = acr.properties.loginServer output cosmosEndpoint string = cosmosAccount.properties.documentEndpoint output serviceBusEndpoint string = '${serviceBus.name}.servicebus.windows.net' output keyVaultUri string = keyVault.properties.vaultUri """ def _serverless_template() -> str: return r"""// ============================================================================= // Azure Serverless Architecture — Bicep Template // Azure Functions + Event Grid + Service Bus + Cosmos DB // ============================================================================= @description('Environment name') @allowed(['dev', 'staging', 'production']) param environment string = 'dev' @description('Azure region') param location string = resourceGroup().location @description('Application name') @minLength(3) @maxLength(20) param appName string // --------------------------------------------------------------------------- // Storage Account (required by Functions) // --------------------------------------------------------------------------- resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: '${environment}${appName}st' location: location sku: { name: 'Standard_LRS' } kind: 'StorageV2' properties: { supportsHttpsTrafficOnly: true minimumTlsVersion: 'TLS1_2' allowBlobPublicAccess: false } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Azure Functions (Consumption Plan) // --------------------------------------------------------------------------- resource functionPlan 'Microsoft.Web/serverfarms@2023-01-01' = { name: '${environment}-${appName}-func-plan' location: location sku: { name: 'Y1' tier: 'Dynamic' } properties: { reserved: true // Linux } tags: { environment: environment 'app-name': appName } } resource functionApp 'Microsoft.Web/sites@2023-01-01' = { name: '${environment}-${appName}-func' location: location kind: 'functionapp,linux' identity: { type: 'SystemAssigned' } properties: { serverFarmId: functionPlan.id httpsOnly: true siteConfig: { linuxFxVersion: 'NODE|20' minTlsVersion: '1.2' ftpsState: 'Disabled' appSettings: [ { name: 'AzureWebJobsStorage', value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=core.windows.net;AccountKey=${storageAccount.listKeys().keys[0].value}' } { name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' } { name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' } { name: 'APPINSIGHTS_INSTRUMENTATIONKEY', value: appInsights.properties.InstrumentationKey } { name: 'COSMOS_ENDPOINT', value: cosmosAccount.properties.documentEndpoint } { name: 'SERVICE_BUS_CONNECTION', value: listKeys('${serviceBus.id}/AuthorizationRules/RootManageSharedAccessKey', serviceBus.apiVersion).primaryConnectionString } ] } } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Cosmos DB (Serverless) // --------------------------------------------------------------------------- resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2023-11-15' = { name: '${environment}-${appName}-cosmos' location: location kind: 'GlobalDocumentDB' properties: { databaseAccountOfferType: 'Standard' consistencyPolicy: { defaultConsistencyLevel: 'Session' } locations: [ { locationName: location, failoverPriority: 0 } ] capabilities: [{ name: 'EnableServerless' }] } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Service Bus // --------------------------------------------------------------------------- resource serviceBus 'Microsoft.ServiceBus/namespaces@2022-10-01-preview' = { name: '${environment}-${appName}-sb' location: location sku: { name: 'Basic', tier: 'Basic' } tags: { environment: environment 'app-name': appName } } resource orderQueue 'Microsoft.ServiceBus/namespaces/queues@2022-10-01-preview' = { parent: serviceBus name: 'orders' properties: { maxDeliveryCount: 5 defaultMessageTimeToLive: 'P7D' deadLetteringOnMessageExpiration: true lockDuration: 'PT1M' } } // --------------------------------------------------------------------------- // Application Insights + Log Analytics // --------------------------------------------------------------------------- resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: '${environment}-${appName}-logs' location: location properties: { sku: { name: 'PerGB2018' } retentionInDays: 30 } tags: { environment: environment 'app-name': appName } } resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: '${environment}-${appName}-ai' location: location kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalytics.id } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Outputs // --------------------------------------------------------------------------- output functionAppUrl string = 'https://${functionApp.properties.defaultHostName}' output cosmosEndpoint string = cosmosAccount.properties.documentEndpoint output serviceBusEndpoint string = '${serviceBus.name}.servicebus.windows.net' output appInsightsKey string = appInsights.properties.InstrumentationKey """ def _data_pipeline_template() -> str: return r"""// ============================================================================= // Azure Data Pipeline Architecture — Bicep Template // Event Hubs + Data Lake Gen2 + Synapse Analytics + Azure Functions // ============================================================================= @description('Environment name') @allowed(['dev', 'staging', 'production']) param environment string = 'dev' @description('Azure region') param location string = resourceGroup().location @description('Application name') @minLength(3) @maxLength(20) param appName string // --------------------------------------------------------------------------- // Data Lake Storage Gen2 // --------------------------------------------------------------------------- resource dataLake 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: '${environment}${appName}dl' location: location sku: { name: environment == 'production' ? 'Standard_ZRS' : 'Standard_LRS' } kind: 'StorageV2' properties: { isHnsEnabled: true // Hierarchical namespace for Data Lake Gen2 supportsHttpsTrafficOnly: true minimumTlsVersion: 'TLS1_2' allowBlobPublicAccess: false } tags: { environment: environment 'app-name': appName } } resource rawContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = { name: '${dataLake.name}/default/raw' properties: { publicAccess: 'None' } } resource curatedContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = { name: '${dataLake.name}/default/curated' properties: { publicAccess: 'None' } } // --------------------------------------------------------------------------- // Event Hubs // --------------------------------------------------------------------------- resource eventHubNamespace 'Microsoft.EventHub/namespaces@2023-01-01-preview' = { name: '${environment}-${appName}-eh' location: location sku: { name: 'Standard' tier: 'Standard' capacity: environment == 'production' ? 2 : 1 } properties: { minimumTlsVersion: '1.2' } tags: { environment: environment 'app-name': appName } } resource eventHub 'Microsoft.EventHub/namespaces/eventhubs@2023-01-01-preview' = { parent: eventHubNamespace name: 'ingest' properties: { partitionCount: environment == 'production' ? 8 : 2 messageRetentionInDays: 7 } } resource consumerGroup 'Microsoft.EventHub/namespaces/eventhubs/consumergroups@2023-01-01-preview' = { parent: eventHub name: 'processing' } // --------------------------------------------------------------------------- // Synapse Analytics (Serverless SQL) // --------------------------------------------------------------------------- resource synapse 'Microsoft.Synapse/workspaces@2021-06-01' = { name: '${environment}-${appName}-syn' location: location identity: { type: 'SystemAssigned' } properties: { defaultDataLakeStorage: { accountUrl: 'https://${dataLake.name}.dfs.core.windows.net' filesystem: 'curated' } sqlAdministratorLogin: 'sqladmin' sqlAdministratorLoginPassword: 'REPLACE_WITH_KEYVAULT_REFERENCE' } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Log Analytics // --------------------------------------------------------------------------- resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { name: '${environment}-${appName}-logs' location: location properties: { sku: { name: 'PerGB2018' } retentionInDays: 30 } tags: { environment: environment 'app-name': appName } } // --------------------------------------------------------------------------- // Outputs // --------------------------------------------------------------------------- output dataLakeEndpoint string = 'https://${dataLake.name}.dfs.core.windows.net' output eventHubNamespace string = eventHubNamespace.name output synapseEndpoint string = synapse.properties.connectivityEndpoints.sql """ TEMPLATES: Dict[str, callable] = { "web-app": _web_app_template, "microservices": _microservices_template, "serverless": _serverless_template, "data-pipeline": _data_pipeline_template, } TEMPLATE_DESCRIPTIONS = { "web-app": "App Service + Azure SQL + Front Door + Key Vault + Application Insights", "microservices": "AKS + API Management + Cosmos DB + Service Bus + Key Vault", "serverless": "Azure Functions + Event Grid + Service Bus + Cosmos DB", "data-pipeline": "Event Hubs + Data Lake Gen2 + Synapse Analytics + Azure Functions", } # --------------------------------------------------------------------------- # CLI # --------------------------------------------------------------------------- def main(): parser = argparse.ArgumentParser( description="Azure Bicep Generator — generate Bicep IaC templates for common Azure architecture patterns.", epilog="Examples:\n" " python bicep_generator.py --arch-type web-app\n" " python bicep_generator.py --arch-type microservices --output main.bicep\n" " python bicep_generator.py --arch-type serverless --json", formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument( "--arch-type", required=True, choices=list(TEMPLATES.keys()), help="Architecture pattern type", ) parser.add_argument( "--output", type=str, default=None, help="Write Bicep to file instead of stdout", ) parser.add_argument( "--json", action="store_true", dest="json_output", help="Output metadata as JSON (template content + description)", ) args = parser.parse_args() template_fn = TEMPLATES[args.arch_type] bicep_content = template_fn() if args.json_output: result = { "arch_type": args.arch_type, "description": TEMPLATE_DESCRIPTIONS[args.arch_type], "bicep_template": bicep_content, "lines": len(bicep_content.strip().split("\n")), } print(json.dumps(result, indent=2)) elif args.output: with open(args.output, "w") as f: f.write(bicep_content) print(f"Bicep template written to {args.output} ({len(bicep_content.strip().split(chr(10)))} lines)") print(f"Pattern: {TEMPLATE_DESCRIPTIONS[args.arch_type]}") print(f"\nNext steps:") print(f" 1. az bicep build --file {args.output}") print(f" 2. az deployment group validate --resource-group --template-file {args.output}") print(f" 3. az deployment group create --resource-group --template-file {args.output}") else: print(bicep_content) if __name__ == "__main__": main()