diff --git a/README.md b/README.md index c812d07..812690b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ description: "This architecture walks you through the process involved in develo [![Node.js CI](https://github.com/Azure-Samples/Serverless-microservices-reference-architecture/actions/workflows/nodejs.yml/badge.svg)](https://github.com/Azure-Samples/Serverless-microservices-reference-architecture/actions/workflows/nodejs.yml) [![spa build](https://github.com/Azure-Samples/Serverless-microservices-reference-architecture/actions/workflows/spa.yml/badge.svg)](https://github.com/Azure-Samples/Serverless-microservices-reference-architecture/actions/workflows/spa.yml) -> This sample has been upgraded to Azure Functions v3. An upgrade to Azure Functions v4 is in progress. See [PR #43](https://github.com/Azure-Samples/Serverless-microservices-reference-architecture/pull/43) for details. +> This sample is being upgraded to Azure Functions v4 / dotnet 6. See [PR #43](https://github.com/Azure-Samples/Serverless-microservices-reference-architecture/pull/43) for details. ## The reference architecture diff --git a/bicep/main.bicep b/bicep/main.bicep index d62d9fb..d2c0841 100644 --- a/bicep/main.bicep +++ b/bicep/main.bicep @@ -1,3 +1,4 @@ +@description('The name of the Rideshare application.') param applicationName string = 'Rideshare' @allowed([ @@ -7,17 +8,27 @@ param applicationName string = 'Rideshare' 'westeurope' 'westus2' ]) +@description('The location that the Static Web App will be deployed to.') param staticWebAppLocation string + +@description('The username that will be used for the provisioned SQL Server.') param sqlAdminLogin string +@description('The password that will be used for the provisioned SQL Server.') @secure() param sqlAdminPassword string + +@description('Service principal Id used for deployment.') +param objectId string + +@description('The resource tags that will be applied to the deployed resources.') param resourceTags object = { ProjectType: 'Azure Serverless Microservices' Purpose: 'Sample' } -var location = resourceGroup().location +param location string = resourceGroup().location + var functionAppServicePlanName = '${applicationName}Plan' var keyVaultName = '${applicationName}KeyVault' var cosmosdbName = '${applicationName}Cosmos' @@ -28,13 +39,18 @@ var apimName = '${applicationName}Apim' var sqlServerName = '${applicationName}-db' var staticWebAppName = '${applicationName}Web' var storageAccountName = take(toLower(replace('${applicationName}func', '-', '')), 24) -var functionsApps = [ - 'Trips' - 'Drivers' - 'Passengers' - 'TripArchiver' - 'Orchestrators' - ] +var functionRuntime = 'dotnet' +var functionVersion = '~4' + +module keyVault 'modules/keyvault.bicep' = { + name: keyVaultName + params: { + keyVaultName: keyVaultName + objectId: objectId + resourceTags: resourceTags + location: location + } +} module cosmos 'modules/cosmosdb.bicep' = { name: cosmosdbName @@ -43,6 +59,7 @@ module cosmos 'modules/cosmosdb.bicep' = { location: location databaseName: applicationName resourceTags: resourceTags + keyVaultName: keyVault.name } } @@ -50,11 +67,12 @@ module sqlDb 'modules/sqldb.bicep' = { name: 'sqldb' params: { sqlServerName: sqlServerName - sqlDatabaeName: applicationName + sqlDatabaseName: applicationName administratorLogin: sqlAdminLogin administratorPassword: sqlAdminPassword location: location resourceTags: resourceTags + keyVaultName: keyVault.name } } @@ -64,6 +82,7 @@ module eventGrid 'modules/eventgrid.bicep' = { eventGridTopicName: eventGridName location: location resourceTags: resourceTags + keyVaultName: keyVault.name } } @@ -73,6 +92,7 @@ module signalR 'modules/signalr.bicep' = { signalRName: signalRName location: location resourceTags: resourceTags + keyVaultName: keyVault.name } } @@ -89,13 +109,14 @@ module apim 'modules/apim.bicep' = { name: apimName params: { apimName: apimName + location: location appInsightsName: applicationInsights.outputs.appInsightsName appInsightsInstrumentationKey: applicationInsights.outputs.appInsightsInstrumentationKey resourceTags: resourceTags } } -module staticeWebApp 'modules/staticwebapp.bicep' = { +module staticWebApp 'modules/staticwebapp.bicep' = { name: staticWebAppName params: { staticWebAppName: staticWebAppName @@ -104,30 +125,486 @@ module staticeWebApp 'modules/staticwebapp.bicep' = { } } -module functions 'modules/functions.bicep' = { - name: 'functions' +module appPlan 'modules/appServicePlan.bicep' = { + name: functionAppServicePlanName params: { - storageAccountName: storageAccountName - functionAppPrefix: applicationName - functionApps: functionsApps appServicePlanName: functionAppServicePlanName location: location - staticWebAppURL: staticeWebApp.outputs.staticWebAppURL - appInsightsInstrumentationKey: applicationInsights.outputs.appInsightsInstrumentationKey - resourceTags: resourceTags } } -module keyVault 'modules/keyvault.bicep' = { - name: keyVaultName +resource storage 'Microsoft.Storage/storageAccounts@2021-08-01' = { + name: storageAccountName + location: location + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + encryption: { + services: { + file: { + keyType: 'Account' + enabled: true + } + blob: { + keyType: 'Account' + enabled: true + } + } + keySource: 'Microsoft.Storage' + } + accessTier: 'Hot' + } +} + +resource tripFunctionApp 'Microsoft.Web/sites@2021-03-01' = { + name: '${applicationName}Trips' + location: location + kind: 'functionapp' + properties: { + serverFarmId: appPlan.outputs.appServicePlanId + siteConfig: { + appSettings: [ + { + name: 'AzureWebJobsStorage' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: 'InstrumentationKey=${applicationInsights.outputs.appInsightsInstrumentationKey}' + } + { + name: 'FUNCTIONS_WORKER_RUNTIME' + value: functionRuntime + } + { + name: 'FUNCTIONS_EXTENSION_VERSION' + value: functionVersion + } + { + name: 'DocDbApiKey' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' + } + { + name: 'DocDbRideShareDatabaseName' + value: cosmos.outputs.cosmosDBDatabaseName + } + { + name: 'DocDbRideShareMainCollectionName' + value: cosmos.outputs.cosmosDBRideMainCollectionName + } + { + name: 'DocDbThroughput' + value: '${cosmos.outputs.cosmosDBThroughput}' + } + { + name: 'InsightsInstrumentationKey' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'IsEnqueueToOrchestrators' + value: 'true' + } + { + name: 'TripManagersQueue' + value: 'trip-managers' + } + { + name: 'TripMonitorsQueue' + value: 'trip-monitors' + } + { + name: 'TripDemosQueue' + value: 'trip-demos' + } + { + name: 'AuthorityUrl' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AuthorityUrl)' + } + { + name: 'ApiApplicationId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiApplicationId)' + } + { + name: 'ApiScopeName' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiScopeName)' + } + { + name: 'EnableAuth' + value: 'true' + } + { + name: 'SqlConnectionString' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/SqlConnectionString)' + } + { + name: 'AzureSignalRConnectionString' + value:'@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AzureSignalRConnectionString)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + httpsOnly: true + } + identity: { + type: 'SystemAssigned' + } +} + +resource driverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { + name: '${applicationName}Drivers' + location: location + kind: 'functionapp' + properties: { + serverFarmId: appPlan.outputs.appServicePlanId + siteConfig: { + appSettings: [ + { + name: 'AzureWebJobsStorage' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: 'InstrumentationKey=${applicationInsights.outputs.appInsightsInstrumentationKey}' + } + { + name: 'FUNCTIONS_WORKER_RUNTIME' + value: functionRuntime + } + { + name: 'FUNCTIONS_EXTENSION_VERSION' + value: functionVersion + } + { + name: 'DocDbApiKey' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' + } + { + name: 'DocDbRideShareDatabaseName' + value: cosmos.outputs.cosmosDBDatabaseName + } + { + name: 'DocDbRideShareMainCollectionName' + value: cosmos.outputs.cosmosDBRideMainCollectionName + } + { + name: 'DocDbThroughput' + value: '${cosmos.outputs.cosmosDBThroughput}' + } + { + name: 'InsightsInstrumentationKey' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'AuthorityUrl' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AuthorityUrl)' + } + { + name: 'ApiApplicationId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiApplicationId)' + } + { + name: 'ApiScopeName' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiScopeName)' + } + { + name: 'EnableAuth' + value: 'true' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + httpsOnly: true + } + identity: { + type: 'SystemAssigned' + } +} + +resource passengerFunctionApp 'Microsoft.Web/sites@2021-03-01' = { + name: '${applicationName}Passengers' + location: location + kind: 'functionapp' + properties: { + serverFarmId: appPlan.outputs.appServicePlanId + siteConfig: { + appSettings: [ + { + name: 'AzureWebJobsStorage' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: 'InstrumentationKey=${applicationInsights.outputs.appInsightsInstrumentationKey}' + } + { + name: 'FUNCTIONS_WORKER_RUNTIME' + value: functionRuntime + } + { + name: 'FUNCTIONS_EXTENSION_VERSION' + value: functionVersion + } + { + name: 'DocDbApiKey' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' + } + { + name: 'DocDbRideShareDatabaseName' + value: cosmos.outputs.cosmosDBDatabaseName + } + { + name: 'DocDbRideShareMainCollectionName' + value: cosmos.outputs.cosmosDBRideMainCollectionName + } + { + name: 'DocDbThroughput' + value: '${cosmos.outputs.cosmosDBThroughput}' + } + { + name: 'InsightsInstrumentationKey' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'AuthorityUrl' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AuthorityUrl)' + } + { + name: 'ApiApplicationId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiApplicationId)' + } + { + name: 'ApiScopeName' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiScopeName)' + } + { + name: 'EnableAuth' + value: 'true' + } + { + name: 'GraphTenantId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/GraphTenantId)' + } + { + name: 'GraphClientId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/GraphClientId)' + } + { + name: 'GraphClientSecret' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/GraphClientSecret)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + } + identity: { + type: 'SystemAssigned' + } +} + +resource orchestratorsFunctionApp 'Microsoft.Web/sites@2021-03-01' = { + name: '${applicationName}Orchestrators' + location: location + kind: 'functionapp' + properties: { + serverFarmId: appPlan.outputs.appServicePlanId + siteConfig: { + appSettings: [ + { + name: 'AzureWebJobsStorage' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' + value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storage.id, storage.apiVersion).keys[0].value}' + } + { + name: 'APPINSIGHTS_INSTRUMENTATIONKEY' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' + value: 'InstrumentationKey=${applicationInsights.outputs.appInsightsInstrumentationKey}' + } + { + name: 'FUNCTIONS_WORKER_RUNTIME' + value: functionRuntime + } + { + name: 'FUNCTIONS_EXTENSION_VERSION' + value: functionVersion + } + { + name: 'DocDbApiKey' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' + } + { + name: 'DocDbRideShareDatabaseName' + value: cosmos.outputs.cosmosDBDatabaseName + } + { + name: 'DocDbRideShareMainCollectionName' + value: cosmos.outputs.cosmosDBRideMainCollectionName + } + { + name: 'DocDbThroughput' + value: '${cosmos.outputs.cosmosDBThroughput}' + } + { + name: 'InsightsInstrumentationKey' + value: applicationInsights.outputs.appInsightsInstrumentationKey + } + { + name: 'DriversAcknowledgeMaxWaitPeriodInSeconds' + value: '120' + } + { + name: 'DriversLocationRadiusInMiles' + value: '15' + } + { + name: 'TripMonitorIntervalInSeconds' + value: '10' + } + { + name: 'TripMonitorMaxIterations' + value: '20' + } + { + name: 'IsPersistDirectly' + value: 'true' + } + { + name: 'TripManagersQueue' + value: 'trip-managers' + } + { + name: 'TripMonitorsQueue' + value: 'trip-monitors' + } + { + name: 'TripDemosQueue' + value: 'trip-demos' + } + { + name: 'TripDriversQueue' + value: 'trip-drivers' + } + { + name: 'TripExternalizationsEventGridTopicUrl' + value: eventGrid.outputs.eventGripEndpoint + } + { + name: 'TripExternalizationsEventGridTopicApiKey' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/TripExternalizationsEventGridTopicApiKey)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + } + identity: { + type: 'SystemAssigned' + } +} + +resource tripArchiverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { + name: '${applicationName}TripArchiver' + location: location + kind: 'functionapp' + properties: { + siteConfig: { + appSettings: [ + { + name: 'FUNCTIONS_EXTENSION_VERSION' + value: '~1' + } + { + name: 'DocDbConnectionString' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbConnectionString)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + } + identity: { + type: 'SystemAssigned' + } +} + +module keyVaultPolicies 'modules/keyvaultPolicies.bicep' = { + name: '${keyVaultName}polices' params: { keyVaultName: keyVaultName - functionAppPrefix: applicationName - functionApps: functionsApps - resourceTags: resourceTags + functionAppPrincipalIds: [ + tripFunctionApp.identity.principalId + driverFunctionApp.identity.principalId + passengerFunctionApp.identity.principalId + tripArchiverFunctionApp.identity.principalId + orchestratorsFunctionApp.identity.principalId + ] } - dependsOn: [ - functions - ] } +output principalId string = orchestratorsFunctionApp.identity.principalId diff --git a/bicep/main.json b/bicep/main.json index c8df7ea..fbe01d5 100644 --- a/bicep/main.json +++ b/bicep/main.json @@ -4,8 +4,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "9570357947747340552" + "version": "0.4.1318.3566", + "templateHash": "8701539398809098241" } }, "parameters": { @@ -35,11 +35,13 @@ "ProjectType": "Azure Serverless Microservices", "Purpose": "Sample" } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" } }, - "functions": [], "variables": { - "location": "[resourceGroup().location]", "functionAppServicePlanName": "[format('{0}Plan', parameters('applicationName'))]", "keyVaultName": "[format('{0}KeyVault', parameters('applicationName'))]", "cosmosdbName": "[format('{0}Cosmos', parameters('applicationName'))]", @@ -49,19 +51,510 @@ "apimName": "[format('{0}Apim', parameters('applicationName'))]", "sqlServerName": "[format('{0}-db', parameters('applicationName'))]", "staticWebAppName": "[format('{0}Web', parameters('applicationName'))]", - "storageAccountName": "[toLower(format('{0}functionstore', parameters('applicationName')))]", + "storageAccountName": "[take(toLower(replace(format('{0}func', parameters('applicationName')), '-', '')), 24)]", "functionsApps": [ "Trips", "Drivers", "Passengers", "TripArchiver", "Orchestrators" - ] + ], + "functionRuntime": "dotnet", + "functionVersion": "~4" }, "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-08-01", + "name": "[variables('storageAccountName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2", + "properties": { + "supportsHttpsTrafficOnly": true, + "encryption": { + "services": { + "file": { + "keyType": "Account", + "enabled": true + }, + "blob": { + "keyType": "Account", + "enabled": true + } + }, + "keySource": "Microsoft.Storage" + }, + "accessTier": "Hot" + } + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-03-01", + "name": "[format('{0}Trips', parameters('applicationName'))]", + "location": "[parameters('location')]", + "kind": "functionapp", + "properties": { + "serverFarmId": "[reference(resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))).outputs.appServicePlanId.value]", + "siteConfig": { + "appSettings": [ + { + "name": "AzureWebJobsStorage", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "APPINSIGHTS_INSTRUMENTATIONKEY", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[format('InstrumentationKey={0}', reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value)]" + }, + { + "name": "FUNCTIONS_WORKER_RUNTIME", + "value": "[variables('functionRuntime')]" + }, + { + "name": "FUNCTIONS_EXTENSION_VERSION", + "value": "[variables('functionVersion')]" + }, + { + "name": "DocDbApiKey", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbPrimaryKey)', variables('keyVaultName'))]" + }, + { + "name": "DocDbEndpointUri", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbEndpoint)', variables('keyVaultName'))]" + }, + { + "name": "DocDbRideShareDatabaseName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBDatabaseName.value]" + }, + { + "name": "DocDbRideShareMainCollectionName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBRideMainCollectionName.value]" + }, + { + "name": "DocDbThroughput", + "value": "[format('{0}', reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBThroughput.value)]" + }, + { + "name": "InsightsInstrumentationKey", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "IsEnqueueToOrchestrators", + "value": "true" + }, + { + "name": "TripManagersQueue", + "value": "trip-managers" + }, + { + "name": "TripMonitorsQueue", + "value": "trip-monitors" + }, + { + "name": "TripDemosQueue", + "value": "trip-demos" + }, + { + "name": "AuthorityUrl", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/AuthorityUrl)', variables('keyVaultName'))]" + }, + { + "name": "ApiApplicationId", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/ApiApplicationId)', variables('keyVaultName'))]" + }, + { + "name": "ApiScopeName", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/ApiScopeName)', variables('keyVaultName'))]" + }, + { + "name": "EnableAuth", + "value": "true" + }, + { + "name": "SqlConnectionString", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/SqlConnectionString)', variables('keyVaultName'))]" + }, + { + "name": "AzureSignalRConnectionString", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/AzureSignalRConnectionString)', variables('keyVaultName'))]" + } + ], + "cors": { + "allowedOrigins": [ + "[reference(resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))).outputs.staticWebAppURL.value]" + ] + } + }, + "httpsOnly": true + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-03-01", + "name": "[format('{0}Drivers', parameters('applicationName'))]", + "location": "[parameters('location')]", + "kind": "functionapp", + "properties": { + "serverFarmId": "[reference(resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))).outputs.appServicePlanId.value]", + "siteConfig": { + "appSettings": [ + { + "name": "AzureWebJobsStorage", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "APPINSIGHTS_INSTRUMENTATIONKEY", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[format('InstrumentationKey={0}', reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value)]" + }, + { + "name": "FUNCTIONS_WORKER_RUNTIME", + "value": "[variables('functionRuntime')]" + }, + { + "name": "FUNCTIONS_EXTENSION_VERSION", + "value": "[variables('functionVersion')]" + }, + { + "name": "DocDbApiKey", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbPrimaryKey)', variables('keyVaultName'))]" + }, + { + "name": "DocDbEndpointUri", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbEndpoint)', variables('keyVaultName'))]" + }, + { + "name": "DocDbRideShareDatabaseName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBDatabaseName.value]" + }, + { + "name": "DocDbRideShareMainCollectionName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBRideMainCollectionName.value]" + }, + { + "name": "DocDbThroughput", + "value": "[format('{0}', reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBThroughput.value)]" + }, + { + "name": "InsightsInstrumentationKey", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "AuthorityUrl", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/AuthorityUrl)', variables('keyVaultName'))]" + }, + { + "name": "ApiApplicationId", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/ApiApplicationId)', variables('keyVaultName'))]" + }, + { + "name": "ApiScopeName", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/ApiScopeName)', variables('keyVaultName'))]" + }, + { + "name": "EnableAuth", + "value": "true" + } + ], + "cors": { + "allowedOrigins": [ + "[reference(resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))).outputs.staticWebAppURL.value]" + ] + } + }, + "httpsOnly": true + }, + "identity": { + "type": "SystemAssigned" + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-03-01", + "name": "[format('{0}Passengers', parameters('applicationName'))]", + "location": "[parameters('location')]", + "kind": "functionapp", + "properties": { + "serverFarmId": "[reference(resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))).outputs.appServicePlanId.value]", + "siteConfig": { + "appSettings": [ + { + "name": "AzureWebJobsStorage", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "APPINSIGHTS_INSTRUMENTATIONKEY", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[format('InstrumentationKey={0}', reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value)]" + }, + { + "name": "FUNCTIONS_WORKER_RUNTIME", + "value": "[variables('functionRuntime')]" + }, + { + "name": "FUNCTIONS_EXTENSION_VERSION", + "value": "[variables('functionVersion')]" + }, + { + "name": "DocDbApiKey", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbPrimaryKey)', variables('keyVaultName'))]" + }, + { + "name": "DocDbEndpointUri", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbEndpoint)', variables('keyVaultName'))]" + }, + { + "name": "DocDbRideShareDatabaseName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBDatabaseName.value]" + }, + { + "name": "DocDbRideShareMainCollectionName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBRideMainCollectionName.value]" + }, + { + "name": "DocDbThroughput", + "value": "[format('{0}', reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBThroughput.value)]" + }, + { + "name": "InsightsInstrumentationKey", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "AuthorityUrl", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/AuthorityUrl)', variables('keyVaultName'))]" + }, + { + "name": "ApiApplicationId", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/ApiApplicationId)', variables('keyVaultName'))]" + }, + { + "name": "ApiScopeName", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/ApiScopeName)', variables('keyVaultName'))]" + }, + { + "name": "EnableAuth", + "value": "true" + }, + { + "name": "GraphTenantId", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/GraphTenantId)', variables('keyVaultName'))]" + }, + { + "name": "GraphClientId", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/GraphClientId)', variables('keyVaultName'))]" + }, + { + "name": "GraphClientSecret", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/GraphClientSecret)', variables('keyVaultName'))]" + } + ], + "cors": { + "allowedOrigins": [ + "[reference(resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))).outputs.staticWebAppURL.value]" + ] + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-03-01", + "name": "[format('{0}Passengers', parameters('applicationName'))]", + "location": "[parameters('location')]", + "kind": "functionapp", + "properties": { + "serverFarmId": "[reference(resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))).outputs.appServicePlanId.value]", + "siteConfig": { + "appSettings": [ + { + "name": "AzureWebJobsStorage", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", + "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', variables('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2021-08-01').keys[0].value)]" + }, + { + "name": "APPINSIGHTS_INSTRUMENTATIONKEY", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", + "value": "[format('InstrumentationKey={0}', reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value)]" + }, + { + "name": "FUNCTIONS_WORKER_RUNTIME", + "value": "[variables('functionRuntime')]" + }, + { + "name": "FUNCTIONS_EXTENSION_VERSION", + "value": "[variables('functionVersion')]" + }, + { + "name": "DocDbApiKey", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbPrimaryKey)', variables('keyVaultName'))]" + }, + { + "name": "DocDbEndpointUri", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbEndpoint)', variables('keyVaultName'))]" + }, + { + "name": "DocDbRideShareDatabaseName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBDatabaseName.value]" + }, + { + "name": "DocDbRideShareMainCollectionName", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBRideMainCollectionName.value]" + }, + { + "name": "DocDbThroughput", + "value": "[format('{0}', reference(resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))).outputs.cosmosDBThroughput.value)]" + }, + { + "name": "InsightsInstrumentationKey", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" + }, + { + "name": "DriversAcknowledgeMaxWaitPeriodInSeconds", + "value": "120" + }, + { + "name": "DriversLocationRadiusInMiles", + "value": "15" + }, + { + "name": "TripMonitorIntervalInSeconds", + "value": "10" + }, + { + "name": "TripMonitorMaxIterations", + "value": "20" + }, + { + "name": "IsPersistDirectly", + "value": "true" + }, + { + "name": "TripManagersQueue", + "value": "trip-managers" + }, + { + "name": "TripMonitorsQueue", + "value": "trip-monitors" + }, + { + "name": "TripDemosQueue", + "value": "trip-demos" + }, + { + "name": "TripDriversQueue", + "value": "trip-drivers" + }, + { + "name": "TripExternalizationsEventGridTopicUrl", + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('eventGridName'))).outputs.eventGripEndpoint.value]" + }, + { + "name": "TripExternalizationsEventGridTopicApiKey", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/TripExternalizationsEventGridTopicApiKey)', variables('keyVaultName'))]" + } + ], + "cors": { + "allowedOrigins": [ + "[reference(resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))).outputs.staticWebAppURL.value]" + ] + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('functionAppServicePlanName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('cosmosdbName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('eventGridName'))]", + "[resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))]", + "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2021-03-01", + "name": "[format('{0}TripArchiver', parameters('applicationName'))]", + "location": "[parameters('location')]", + "kind": "functionapp", + "properties": { + "siteConfig": { + "appSettings": [ + { + "name": "FUNCTIONS_EXTENSION_VERSION", + "value": "~1" + }, + { + "name": "DocDbConnectionString", + "value": "[format('@Microsoft.KeyVault(SecretUri=https:://{0}.vault.azure.net/secrets/CosmosDbConnectionString)', variables('keyVaultName'))]" + } + ], + "cors": { + "allowedOrigins": [ + "[reference(resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))).outputs.staticWebAppURL.value]" + ] + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))]" + ] + }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('cosmosdbName')]", "properties": { "expressionEvaluationOptions": { @@ -73,13 +566,16 @@ "value": "[variables('cosmosdbName')]" }, "location": { - "value": "[variables('location')]" + "value": "[parameters('location')]" }, "databaseName": { "value": "[parameters('applicationName')]" }, "resourceTags": { "value": "[parameters('resourceTags')]" + }, + "keyVaultName": { + "value": "[variables('keyVaultName')]" } }, "template": { @@ -88,8 +584,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "3083240189091619866" + "version": "0.4.1318.3566", + "templateHash": "10836054490273803686" } }, "parameters": { @@ -114,14 +610,26 @@ }, "resourceTags": { "type": "object" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Name of the Key Vault to store secrets in." + } + }, + "throughput": { + "type": "int", + "defaultValue": 400 } }, - "functions": [], "variables": { "containerNames": [ "main", "archiver" - ] + ], + "cosmosDbConnectionStringSecretName": "CosmosDbConnectionString", + "cosmosDbPrimaryKeySecretName": "CosmosDbPrimaryKey", + "cosmosDbEndpointSecretName": "CosmosDbEndpoint" }, "resources": [ { @@ -136,11 +644,6 @@ "consistencyPolicy": { "defaultConsistencyLevel": "Session" }, - "capabilities": [ - { - "name": "EnableServerless" - } - ], "enableFreeTier": false, "locations": [ { @@ -164,6 +667,9 @@ "properties": { "resource": { "id": "[format('{0}', toLower(parameters('databaseName')))]" + }, + "options": { + "throughput": "[parameters('throughput')]" } }, "dependsOn": [ @@ -193,12 +699,57 @@ "[resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName')))]", "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlDatabases', toLower(parameters('accountName')), format('{0}', toLower(parameters('databaseName'))))]" ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-11-01-preview", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('cosmosDbPrimaryKeySecretName'))]", + "properties": { + "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName'))), '2021-06-15').primaryMasterKey]" + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName')))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-11-01-preview", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('cosmosDbConnectionStringSecretName'))]", + "properties": { + "value": "[listConnectionStrings(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName'))), '2021-06-15').connectionStrings[0].connectionString]" + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName')))]" + ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-11-01-preview", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('cosmosDbEndpointSecretName'))]", + "properties": { + "value": "[reference(resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName')))).documentEndpoint]" + }, + "dependsOn": [ + "[resourceId('Microsoft.DocumentDB/databaseAccounts', toLower(parameters('accountName')))]" + ] } ], "outputs": { "cosmosDBAccountName": { "type": "string", "value": "[toLower(parameters('accountName'))]" + }, + "cosmosDBDatabaseName": { + "type": "string", + "value": "[format('{0}', toLower(parameters('databaseName')))]" + }, + "cosmosDBRideMainCollectionName": { + "type": "string", + "value": "[variables('containerNames')[0]]" + }, + "cosmosDBThroughput": { + "type": "int", + "value": "[parameters('throughput')]" } } } @@ -206,7 +757,7 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "sqldb", "properties": { "expressionEvaluationOptions": { @@ -217,7 +768,7 @@ "sqlServerName": { "value": "[variables('sqlServerName')]" }, - "sqlDatabaeName": { + "sqlDatabaseName": { "value": "[parameters('applicationName')]" }, "administratorLogin": { @@ -227,10 +778,13 @@ "value": "[parameters('sqlAdminPassword')]" }, "location": { - "value": "[variables('location')]" + "value": "[parameters('location')]" }, "resourceTags": { "value": "[parameters('resourceTags')]" + }, + "keyVaultName": { + "value": "[variables('keyVaultName')]" } }, "template": { @@ -239,15 +793,15 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "5407239579252073037" + "version": "0.4.1318.3566", + "templateHash": "3153046550953969148" } }, "parameters": { "sqlServerName": { "type": "string" }, - "sqlDatabaeName": { + "sqlDatabaseName": { "type": "string" }, "location": { @@ -261,9 +815,17 @@ }, "resourceTags": { "type": "object" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Name of the Key Vault to store secrets in." + } } }, - "functions": [], + "variables": { + "sqlDbConnectionStringSecretName": "SqlConnectionString" + }, "resources": [ { "type": "Microsoft.Sql/servers", @@ -280,7 +842,7 @@ { "type": "Microsoft.Sql/servers/databases", "apiVersion": "2021-05-01-preview", - "name": "[format('{0}/{1}', parameters('sqlServerName'), parameters('sqlDatabaeName'))]", + "name": "[format('{0}/{1}', parameters('sqlServerName'), parameters('sqlDatabaseName'))]", "location": "[parameters('location')]", "tags": "[parameters('resourceTags')]", "sku": { @@ -296,6 +858,18 @@ "dependsOn": [ "[resourceId('Microsoft.Sql/servers', parameters('sqlServerName'))]" ] + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-11-01-preview", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('sqlDbConnectionStringSecretName'))]", + "properties": { + "value": "[format('Server=tcp:{0}{1},1433;Initial Catalog=db{2};Persist Security Info=False;User ID={3};Password={4};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;', parameters('sqlServerName'), environment().suffixes.sqlServerHostname, parameters('sqlDatabaseName'), parameters('administratorLogin'), parameters('administratorPassword'))]" + }, + "dependsOn": [ + "[resourceId('Microsoft.Sql/servers/databases', parameters('sqlServerName'), parameters('sqlDatabaseName'))]", + "[resourceId('Microsoft.Sql/servers', parameters('sqlServerName'))]" + ] } ] } @@ -303,7 +877,7 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('eventGridName')]", "properties": { "expressionEvaluationOptions": { @@ -315,10 +889,13 @@ "value": "[variables('eventGridName')]" }, "location": { - "value": "[variables('location')]" + "value": "[parameters('location')]" }, "resourceTags": { "value": "[parameters('resourceTags')]" + }, + "keyVaultName": { + "value": "[variables('keyVaultName')]" } }, "template": { @@ -327,22 +904,36 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "17203959133581660403" + "version": "0.4.1318.3566", + "templateHash": "13429133402434012737" } }, "parameters": { "eventGridTopicName": { - "type": "string" + "type": "string", + "metadata": { + "description": "Name of the Event Grid Topic" + } }, "location": { - "type": "string" + "type": "string", + "metadata": { + "description": "The location that the Event Grid Topic will be deployed to" + } }, "resourceTags": { "type": "object" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Name of the Key Vault to store secrets in." + } } }, - "functions": [], + "variables": { + "eventGridTopicApiKeySecretName": "TripExternalizationsEventGridTopicApiKey" + }, "resources": [ { "type": "Microsoft.EventGrid/topics", @@ -354,6 +945,17 @@ "publicNetworkAccess": "Enabled", "inputSchema": "EventGridSchema" } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-11-01-preview", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('eventGridTopicApiKeySecretName'))]", + "properties": { + "value": "[listKeys(resourceId('Microsoft.EventGrid/topics', parameters('eventGridTopicName')), '2020-06-01').key1]" + }, + "dependsOn": [ + "[resourceId('Microsoft.EventGrid/topics', parameters('eventGridTopicName'))]" + ] } ], "outputs": { @@ -367,7 +969,7 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('signalRName')]", "properties": { "expressionEvaluationOptions": { @@ -379,10 +981,13 @@ "value": "[variables('signalRName')]" }, "location": { - "value": "[variables('location')]" + "value": "[parameters('location')]" }, "resourceTags": { "value": "[parameters('resourceTags')]" + }, + "keyVaultName": { + "value": "[variables('keyVaultName')]" } }, "template": { @@ -391,8 +996,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "2160980875649621117" + "version": "0.4.1318.3566", + "templateHash": "2675249973579397886" } }, "parameters": { @@ -404,9 +1009,17 @@ }, "resourceTags": { "type": "object" + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Name of the Key Vault to store secrets in." + } } }, - "functions": [], + "variables": { + "signalRConnectionStringSecretName": "AzureSignalRConnectionString" + }, "resources": [ { "type": "Microsoft.SignalRService/signalR", @@ -423,6 +1036,17 @@ "properties": { "hostNamePrefix": null } + }, + { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2021-11-01-preview", + "name": "[format('{0}/{1}', parameters('keyVaultName'), variables('signalRConnectionStringSecretName'))]", + "properties": { + "value": "[listKeys(resourceId('Microsoft.SignalRService/signalR', parameters('signalRName')), '2018-10-01').primaryConnectionString]" + }, + "dependsOn": [ + "[resourceId('Microsoft.SignalRService/signalR', parameters('signalRName'))]" + ] } ] } @@ -430,7 +1054,7 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('applicationInsightsName')]", "properties": { "expressionEvaluationOptions": { @@ -442,7 +1066,7 @@ "value": "[variables('applicationInsightsName')]" }, "location": { - "value": "[variables('location')]" + "value": "[parameters('location')]" }, "resourceTags": { "value": "[parameters('resourceTags')]" @@ -454,8 +1078,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "16613972829894520281" + "version": "0.4.1318.3566", + "templateHash": "14891316511597726658" } }, "parameters": { @@ -469,7 +1093,6 @@ "type": "object" } }, - "functions": [], "resources": [ { "type": "Microsoft.Insights/components", @@ -498,7 +1121,7 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('apimName')]", "properties": { "expressionEvaluationOptions": { @@ -509,11 +1132,14 @@ "apimName": { "value": "[variables('apimName')]" }, + "location": { + "value": "[parameters('location')]" + }, "appInsightsName": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName')), '2020-06-01').outputs.appInsightsName.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsName.value]" }, "appInsightsInstrumentationKey": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName')), '2020-06-01').outputs.appInsightsInstrumentationKey.value]" + "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))).outputs.appInsightsInstrumentationKey.value]" }, "resourceTags": { "value": "[parameters('resourceTags')]" @@ -525,8 +1151,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "12818415135131956890" + "version": "0.4.1318.3566", + "templateHash": "9214130584774277020" } }, "parameters": { @@ -566,11 +1192,15 @@ "metadata": { "description": "The instance size of this API Management service." } + }, + "location": { + "type": "string", + "metadata": { + "description": "The location of this API Management service" + } } }, - "functions": [], "variables": { - "location": "[resourceGroup().location]", "publisherEmail": "email@contoso.com", "publisherName": "Company Name" }, @@ -579,7 +1209,7 @@ "type": "Microsoft.ApiManagement/service", "apiVersion": "2021-01-01-preview", "name": "[parameters('apimName')]", - "location": "[variables('location')]", + "location": "[parameters('location')]", "tags": "[parameters('resourceTags')]", "sku": { "name": "[parameters('sku')]", @@ -645,7 +1275,7 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('staticWebAppName')]", "properties": { "expressionEvaluationOptions": { @@ -669,8 +1299,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "9606543262645889119" + "version": "0.4.1318.3566", + "templateHash": "990238708955225645" } }, "parameters": { @@ -684,7 +1314,6 @@ "type": "object" } }, - "functions": [], "resources": [ { "type": "Microsoft.Web/staticSites", @@ -717,37 +1346,19 @@ }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", - "name": "functions", + "apiVersion": "2020-10-01", + "name": "[variables('functionAppServicePlanName')]", "properties": { "expressionEvaluationOptions": { "scope": "inner" }, "mode": "Incremental", "parameters": { - "storageAccountName": { - "value": "[variables('storageAccountName')]" - }, - "functionAppPrefix": { - "value": "[parameters('applicationName')]" - }, - "functionApps": { - "value": "[variables('functionsApps')]" - }, "appServicePlanName": { "value": "[variables('functionAppServicePlanName')]" }, "location": { - "value": "[variables('location')]" - }, - "staticWebAppURL": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('staticWebAppName')), '2020-06-01').outputs.staticWebAppURL.value]" - }, - "appInsightsInstrumentationKey": { - "value": "[reference(resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName')), '2020-06-01').outputs.appInsightsInstrumentationKey.value]" - }, - "resourceTags": { - "value": "[parameters('resourceTags')]" + "value": "[parameters('location')]" } }, "template": { @@ -756,71 +1367,20 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "105252057361555557" + "version": "0.4.1318.3566", + "templateHash": "1091027108330860427" } }, "parameters": { - "storageAccountName": { - "type": "string" - }, - "functionAppPrefix": { - "type": "string" - }, - "functionApps": { - "type": "array" - }, "appServicePlanName": { "type": "string" }, "location": { "type": "string", "defaultValue": "[resourceGroup().location]" - }, - "staticWebAppURL": { - "type": "string" - }, - "appInsightsInstrumentationKey": { - "type": "string" - }, - "resourceTags": { - "type": "object" } }, - "functions": [], - "variables": { - "functionRuntime": "dotnet", - "functionVersion": "~4" - }, "resources": [ - { - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2019-06-01", - "name": "[parameters('storageAccountName')]", - "location": "[parameters('location')]", - "tags": "[parameters('resourceTags')]", - "sku": { - "name": "Standard_LRS" - }, - "kind": "StorageV2", - "properties": { - "supportsHttpsTrafficOnly": true, - "encryption": { - "services": { - "file": { - "keyType": "Account", - "enabled": true - }, - "blob": { - "keyType": "Account", - "enabled": true - } - }, - "keySource": "Microsoft.Storage" - }, - "accessTier": "Hot" - } - }, { "type": "Microsoft.Web/serverfarms", "apiVersion": "2020-06-01", @@ -832,73 +1392,20 @@ "tier": "Dynamic" }, "properties": {} - }, - { - "copy": { - "name": "functionApp", - "count": "[length(parameters('functionApps'))]" - }, - "type": "Microsoft.Web/sites", - "apiVersion": "2020-06-01", - "name": "[format('{0}{1}', parameters('functionAppPrefix'), parameters('functionApps')[copyIndex()])]", - "location": "[parameters('location')]", - "kind": "functionapp", - "properties": { - "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]", - "siteConfig": { - "appSettings": [ - { - "name": "AzureWebJobsStorage", - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]" - }, - { - "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", - "value": "[format('DefaultEndpointsProtocol=https;AccountName={0};EndpointSuffix={1};AccountKey={2}', parameters('storageAccountName'), environment().suffixes.storage, listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]" - }, - { - "name": "APPINSIGHTS_INSTRUMENTATIONKEY", - "value": "[parameters('appInsightsInstrumentationKey')]" - }, - { - "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", - "value": "[format('InstrumentationKey={0}', parameters('appInsightsInstrumentationKey'))]" - }, - { - "name": "FUNCTIONS_WORKER_RUNTIME", - "value": "[variables('functionRuntime')]" - }, - { - "name": "FUNCTIONS_EXTENSION_VERSION", - "value": "[variables('functionVersion')]" - } - ], - "cors": { - "allowedOrigins": [ - "[parameters('staticWebAppURL')]" - ] - } - }, - "httpsOnly": true - }, - "identity": { - "type": "SystemAssigned" - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]", - "[resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName'))]" - ] } - ] + ], + "outputs": { + "appServicePlanId": { + "type": "string", + "value": "[resourceId('Microsoft.Web/serverfarms', parameters('appServicePlanName'))]" + } + } } - }, - "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', variables('applicationInsightsName'))]", - "[resourceId('Microsoft.Resources/deployments', variables('staticWebAppName'))]" - ] + } }, { "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-06-01", + "apiVersion": "2020-10-01", "name": "[variables('keyVaultName')]", "properties": { "expressionEvaluationOptions": { @@ -917,6 +1424,9 @@ }, "resourceTags": { "value": "[parameters('resourceTags')]" + }, + "location": { + "value": "[parameters('location')]" } }, "template": { @@ -925,8 +1435,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.4.1008.15138", - "templateHash": "14106814129237260996" + "version": "0.4.1318.3566", + "templateHash": "3427998671960147103" } }, "parameters": { @@ -941,15 +1451,17 @@ }, "resourceTags": { "type": "object" + }, + "location": { + "type": "string" } }, - "functions": [], "resources": [ { "type": "Microsoft.KeyVault/vaults", "apiVersion": "2021-06-01-preview", "name": "[parameters('keyVaultName')]", - "location": "[resourceGroup().location]", + "location": "[parameters('location')]", "properties": { "copy": [ { @@ -978,7 +1490,11 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Resources/deployments', 'functions')]" + "[resourceId('Microsoft.Web/sites', format('{0}Drivers', parameters('applicationName')))]", + "[resourceId('Microsoft.Web/sites', format('{0}Passengers', parameters('applicationName')))]", + "[resourceId('Microsoft.Web/sites', format('{0}Passengers', parameters('applicationName')))]", + "[resourceId('Microsoft.Web/sites', format('{0}TripArchiver', parameters('applicationName')))]", + "[resourceId('Microsoft.Web/sites', format('{0}Trips', parameters('applicationName')))]" ] } ] diff --git a/bicep/modules/apim.bicep b/bicep/modules/apim.bicep index 9efe91b..fae8b71 100644 --- a/bicep/modules/apim.bicep +++ b/bicep/modules/apim.bicep @@ -1,7 +1,13 @@ @description('API Management DB account name') param apimName string + +@description('The name of the Application insights workspace to send APIM logs to.') param appInsightsName string + +@description('The Application insights instrumentation key to authenticate APIM logs.') param appInsightsInstrumentationKey string + +@description('The resource tags that will be applied to the APIM instance.') param resourceTags object @allowed([ @@ -18,7 +24,9 @@ param sku string = 'Developer' @minValue(1) param skuCount int = 1 -var location = resourceGroup().location +@description('The location of this API Management service') +param location string + var publisherEmail = 'email@contoso.com' var publisherName = 'Company Name' diff --git a/bicep/modules/apimAPI.bicep b/bicep/modules/apimAPI.bicep index 262a726..5876025 100644 --- a/bicep/modules/apimAPI.bicep +++ b/bicep/modules/apimAPI.bicep @@ -1,7 +1,16 @@ +@description('The name of the APIM instance that the APIs will be deployed to.') param apimName string + +@description('The resource group that the APIM is deployed to.') param currentResourceGroup string + +@description('The name of the Backend API in APIM.') param backendApiName string + +@description('The name of the API.') param apiName string + +@description('The origin URL used for the backend policy.') param originUrl string var functionAppKeyName = '${backendApiName}-key' diff --git a/bicep/modules/appServicePlan.bicep b/bicep/modules/appServicePlan.bicep new file mode 100644 index 0000000..6dff5a2 --- /dev/null +++ b/bicep/modules/appServicePlan.bicep @@ -0,0 +1,18 @@ +@description('The name of the App Service Plan that will be deployed.') +param appServicePlanName string + +@description('The location that the App Service Plan will be deployed to. Default value is the location of the resource group.') +param location string = resourceGroup().location + +resource plan 'Microsoft.Web/serverFarms@2020-06-01' = { + name: appServicePlanName + location: location + kind: 'functionapp' + sku: { + name: 'Y1' + tier: 'Dynamic' + } + properties: {} +} + +output appServicePlanId string = plan.id diff --git a/bicep/modules/applicationInsights.bicep b/bicep/modules/applicationInsights.bicep index aa909c3..b1a0270 100644 --- a/bicep/modules/applicationInsights.bicep +++ b/bicep/modules/applicationInsights.bicep @@ -1,5 +1,10 @@ +@description('The name of the Application insights workspace that will be deployed.') param applicationInsightsName string + +@description('The location that the Application insights workspace that will be deployed to.') param location string + +@description('The resource tags that will be applied to this Application insights workspace.') param resourceTags object resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { diff --git a/bicep/modules/cosmosdb.bicep b/bicep/modules/cosmosdb.bicep index 7a75665..da29266 100644 --- a/bicep/modules/cosmosdb.bicep +++ b/bicep/modules/cosmosdb.bicep @@ -1,4 +1,3 @@ - @description('Cosmos DB account name') param accountName string @@ -7,8 +6,14 @@ param location string = resourceGroup().location @description('The name for the Core (SQL) database') param databaseName string + +@description('The resource tags that will be applied to the Cosmos DB account.') param resourceTags object +@description('Name of the Key Vault to store secrets in.') +param keyVaultName string + +@description('The amount of Request Units that will be provisioned to the database. Default value is 400 RUs.') param throughput int = 400 var containerNames = [ @@ -16,6 +21,10 @@ var containerNames = [ 'archiver' ] +var cosmosDbConnectionStringSecretName = 'CosmosDbConnectionString' +var cosmosDbPrimaryKeySecretName = 'CosmosDbPrimaryKey' +var cosmosDbEndpointSecretName = 'CosmosDbEndpoint' + resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2021-06-15' = { name: toLower(accountName) kind: 'GlobalDocumentDB' @@ -56,13 +65,13 @@ resource cosmosDB 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2021-06-15 } } -resource containers 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2021-06-15' = [for cotainerName in containerNames :{ - name: cotainerName +resource containers 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2021-06-15' = [for containerName in containerNames :{ + name: containerName parent: cosmosDB tags: resourceTags properties: { resource: { - id: cotainerName + id: containerName partitionKey: { paths: [ '/code' @@ -72,4 +81,35 @@ resource containers 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containe } }] +resource keyVault 'Microsoft.KeyVault/vaults@2021-11-01-preview' existing = { + name: keyVaultName +} + +resource cosmosKeySecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = { + name: cosmosDbPrimaryKeySecretName + parent: keyVault + properties: { + value: cosmosAccount.listKeys().primaryMasterKey + } +} + +resource cosmosConnectionSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = { + name: cosmosDbConnectionStringSecretName + parent: keyVault + properties: { + value: cosmosAccount.listConnectionStrings().connectionStrings[0].connectionString + } +} + +resource cosmosEndpointSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = { + name: cosmosDbEndpointSecretName + parent: keyVault + properties: { + value: cosmosAccount.properties.documentEndpoint + } +} + output cosmosDBAccountName string = cosmosAccount.name +output cosmosDBDatabaseName string = cosmosDB.name +output cosmosDBRideMainCollectionName string = containerNames[0] +output cosmosDBThroughput int = throughput diff --git a/bicep/modules/eventgrid.bicep b/bicep/modules/eventgrid.bicep index 1616361..1fb5289 100644 --- a/bicep/modules/eventgrid.bicep +++ b/bicep/modules/eventgrid.bicep @@ -1,7 +1,17 @@ +@description('Name of the Event Grid Topic') param eventGridTopicName string + +@description('The location that the Event Grid Topic will be deployed to') param location string + +@description('The resource tags that will be applied to the Event Grid resource.') param resourceTags object +@description('Name of the Key Vault to store secrets in.') +param keyVaultName string + +var eventGridTopicApiKeySecretName = 'TripExternalizationsEventGridTopicApiKey' + resource eventGrid 'Microsoft.EventGrid/topics@2020-06-01' = { name: eventGridTopicName location: location @@ -12,4 +22,16 @@ resource eventGrid 'Microsoft.EventGrid/topics@2020-06-01' = { } } +resource keyVault 'Microsoft.KeyVault/vaults@2021-11-01-preview' existing = { + name: keyVaultName +} + +resource eventGridTopicApiKey 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = { + name: eventGridTopicApiKeySecretName + parent: keyVault + properties: { + value: eventGrid.listKeys().key1 + } +} + output eventGripEndpoint string = eventGrid.properties.endpoint diff --git a/bicep/modules/functions.bicep b/bicep/modules/functions.bicep deleted file mode 100644 index 2e65772..0000000 --- a/bicep/modules/functions.bicep +++ /dev/null @@ -1,95 +0,0 @@ -param storageAccountName string -param functionAppPrefix string -param functionApps array -param appServicePlanName string -param location string = resourceGroup().location -param staticWebAppURL string -param appInsightsInstrumentationKey string -param resourceTags object - -var functionRuntime = 'dotnet' -var functionVersion = '~4' - -resource storageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = { - name: storageAccountName - location: location - tags: resourceTags - sku: { - name: 'Standard_LRS' - } - kind: 'StorageV2' - properties: { - supportsHttpsTrafficOnly: true - encryption: { - services: { - file: { - keyType: 'Account' - enabled: true - } - blob: { - keyType: 'Account' - enabled: true - } - } - keySource: 'Microsoft.Storage' - } - accessTier: 'Hot' - } -} - -resource plan 'Microsoft.Web/serverFarms@2020-06-01' = { - name: appServicePlanName - location: location - kind: 'functionapp' - sku: { - name: 'Y1' - tier: 'Dynamic' - } - properties: {} -} - -resource functionApp 'Microsoft.Web/sites@2020-06-01' = [for functionApp in functionApps :{ - name: '${functionAppPrefix}${functionApp}' - location: location - kind: 'functionapp' - properties: { - serverFarmId: plan.id - siteConfig: { - appSettings: [ - { - name: 'AzureWebJobsStorage' - value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}' - } - { - name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' - value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${listKeys(storageAccount.id, storageAccount.apiVersion).keys[0].value}' - } - { - name: 'APPINSIGHTS_INSTRUMENTATIONKEY' - value: appInsightsInstrumentationKey - } - { - name: 'APPLICATIONINSIGHTS_CONNECTION_STRING' - value: 'InstrumentationKey=${appInsightsInstrumentationKey}' - } - { - name: 'FUNCTIONS_WORKER_RUNTIME' - value: functionRuntime - } - { - name: 'FUNCTIONS_EXTENSION_VERSION' - value: functionVersion - } - ] - cors: { - allowedOrigins: [ - staticWebAppURL - ] - } - } - httpsOnly: true - } - identity: { - type: 'SystemAssigned' - } -}] diff --git a/bicep/modules/keyvault.bicep b/bicep/modules/keyvault.bicep index d696f32..6212668 100644 --- a/bicep/modules/keyvault.bicep +++ b/bicep/modules/keyvault.bicep @@ -1,31 +1,38 @@ +@description('The name of the Key Vault resource that will be deployed.') param keyVaultName string -param functionAppPrefix string -param functionApps array + +@description('Service principal Id used for deployment.') +param objectId string + +@description('The resource tags that will be applied to this Key Vault.') param resourceTags object -resource functions 'Microsoft.Web/sites@2021-01-15' existing = [for functionApp in functionApps :{ - name: '${functionAppPrefix}${functionApp}' -}] +@description('The location that this Key Vault will be deployed to.') +param location string resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { name: keyVaultName - location: resourceGroup().location + location: location properties: { sku: { name: 'standard' family: 'A' } - tenantId: subscription().tenantId - accessPolicies: [for i in range(0, length(functionApps)) : { - tenantId: functions[i].identity.tenantId - objectId: functions[i].identity.principalId - permissions: { - secrets: [ - 'get' - ] + accessPolicies: [ + { + tenantId: subscription().tenantId + objectId: objectId + permissions: { + secrets: [ + 'all' + ] + } } - }] + ] + enableSoftDelete: true + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + tenantId: subscription().tenantId } tags: resourceTags } - diff --git a/bicep/modules/keyvaultPolicies.bicep b/bicep/modules/keyvaultPolicies.bicep new file mode 100644 index 0000000..45b801c --- /dev/null +++ b/bicep/modules/keyvaultPolicies.bicep @@ -0,0 +1,25 @@ +@description('The name of the Key Vault resource that will be deployed.') +param keyVaultName string + +@description('The list of function app principal Id that will have access to this Key Vault.') +param functionAppPrincipalIds array + +resource keyVault 'Microsoft.KeyVault/vaults@2021-11-01-preview' existing = { + name: keyVaultName +} + +resource policies 'Microsoft.KeyVault/vaults/accessPolicies@2021-06-01-preview' = { + name: 'add' + parent: keyVault + properties: { + accessPolicies: [for i in range(0, length(functionAppPrincipalIds)) : { + tenantId: subscription().tenantId + objectId: functionAppPrincipalIds[i] + permissions: { + secrets: [ + 'get' + ] + } + }] + } +} diff --git a/bicep/modules/signalr.bicep b/bicep/modules/signalr.bicep index 2a4d358..cf347ef 100644 --- a/bicep/modules/signalr.bicep +++ b/bicep/modules/signalr.bicep @@ -1,7 +1,17 @@ +@description('The name of the SignalR service that will be deployed.') param signalRName string + +@description('The location that the SignalR service will be deployed to.') param location string + +@description('The resource tags that will be applied to the SignalR resource.') param resourceTags object +@description('Name of the Key Vault to store secrets in.') +param keyVaultName string + +var signalRConnectionStringSecretName = 'AzureSignalRConnectionString' + resource signalR 'Microsoft.SignalRService/SignalR@2018-10-01' = { name: signalRName location: location @@ -16,3 +26,15 @@ resource signalR 'Microsoft.SignalRService/SignalR@2018-10-01' = { hostNamePrefix: null } } + +resource keyVault 'Microsoft.KeyVault/vaults@2021-11-01-preview' existing = { + name: keyVaultName +} + +resource signalRConnectionString 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = { + name: signalRConnectionStringSecretName + parent: keyVault + properties: { + value: signalR.listKeys().primaryConnectionString + } +} diff --git a/bicep/modules/sqldb.bicep b/bicep/modules/sqldb.bicep index ba3bf29..9f06f57 100644 --- a/bicep/modules/sqldb.bicep +++ b/bicep/modules/sqldb.bicep @@ -1,11 +1,27 @@ +@description('The name of the SQL Server that will be deployed.') param sqlServerName string -param sqlDatabaeName string + +@description('The name of the database that will be deployed.') +param sqlDatabaseName string + +@description('The location that our server and database will be deployed to.') param location string + +@description('The admin username for the server.') param administratorLogin string + +@description('The password for the deployed server.') @secure() param administratorPassword string + +@description('The resource tags that will be applied to our SQL resources.') param resourceTags object +@description('Name of the Key Vault to store secrets in.') +param keyVaultName string + +var sqlDbConnectionStringSecretName = 'SqlConnectionString' + resource sqlServer 'Microsoft.Sql/servers@2021-05-01-preview' = { name: sqlServerName location: location @@ -18,9 +34,9 @@ resource sqlServer 'Microsoft.Sql/servers@2021-05-01-preview' = { dependsOn: [] } -resource servers_rideshare_server_name_databases_Rideshare_name 'Microsoft.Sql/servers/databases@2021-05-01-preview' = { +resource sqlDatabase 'Microsoft.Sql/servers/databases@2021-05-01-preview' = { parent: sqlServer - name: sqlDatabaeName + name: sqlDatabaseName location: location tags: resourceTags sku: { @@ -34,3 +50,15 @@ resource servers_rideshare_server_name_databases_Rideshare_name 'Microsoft.Sql/s zoneRedundant: false } } + +resource keyVault 'Microsoft.KeyVault/vaults@2021-11-01-preview' existing = { + name: keyVaultName +} + +resource sqlDbConnectionStringSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = { + name: sqlDbConnectionStringSecretName + parent: keyVault + properties: { + value: 'Server=tcp:${sqlServer.name}${environment().suffixes.sqlServerHostname},1433;Initial Catalog=db${sqlDatabase.name};Persist Security Info=False;User ID=${administratorLogin};Password=${administratorPassword};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;' + } +} diff --git a/bicep/modules/staticwebapp.bicep b/bicep/modules/staticwebapp.bicep index c28fade..4aa68e7 100644 --- a/bicep/modules/staticwebapp.bicep +++ b/bicep/modules/staticwebapp.bicep @@ -1,5 +1,10 @@ +@description('The name of the static web app that will be deployed.') param staticWebAppName string + +@description('The location that the static web app will be deployed to.') param location string + +@description('The resource tags that will be applied to the static web app.') param resourceTags object resource staticWebApp 'Microsoft.Web/staticSites@2021-02-01' = { diff --git a/bicep/modules/storageAccount.bicep b/bicep/modules/storageAccount.bicep new file mode 100644 index 0000000..6de77c6 --- /dev/null +++ b/bicep/modules/storageAccount.bicep @@ -0,0 +1,39 @@ +@description('The name of the storage account that will be deployed.') +param storageAccountName string + +@description('The location that the storage account will be deployed to. Default value is the location of the resource group.') +param location string = resourceGroup().location + +@description('The resource tags that will be applied to the storage account.') +param resourceTags object + +resource storageAccount 'Microsoft.Storage/storageAccounts@2019-06-01' = { + name: storageAccountName + location: location + tags: resourceTags + sku: { + name: 'Standard_LRS' + } + kind: 'StorageV2' + properties: { + supportsHttpsTrafficOnly: true + encryption: { + services: { + file: { + keyType: 'Account' + enabled: true + } + blob: { + keyType: 'Account' + enabled: true + } + } + keySource: 'Microsoft.Storage' + } + accessTier: 'Hot' + } +} + +output storageAccountName string = storageAccount.name +output storageAccountId string = storageAccount.id +output storageAccountApiVersion string = storageAccount.apiVersion diff --git a/bicep/parameters.json b/bicep/parameters.json index 73331c6..1204bff 100644 --- a/bicep/parameters.json +++ b/bicep/parameters.json @@ -3,7 +3,7 @@ "contentVersion": "1.0.0.0", "parameters": { "applicationName": { - "value": "RideshareWV" + "value": "" }, "resourceTags": { "value": { @@ -12,18 +12,18 @@ } }, "sqlAdminLogin": { - "value": "wviriya" + "value": "" }, "sqlAdminPassword": { "reference": { "keyVault": { - "id": "/subscriptions/10fe34c7-c442-46d8-b43f-2c92651e6545/resourceGroups/common-rg/providers/Microsoft.KeyVault/vaults/wviriya-kv" + "id": "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" }, "secretName": "sqlAdminPassword" } }, "staticWebAppLocation": { - "value": "westus2" + "value": "" } } } \ No newline at end of file