azure-cloud-architect (451-line SKILL.md, 3 scripts, 3 references): - 6-step workflow mirroring aws-solution-architect for Azure - Bicep/ARM templates, AKS, Functions, Cosmos DB, cost optimization - architecture_designer.py, cost_optimizer.py, bicep_generator.py security-pen-testing (850-line SKILL.md, 3 scripts, 3 references): - OWASP Top 10 systematic audit, offensive security testing - XSS/SQLi/SSRF/IDOR detection, secret scanning, API security - vulnerability_scanner.py, dependency_auditor.py, pentest_report_generator.py - Responsible disclosure workflow included terraform-patterns extended (487 → 740 lines): - Multi-cloud provider configuration - OpenTofu compatibility notes - Infracost integration for PR cost estimation - Import existing infrastructure patterns - Terragrunt DRY multi-environment patterns Updated engineering-team plugin.json (26 → 28 skills). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
776 lines
23 KiB
Python
776 lines
23 KiB
Python
#!/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 <rg> --template-file {args.output}")
|
|
print(f" 3. az deployment group create --resource-group <rg> --template-file {args.output}")
|
|
else:
|
|
print(bicep_content)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|