From 3a81d639af6679a6110e91d96e1c78bf990145a6 Mon Sep 17 00:00:00 2001 From: Daniel Larsen Date: Tue, 11 Jan 2022 17:46:55 +1300 Subject: [PATCH 1/6] not done yet! --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From e8ca479fd8c04a6fe1aff79ec8ca05db9c26b548 Mon Sep 17 00:00:00 2001 From: Will Velida Date: Mon, 14 Feb 2022 14:49:59 +1300 Subject: [PATCH 2/6] Adding Cosmos Settings to Key Vault --- bicep/main.bicep | 1 + bicep/modules/cosmosdb.bicep | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/bicep/main.bicep b/bicep/main.bicep index d62d9fb..38bcb94 100644 --- a/bicep/main.bicep +++ b/bicep/main.bicep @@ -43,6 +43,7 @@ module cosmos 'modules/cosmosdb.bicep' = { location: location databaseName: applicationName resourceTags: resourceTags + keyVaultName: keyVaultName } } diff --git a/bicep/modules/cosmosdb.bicep b/bicep/modules/cosmosdb.bicep index 7a75665..97ff52a 100644 --- a/bicep/modules/cosmosdb.bicep +++ b/bicep/modules/cosmosdb.bicep @@ -9,6 +9,9 @@ param location string = resourceGroup().location param databaseName string param resourceTags object +@description('Name of the Key Vault to store secrets in.') +param keyVaultName string + param throughput int = 400 var containerNames = [ @@ -16,6 +19,9 @@ var containerNames = [ 'archiver' ] +var cosmosDbConnectionStringSecretName = 'CosmosDbConnectionString' +var cosmosDbPrimaryKeySecretName = 'CosmosDbPrimaryKey' + resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2021-06-15' = { name: toLower(accountName) kind: 'GlobalDocumentDB' @@ -72,4 +78,24 @@ 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 + } +} + output cosmosDBAccountName string = cosmosAccount.name From bd7a3c70b2e915a2eda5fdeb49959978129072b7 Mon Sep 17 00:00:00 2001 From: Will Velida Date: Mon, 28 Mar 2022 15:48:54 +1300 Subject: [PATCH 3/6] Adding app settings to Function and Static Web App --- bicep/main.bicep | 481 ++++++++++++++- bicep/main.json | 906 ++++++++++++++++++++++------- bicep/modules/apim.bicep | 4 +- bicep/modules/appServicePlan.bicep | 15 + bicep/modules/cosmosdb.bicep | 18 +- bicep/modules/eventgrid.bicep | 21 + bicep/modules/functions.bicep | 95 --- bicep/modules/keyvault.bicep | 7 +- bicep/modules/signalr.bicep | 17 + bicep/modules/sqldb.bicep | 23 +- bicep/modules/storageAccount.bicep | 34 ++ bicep/parameters.json | 12 +- 12 files changed, 1312 insertions(+), 321 deletions(-) create mode 100644 bicep/modules/appServicePlan.bicep delete mode 100644 bicep/modules/functions.bicep create mode 100644 bicep/modules/storageAccount.bicep diff --git a/bicep/main.bicep b/bicep/main.bicep index 38bcb94..4bc6a44 100644 --- a/bicep/main.bicep +++ b/bicep/main.bicep @@ -17,7 +17,8 @@ param resourceTags object = { Purpose: 'Sample' } -var location = resourceGroup().location +param location string = resourceGroup().location + var functionAppServicePlanName = '${applicationName}Plan' var keyVaultName = '${applicationName}KeyVault' var cosmosdbName = '${applicationName}Cosmos' @@ -35,6 +36,8 @@ var functionsApps = [ 'TripArchiver' 'Orchestrators' ] +var functionRuntime = 'dotnet' +var functionVersion = '~4' module cosmos 'modules/cosmosdb.bicep' = { name: cosmosdbName @@ -51,11 +54,12 @@ module sqlDb 'modules/sqldb.bicep' = { name: 'sqldb' params: { sqlServerName: sqlServerName - sqlDatabaeName: applicationName + sqlDatabaseName: applicationName administratorLogin: sqlAdminLogin administratorPassword: sqlAdminPassword location: location resourceTags: resourceTags + keyVaultName: keyVaultName } } @@ -65,6 +69,7 @@ module eventGrid 'modules/eventgrid.bicep' = { eventGridTopicName: eventGridName location: location resourceTags: resourceTags + keyVaultName: keyVaultName } } @@ -74,6 +79,7 @@ module signalR 'modules/signalr.bicep' = { signalRName: signalRName location: location resourceTags: resourceTags + keyVaultName: keyVaultName } } @@ -90,13 +96,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 @@ -105,17 +112,462 @@ 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 + } +} + +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:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.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:://${keyVaultName}.vault.azure.net/secrets/AuthorityUrl)' + } + { + name: 'ApiApplicationId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiApplicationId)' + } + { + name: 'ApiScopeName' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiScopeName)' + } + { + name: 'EnableAuth' + value: 'true' + } + { + name: 'SqlConnectionString' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/SqlConnectionString)' + } + { + name: 'AzureSignalRConnectionString' + value:'@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.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:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.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:://${keyVaultName}.vault.azure.net/secrets/AuthorityUrl)' + } + { + name: 'ApiApplicationId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiApplicationId)' + } + { + name: 'ApiScopeName' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.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:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.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:://${keyVaultName}.vault.azure.net/secrets/AuthorityUrl)' + } + { + name: 'ApiApplicationId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiApplicationId)' + } + { + name: 'ApiScopeName' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiScopeName)' + } + { + name: 'EnableAuth' + value: 'true' + } + { + name: 'GraphTenantId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/GraphTenantId)' + } + { + name: 'GraphClientId' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/GraphClientId)' + } + { + name: 'GraphClientSecret' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/GraphClientSecret)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + } +} + +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:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + } + { + name: 'DocDbEndpointUri' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.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:://${keyVaultName}.vault.azure.net/secrets/TripExternalizationsEventGridTopicApiKey)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } + } +} + +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:://${keyVaultName}.vault.azure.net/secrets/CosmosDbConnectionString)' + } + ] + cors: { + allowedOrigins: [ + staticWebApp.outputs.staticWebAppURL + ] + } + } } } @@ -126,9 +578,14 @@ module keyVault 'modules/keyvault.bicep' = { functionAppPrefix: applicationName functionApps: functionsApps resourceTags: resourceTags + location: location } dependsOn: [ - functions + tripFunctionApp + driverFunctionApp + passengerFunctionApp + tripArchiverFunctionApp + orchestratorsFunctionApp ] } 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..d6cf742 100644 --- a/bicep/modules/apim.bicep +++ b/bicep/modules/apim.bicep @@ -18,7 +18,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/appServicePlan.bicep b/bicep/modules/appServicePlan.bicep new file mode 100644 index 0000000..8090619 --- /dev/null +++ b/bicep/modules/appServicePlan.bicep @@ -0,0 +1,15 @@ +param appServicePlanName string +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/cosmosdb.bicep b/bicep/modules/cosmosdb.bicep index 97ff52a..437242f 100644 --- a/bicep/modules/cosmosdb.bicep +++ b/bicep/modules/cosmosdb.bicep @@ -21,6 +21,7 @@ var containerNames = [ var cosmosDbConnectionStringSecretName = 'CosmosDbConnectionString' var cosmosDbPrimaryKeySecretName = 'CosmosDbPrimaryKey' +var cosmosDbEndpointSecretName = 'CosmosDbEndpoint' resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2021-06-15' = { name: toLower(accountName) @@ -62,13 +63,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' @@ -98,4 +99,15 @@ resource cosmosConnectionSecret 'Microsoft.KeyVault/vaults/secrets@2021-11-01-pr } } +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..a6d3e7d 100644 --- a/bicep/modules/eventgrid.bicep +++ b/bicep/modules/eventgrid.bicep @@ -1,7 +1,16 @@ +@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 + 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 +21,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..5632950 100644 --- a/bicep/modules/keyvault.bicep +++ b/bicep/modules/keyvault.bicep @@ -2,6 +2,7 @@ param keyVaultName string param functionAppPrefix string param functionApps array param resourceTags object +param location string resource functions 'Microsoft.Web/sites@2021-01-15' existing = [for functionApp in functionApps :{ name: '${functionAppPrefix}${functionApp}' @@ -9,12 +10,15 @@ resource functions 'Microsoft.Web/sites@2021-01-15' existing = [for functionApp resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { name: keyVaultName - location: resourceGroup().location + location: location properties: { sku: { name: 'standard' family: 'A' } + enableSoftDelete: true + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true tenantId: subscription().tenantId accessPolicies: [for i in range(0, length(functionApps)) : { tenantId: functions[i].identity.tenantId @@ -28,4 +32,3 @@ resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { } tags: resourceTags } - diff --git a/bicep/modules/signalr.bicep b/bicep/modules/signalr.bicep index 2a4d358..2904107 100644 --- a/bicep/modules/signalr.bicep +++ b/bicep/modules/signalr.bicep @@ -2,6 +2,11 @@ param signalRName string param location string 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 +21,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..c269cde 100644 --- a/bicep/modules/sqldb.bicep +++ b/bicep/modules/sqldb.bicep @@ -1,11 +1,16 @@ param sqlServerName string -param sqlDatabaeName string +param sqlDatabaseName string param location string param administratorLogin string @secure() param administratorPassword string 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 +23,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 +39,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/storageAccount.bicep b/bicep/modules/storageAccount.bicep new file mode 100644 index 0000000..bd90a1f --- /dev/null +++ b/bicep/modules/storageAccount.bicep @@ -0,0 +1,34 @@ +param storageAccountName string +param location string = resourceGroup().location +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..16db01d 100644 --- a/bicep/parameters.json +++ b/bicep/parameters.json @@ -3,7 +3,7 @@ "contentVersion": "1.0.0.0", "parameters": { "applicationName": { - "value": "RideshareWV" + "value": "velidarideshare" }, "resourceTags": { "value": { @@ -12,15 +12,7 @@ } }, "sqlAdminLogin": { - "value": "wviriya" - }, - "sqlAdminPassword": { - "reference": { - "keyVault": { - "id": "/subscriptions/10fe34c7-c442-46d8-b43f-2c92651e6545/resourceGroups/common-rg/providers/Microsoft.KeyVault/vaults/wviriya-kv" - }, - "secretName": "sqlAdminPassword" - } + "value": "wvelida" }, "staticWebAppLocation": { "value": "westus2" From 66867736e2d35428909e8b772233b7583612a1fb Mon Sep 17 00:00:00 2001 From: Will Velida Date: Fri, 27 May 2022 13:54:47 +1200 Subject: [PATCH 4/6] Tidying Bicep files and parameter files --- bicep/main.bicep | 7 +++++++ bicep/modules/apim.bicep | 6 ++++++ bicep/modules/apimAPI.bicep | 9 +++++++++ bicep/modules/appServicePlan.bicep | 3 +++ bicep/modules/applicationInsights.bicep | 5 +++++ bicep/modules/cosmosdb.bicep | 4 +++- bicep/modules/eventgrid.bicep | 1 + bicep/modules/keyvault.bicep | 9 +++++++++ bicep/modules/signalr.bicep | 5 +++++ bicep/modules/sqldb.bicep | 11 +++++++++++ bicep/modules/staticwebapp.bicep | 5 +++++ bicep/modules/storageAccount.bicep | 5 +++++ bicep/parameters.json | 13 ++++++++++--- 13 files changed, 79 insertions(+), 4 deletions(-) diff --git a/bicep/main.bicep b/bicep/main.bicep index 4bc6a44..df218de 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,11 +8,17 @@ 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('The resource tags that will be applied to the deployed resources.') param resourceTags object = { ProjectType: 'Azure Serverless Microservices' Purpose: 'Sample' diff --git a/bicep/modules/apim.bicep b/bicep/modules/apim.bicep index d6cf742..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([ 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 index 8090619..6dff5a2 100644 --- a/bicep/modules/appServicePlan.bicep +++ b/bicep/modules/appServicePlan.bicep @@ -1,4 +1,7 @@ +@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' = { 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 437242f..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,11 +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 = [ diff --git a/bicep/modules/eventgrid.bicep b/bicep/modules/eventgrid.bicep index a6d3e7d..1fb5289 100644 --- a/bicep/modules/eventgrid.bicep +++ b/bicep/modules/eventgrid.bicep @@ -4,6 +4,7 @@ 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.') diff --git a/bicep/modules/keyvault.bicep b/bicep/modules/keyvault.bicep index 5632950..394ab81 100644 --- a/bicep/modules/keyvault.bicep +++ b/bicep/modules/keyvault.bicep @@ -1,7 +1,16 @@ +@description('The name of the Key Vault resource that will be deployed.') param keyVaultName string + +@description('The prefix for the function apps.') param functionAppPrefix string + +@description('The list of function apps that will have access to this Key Vault.') param functionApps array + +@description('The resource tags that will be applied to this Key Vault.') param resourceTags object + +@description('The location that this Key Vault will be deployed to.') param location string resource functions 'Microsoft.Web/sites@2021-01-15' existing = [for functionApp in functionApps :{ diff --git a/bicep/modules/signalr.bicep b/bicep/modules/signalr.bicep index 2904107..cf347ef 100644 --- a/bicep/modules/signalr.bicep +++ b/bicep/modules/signalr.bicep @@ -1,5 +1,10 @@ +@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.') diff --git a/bicep/modules/sqldb.bicep b/bicep/modules/sqldb.bicep index c269cde..9f06f57 100644 --- a/bicep/modules/sqldb.bicep +++ b/bicep/modules/sqldb.bicep @@ -1,9 +1,20 @@ +@description('The name of the SQL Server that will be deployed.') param sqlServerName 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.') 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 index bd90a1f..6de77c6 100644 --- a/bicep/modules/storageAccount.bicep +++ b/bicep/modules/storageAccount.bicep @@ -1,5 +1,10 @@ +@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' = { diff --git a/bicep/parameters.json b/bicep/parameters.json index 16db01d..c14e1a5 100644 --- a/bicep/parameters.json +++ b/bicep/parameters.json @@ -3,7 +3,7 @@ "contentVersion": "1.0.0.0", "parameters": { "applicationName": { - "value": "velidarideshare" + "value": "" }, "resourceTags": { "value": { @@ -12,10 +12,17 @@ } }, "sqlAdminLogin": { - "value": "wvelida" + "value": "" }, + "sqlAdminPassword": { + "reference": { + "keyVault": { + "id": "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" + }, + "secretName": "sqlAdminPassword" + }, "staticWebAppLocation": { - "value": "westus2" + "value": "" } } } \ No newline at end of file From e1fa1182ee7a7101263e9c47dd44667bad00a0c2 Mon Sep 17 00:00:00 2001 From: Will Velida Date: Fri, 27 May 2022 14:11:07 +1200 Subject: [PATCH 5/6] Fixing parameter file --- bicep/parameters.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bicep/parameters.json b/bicep/parameters.json index c14e1a5..1204bff 100644 --- a/bicep/parameters.json +++ b/bicep/parameters.json @@ -20,7 +20,8 @@ "id": "/subscriptions//resourceGroups//providers/Microsoft.KeyVault/vaults/" }, "secretName": "sqlAdminPassword" - }, + } + }, "staticWebAppLocation": { "value": "" } From f4a3308acd0c8958bbca5af17a9e8029e81ef2de Mon Sep 17 00:00:00 2001 From: Victor Viriya-ampanond <15903177+wviriya@users.noreply.github.com> Date: Tue, 14 Jun 2022 10:10:17 +1200 Subject: [PATCH 6/6] Fix Key Vault dependency issue, split create and update Key Vault into two modules --- bicep/main.bicep | 108 +++++++++++++++------------ bicep/modules/keyvault.bicep | 31 ++++---- bicep/modules/keyvaultPolicies.bicep | 25 +++++++ 3 files changed, 98 insertions(+), 66 deletions(-) create mode 100644 bicep/modules/keyvaultPolicies.bicep diff --git a/bicep/main.bicep b/bicep/main.bicep index df218de..d2c0841 100644 --- a/bicep/main.bicep +++ b/bicep/main.bicep @@ -18,6 +18,9 @@ param sqlAdminLogin string @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' @@ -36,16 +39,19 @@ 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 params: { @@ -53,7 +59,7 @@ module cosmos 'modules/cosmosdb.bicep' = { location: location databaseName: applicationName resourceTags: resourceTags - keyVaultName: keyVaultName + keyVaultName: keyVault.name } } @@ -66,7 +72,7 @@ module sqlDb 'modules/sqldb.bicep' = { administratorPassword: sqlAdminPassword location: location resourceTags: resourceTags - keyVaultName: keyVaultName + keyVaultName: keyVault.name } } @@ -76,7 +82,7 @@ module eventGrid 'modules/eventgrid.bicep' = { eventGridTopicName: eventGridName location: location resourceTags: resourceTags - keyVaultName: keyVaultName + keyVaultName: keyVault.name } } @@ -86,7 +92,7 @@ module signalR 'modules/signalr.bicep' = { signalRName: signalRName location: location resourceTags: resourceTags - keyVaultName: keyVaultName + keyVaultName: keyVault.name } } @@ -187,11 +193,11 @@ resource tripFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'DocDbApiKey' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' } { name: 'DocDbEndpointUri' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbEndpoint)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' } { name: 'DocDbRideShareDatabaseName' @@ -227,15 +233,15 @@ resource tripFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'AuthorityUrl' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/AuthorityUrl)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AuthorityUrl)' } { name: 'ApiApplicationId' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiApplicationId)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiApplicationId)' } { name: 'ApiScopeName' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiScopeName)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiScopeName)' } { name: 'EnableAuth' @@ -243,11 +249,11 @@ resource tripFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'SqlConnectionString' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/SqlConnectionString)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/SqlConnectionString)' } { name: 'AzureSignalRConnectionString' - value:'@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/AzureSignalRConnectionString)' + value:'@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AzureSignalRConnectionString)' } ] cors: { @@ -297,11 +303,11 @@ resource driverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'DocDbApiKey' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' } { name: 'DocDbEndpointUri' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbEndpoint)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' } { name: 'DocDbRideShareDatabaseName' @@ -321,15 +327,15 @@ resource driverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'AuthorityUrl' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/AuthorityUrl)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AuthorityUrl)' } { name: 'ApiApplicationId' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiApplicationId)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiApplicationId)' } { name: 'ApiScopeName' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiScopeName)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiScopeName)' } { name: 'EnableAuth' @@ -383,11 +389,11 @@ resource passengerFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'DocDbApiKey' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' } { name: 'DocDbEndpointUri' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbEndpoint)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' } { name: 'DocDbRideShareDatabaseName' @@ -407,15 +413,15 @@ resource passengerFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'AuthorityUrl' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/AuthorityUrl)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/AuthorityUrl)' } { name: 'ApiApplicationId' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiApplicationId)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiApplicationId)' } { name: 'ApiScopeName' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/ApiScopeName)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/ApiScopeName)' } { name: 'EnableAuth' @@ -423,15 +429,15 @@ resource passengerFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'GraphTenantId' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/GraphTenantId)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/GraphTenantId)' } { name: 'GraphClientId' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/GraphClientId)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/GraphClientId)' } { name: 'GraphClientSecret' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/GraphClientSecret)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/GraphClientSecret)' } ] cors: { @@ -441,6 +447,9 @@ resource passengerFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } } } + identity: { + type: 'SystemAssigned' + } } resource orchestratorsFunctionApp 'Microsoft.Web/sites@2021-03-01' = { @@ -477,11 +486,11 @@ resource orchestratorsFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'DocDbApiKey' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbPrimaryKey)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbPrimaryKey)' } { name: 'DocDbEndpointUri' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbEndpoint)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbEndpoint)' } { name: 'DocDbRideShareDatabaseName' @@ -541,7 +550,7 @@ resource orchestratorsFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'TripExternalizationsEventGridTopicApiKey' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/TripExternalizationsEventGridTopicApiKey)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/TripExternalizationsEventGridTopicApiKey)' } ] cors: { @@ -551,6 +560,9 @@ resource orchestratorsFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } } } + identity: { + type: 'SystemAssigned' + } } resource tripArchiverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { @@ -566,7 +578,7 @@ resource tripArchiverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } { name: 'DocDbConnectionString' - value: '@Microsoft.KeyVault(SecretUri=https:://${keyVaultName}.vault.azure.net/secrets/CosmosDbConnectionString)' + value: '@Microsoft.KeyVault(SecretUri=https:://${keyVault.name}.vault.azure.net/secrets/CosmosDbConnectionString)' } ] cors: { @@ -576,23 +588,23 @@ resource tripArchiverFunctionApp 'Microsoft.Web/sites@2021-03-01' = { } } } + identity: { + type: 'SystemAssigned' + } } -module keyVault 'modules/keyvault.bicep' = { - name: keyVaultName +module keyVaultPolicies 'modules/keyvaultPolicies.bicep' = { + name: '${keyVaultName}polices' params: { keyVaultName: keyVaultName - functionAppPrefix: applicationName - functionApps: functionsApps - resourceTags: resourceTags - location: location + functionAppPrincipalIds: [ + tripFunctionApp.identity.principalId + driverFunctionApp.identity.principalId + passengerFunctionApp.identity.principalId + tripArchiverFunctionApp.identity.principalId + orchestratorsFunctionApp.identity.principalId + ] } - dependsOn: [ - tripFunctionApp - driverFunctionApp - passengerFunctionApp - tripArchiverFunctionApp - orchestratorsFunctionApp - ] } +output principalId string = orchestratorsFunctionApp.identity.principalId diff --git a/bicep/modules/keyvault.bicep b/bicep/modules/keyvault.bicep index 394ab81..6212668 100644 --- a/bicep/modules/keyvault.bicep +++ b/bicep/modules/keyvault.bicep @@ -1,11 +1,8 @@ @description('The name of the Key Vault resource that will be deployed.') param keyVaultName string -@description('The prefix for the function apps.') -param functionAppPrefix string - -@description('The list of function apps that will have access to this Key Vault.') -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 @@ -13,10 +10,6 @@ param resourceTags object @description('The location that this Key Vault will be deployed to.') param location string -resource functions 'Microsoft.Web/sites@2021-01-15' existing = [for functionApp in functionApps :{ - name: '${functionAppPrefix}${functionApp}' -}] - resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { name: keyVaultName location: location @@ -25,19 +18,21 @@ resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = { name: 'standard' family: 'A' } + accessPolicies: [ + { + tenantId: subscription().tenantId + objectId: objectId + permissions: { + secrets: [ + 'all' + ] + } + } + ] enableSoftDelete: true softDeleteRetentionInDays: 7 enabledForTemplateDeployment: true tenantId: subscription().tenantId - accessPolicies: [for i in range(0, length(functionApps)) : { - tenantId: functions[i].identity.tenantId - objectId: functions[i].identity.principalId - permissions: { - secrets: [ - 'get' - ] - } - }] } 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' + ] + } + }] + } +}