@description('Environment (dev, staging, prod)') param environment string = 'prod' @description('Azure region for resources') param location string = resourceGroup().location @description('Stripe public key for payments') @secure() param stripePublicKey string // Variables var uniqueSuffix = substring(uniqueString(resourceGroup().id), 0, 6) // Cosmos DB Account resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = { name: 'mim-${environment}-${uniqueSuffix}-cosmos' location: location kind: 'GlobalDocumentDB' properties: { databaseAccountOfferType: 'Standard' consistencyPolicy: { defaultConsistencyLevel: 'Session' } locations: [ { locationName: location failoverPriority: 0 isZoneRedundant: false } ] capabilities: [ { name: 'EnableServerless' } ] backupPolicy: { type: 'Periodic' periodicModeProperties: { backupIntervalInMinutes: 240 backupRetentionIntervalInHours: 720 backupStorageRedundancy: 'Local' } } } } // Cosmos DB Database resource cosmosDatabase 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2024-05-15' = { parent: cosmosAccount name: 'MiraclesInMotion' properties: { resource: { id: 'MiraclesInMotion' } } } // Cosmos DB Containers resource donationsContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2024-05-15' = { parent: cosmosDatabase name: 'donations' properties: { resource: { id: 'donations' partitionKey: { paths: ['/id'] kind: 'Hash' } indexingPolicy: { indexingMode: 'consistent' automatic: true includedPaths: [ { path: '/*' } ] } } } } resource volunteersContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2024-05-15' = { parent: cosmosDatabase name: 'volunteers' properties: { resource: { id: 'volunteers' partitionKey: { paths: ['/id'] kind: 'Hash' } } } } resource programsContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2024-05-15' = { parent: cosmosDatabase name: 'programs' properties: { resource: { id: 'programs' partitionKey: { paths: ['/id'] kind: 'Hash' } } } } // Key Vault resource keyVault 'Microsoft.KeyVault/vaults@2024-04-01-preview' = { name: 'mim${environment}${uniqueSuffix}kv' location: location properties: { sku: { family: 'A' name: 'standard' } tenantId: tenant().tenantId accessPolicies: [] enabledForDeployment: false enabledForDiskEncryption: false enabledForTemplateDeployment: true enableSoftDelete: true softDeleteRetentionInDays: 90 enableRbacAuthorization: true } } // Application Insights resource appInsights 'Microsoft.Insights/components@2020-02-02' = { name: 'mim-${environment}-${uniqueSuffix}-insights' location: location kind: 'web' properties: { Application_Type: 'web' WorkspaceResourceId: logAnalyticsWorkspace.id } } // Log Analytics Workspace resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2023-09-01' = { name: 'mim-${environment}-${uniqueSuffix}-logs' location: location properties: { sku: { name: 'PerGB2018' } retentionInDays: 30 } } // Storage Account for Functions resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: 'mim${environment}${uniqueSuffix}st' location: location sku: { name: 'Standard_LRS' } kind: 'StorageV2' properties: { accessTier: 'Hot' supportsHttpsTrafficOnly: true minimumTlsVersion: 'TLS1_2' } } // App Service Plan resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = { name: 'mim-${environment}-${uniqueSuffix}-plan' location: location sku: { name: 'Y1' tier: 'Dynamic' } properties: { reserved: false } } // Function App resource functionApp 'Microsoft.Web/sites@2023-01-01' = { name: 'mim-${environment}-${uniqueSuffix}-func' location: location kind: 'functionapp' identity: { type: 'SystemAssigned' } properties: { serverFarmId: appServicePlan.id siteConfig: { appSettings: [ { name: 'AzureWebJobsStorage' value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=core.windows.net' } { name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};AccountKey=${storageAccount.listKeys().keys[0].value};EndpointSuffix=core.windows.net' } { name: 'WEBSITE_CONTENTSHARE' value: toLower('mim-${environment}-func') } { name: 'FUNCTIONS_EXTENSION_VERSION' value: '~4' } { name: 'FUNCTIONS_WORKER_RUNTIME' value: 'node' } { name: 'WEBSITE_NODE_DEFAULT_VERSION' value: '~22' } { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' value: appInsights.properties.InstrumentationKey } { name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' value: appInsights.properties.ConnectionString } { name: 'COSMOS_CONNECTION_STRING' value: cosmosAccount.listConnectionStrings().connectionStrings[0].connectionString } { name: 'COSMOS_DATABASE_NAME' value: 'MiraclesInMotion' } { name: 'KEY_VAULT_URL' value: keyVault.properties.vaultUri } { name: 'STRIPE_PUBLIC_KEY' value: stripePublicKey } ] } httpsOnly: true } } // SignalR Service resource signalR 'Microsoft.SignalRService/signalR@2023-02-01' = { name: 'mim-${environment}-${uniqueSuffix}-signalr' location: location sku: { name: 'Free_F1' capacity: 1 } kind: 'SignalR' properties: { features: [ { flag: 'ServiceMode' value: 'Serverless' } ] cors: { allowedOrigins: ['*'] } } } // Static Web App resource staticWebApp 'Microsoft.Web/staticSites@2023-01-01' = { name: 'mim-${environment}-${uniqueSuffix}-web' location: 'Central US' sku: { name: 'Free' } properties: { buildProperties: { outputLocation: 'dist' apiLocation: '' appLocation: '/' } stagingEnvironmentPolicy: 'Enabled' } } // Key Vault Secrets resource cosmosConnectionStringSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { parent: keyVault name: 'cosmos-connection-string' properties: { value: cosmosAccount.listConnectionStrings().connectionStrings[0].connectionString } } resource signalRConnectionStringSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { parent: keyVault name: 'signalr-connection-string' properties: { value: signalR.listKeys().primaryConnectionString } } // RBAC Assignments for Function App resource keyVaultSecretsUserRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(keyVault.id, functionApp.id, 'Key Vault Secrets User') scope: keyVault properties: { roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6') // Key Vault Secrets User principalId: functionApp.identity.principalId principalType: 'ServicePrincipal' } } // Outputs output resourceGroupName string = resourceGroup().name output cosmosAccountName string = cosmosAccount.name output functionAppName string = functionApp.name output staticWebAppName string = staticWebApp.name output keyVaultName string = keyVault.name output appInsightsName string = appInsights.name output signalRName string = signalR.name output functionAppUrl string = 'https://${functionApp.properties.defaultHostName}' output staticWebAppUrl string = 'https://${staticWebApp.properties.defaultHostname}'