From 27b2a4b8bac318908122faf9fc756922e68bae86 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 21 Mar 2023 19:41:22 +0000 Subject: [PATCH 01/24] Security workflow --- .github/workflows/azure-bicep-validate.yaml | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/azure-bicep-validate.yaml diff --git a/.github/workflows/azure-bicep-validate.yaml b/.github/workflows/azure-bicep-validate.yaml new file mode 100644 index 0000000..78446c7 --- /dev/null +++ b/.github/workflows/azure-bicep-validate.yaml @@ -0,0 +1,36 @@ +name: Validate bicep scripts +on: + workflow_dispatch: + push: + branches: + - main + - master + pull_request: + branches: + - main + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Azure CLI script + uses: azure/CLI@v1 + with: + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f infra/main.bicep + + - name: Run Microsoft Security DevOps Analysis + uses: microsoft/security-devops-action@preview + env: + GDN_TEMPLATEANALYZER_VERBOSE: 1 + id: msdo + with: + tools: templateanalyzer + + - name: Upload alerts to Security tab + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: ${{ steps.msdo.outputs.sarifFile }} \ No newline at end of file From 2d6dfec828be83c3135b78d67303c6f3fe1f7307 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 21 Mar 2023 19:46:23 +0000 Subject: [PATCH 02/24] Remove unused files and add json --- .../core/database/cosmos/cosmos-account.bicep | 48 - .../cosmos/mongo/cosmos-mongo-account.bicep | 22 - .../cosmos/mongo/cosmos-mongo-db.bicep | 46 - .../cosmos/sql/cosmos-sql-account.bicep | 21 - .../database/cosmos/sql/cosmos-sql-db.bicep | 73 - .../cosmos/sql/cosmos-sql-role-assign.bicep | 18 - .../cosmos/sql/cosmos-sql-role-def.bicep | 29 - infra/core/database/sqlserver/sqlserver.bicep | 129 -- infra/core/gateway/apim-api-policy.xml | 92 -- infra/core/gateway/apim.bicep | 61 - infra/core/host/container-app.bicep | 77 - .../host/container-apps-environment.bicep | 26 - infra/core/host/container-apps.bicep | 30 - infra/core/host/container-registry.bicep | 36 - infra/core/host/functions.bicep | 82 -- infra/core/host/staticwebapp.bicep | 21 - .../applicationinsights-dashboard.bicep | 1235 ----------------- infra/core/monitor/applicationinsights.bicep | 30 - infra/core/monitor/monitoring.bicep | 31 - infra/core/security/keyvault-access.bicep | 21 - infra/core/security/keyvault-secret.bicep | 30 - infra/core/security/keyvault.bicep | 25 - infra/core/storage/storage-account.bicep | 38 - infra/main.json | 461 ++++++ 24 files changed, 461 insertions(+), 2221 deletions(-) delete mode 100644 infra/core/database/cosmos/cosmos-account.bicep delete mode 100644 infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep delete mode 100644 infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep delete mode 100644 infra/core/database/cosmos/sql/cosmos-sql-account.bicep delete mode 100644 infra/core/database/cosmos/sql/cosmos-sql-db.bicep delete mode 100644 infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep delete mode 100644 infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep delete mode 100644 infra/core/database/sqlserver/sqlserver.bicep delete mode 100644 infra/core/gateway/apim-api-policy.xml delete mode 100644 infra/core/gateway/apim.bicep delete mode 100644 infra/core/host/container-app.bicep delete mode 100644 infra/core/host/container-apps-environment.bicep delete mode 100644 infra/core/host/container-apps.bicep delete mode 100644 infra/core/host/container-registry.bicep delete mode 100644 infra/core/host/functions.bicep delete mode 100644 infra/core/host/staticwebapp.bicep delete mode 100644 infra/core/monitor/applicationinsights-dashboard.bicep delete mode 100644 infra/core/monitor/applicationinsights.bicep delete mode 100644 infra/core/monitor/monitoring.bicep delete mode 100644 infra/core/security/keyvault-access.bicep delete mode 100644 infra/core/security/keyvault-secret.bicep delete mode 100644 infra/core/security/keyvault.bicep delete mode 100644 infra/core/storage/storage-account.bicep create mode 100644 infra/main.json diff --git a/infra/core/database/cosmos/cosmos-account.bicep b/infra/core/database/cosmos/cosmos-account.bicep deleted file mode 100644 index 6bc1f2e..0000000 --- a/infra/core/database/cosmos/cosmos-account.bicep +++ /dev/null @@ -1,48 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' -param keyVaultName string - -@allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ]) -param kind string - -resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = { - name: name - kind: kind - location: location - tags: tags - properties: { - consistencyPolicy: { defaultConsistencyLevel: 'Session' } - locations: [ - { - locationName: location - failoverPriority: 0 - isZoneRedundant: false - } - ] - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false - enableMultipleWriteLocations: false - apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.0' } : {} - capabilities: [ { name: 'EnableServerless' } ] - } -} - -resource cosmosConnectionString 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: connectionStringKey - properties: { - value: cosmos.listConnectionStrings().connectionStrings[0].connectionString - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} - -output connectionStringKey string = connectionStringKey -output endpoint string = cosmos.properties.documentEndpoint -output id string = cosmos.id -output name string = cosmos.name diff --git a/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep b/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep deleted file mode 100644 index bd2a2b5..0000000 --- a/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep +++ /dev/null @@ -1,22 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param keyVaultName string -param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' - -module cosmos '../../cosmos/cosmos-account.bicep' = { - name: 'cosmos-account' - params: { - name: name - location: location - connectionStringKey: connectionStringKey - keyVaultName: keyVaultName - kind: 'MongoDB' - tags: tags - } -} - -output connectionStringKey string = cosmos.outputs.connectionStringKey -output endpoint string = cosmos.outputs.endpoint -output id string = cosmos.outputs.id diff --git a/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep b/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep deleted file mode 100644 index 2c9688e..0000000 --- a/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep +++ /dev/null @@ -1,46 +0,0 @@ -param accountName string -param databaseName string -param location string = resourceGroup().location -param tags object = {} - -param collections array = [] -param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' -param keyVaultName string - -module cosmos 'cosmos-mongo-account.bicep' = { - name: 'cosmos-mongo-account' - params: { - name: accountName - location: location - keyVaultName: keyVaultName - tags: tags - connectionStringKey: connectionStringKey - } -} - -resource database 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2022-08-15' = { - name: '${accountName}/${databaseName}' - tags: tags - properties: { - resource: { id: databaseName } - } - - resource list 'collections' = [for collection in collections: { - name: collection.name - properties: { - resource: { - id: collection.id - shardKey: { _id: collection.shardKey } - indexes: [ { key: { keys: [ collection.indexKey ] } } ] - } - } - }] - - dependsOn: [ - cosmos - ] -} - -output connectionStringKey string = connectionStringKey -output databaseName string = databaseName -output endpoint string = cosmos.outputs.endpoint diff --git a/infra/core/database/cosmos/sql/cosmos-sql-account.bicep b/infra/core/database/cosmos/sql/cosmos-sql-account.bicep deleted file mode 100644 index e8b030f..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-account.bicep +++ /dev/null @@ -1,21 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param keyVaultName string - -module cosmos '../../cosmos/cosmos-account.bicep' = { - name: 'cosmos-account' - params: { - name: name - location: location - tags: tags - keyVaultName: keyVaultName - kind: 'GlobalDocumentDB' - } -} - -output connectionStringKey string = cosmos.outputs.connectionStringKey -output endpoint string = cosmos.outputs.endpoint -output id string = cosmos.outputs.id -output name string = cosmos.outputs.name diff --git a/infra/core/database/cosmos/sql/cosmos-sql-db.bicep b/infra/core/database/cosmos/sql/cosmos-sql-db.bicep deleted file mode 100644 index 5a4de20..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-db.bicep +++ /dev/null @@ -1,73 +0,0 @@ -param accountName string -param databaseName string -param location string = resourceGroup().location -param tags object = {} - -param containers array = [] -param keyVaultName string -param principalIds array = [] - -module cosmos 'cosmos-sql-account.bicep' = { - name: 'cosmos-sql-account' - params: { - name: accountName - location: location - tags: tags - keyVaultName: keyVaultName - } -} - -resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = { - name: '${accountName}/${databaseName}' - properties: { - resource: { id: databaseName } - } - - resource list 'containers' = [for container in containers: { - name: container.name - properties: { - resource: { - id: container.id - partitionKey: { paths: [ container.partitionKey ] } - } - options: {} - } - }] - - dependsOn: [ - cosmos - ] -} - -module roleDefintion 'cosmos-sql-role-def.bicep' = { - name: 'cosmos-sql-role-definition' - params: { - accountName: accountName - } - dependsOn: [ - cosmos - database - ] -} - -// We need batchSize(1) here because sql role assignments have to be done sequentially -@batchSize(1) -module userRole 'cosmos-sql-role-assign.bicep' = [for principalId in principalIds: if (!empty(principalId)) { - name: 'cosmos-sql-user-role-${uniqueString(principalId)}' - params: { - accountName: accountName - roleDefinitionId: roleDefintion.outputs.id - principalId: principalId - } - dependsOn: [ - cosmos - database - ] -}] - -output accountId string = cosmos.outputs.id -output accountName string = cosmos.outputs.name -output connectionStringKey string = cosmos.outputs.connectionStringKey -output databaseName string = databaseName -output endpoint string = cosmos.outputs.endpoint -output roleDefinitionId string = roleDefintion.outputs.id diff --git a/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep b/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep deleted file mode 100644 index 6855edf..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep +++ /dev/null @@ -1,18 +0,0 @@ -param accountName string - -param roleDefinitionId string -param principalId string = '' - -resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = { - parent: cosmos - name: guid(roleDefinitionId, principalId, cosmos.id) - properties: { - principalId: principalId - roleDefinitionId: roleDefinitionId - scope: cosmos.id - } -} - -resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { - name: accountName -} diff --git a/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep b/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep deleted file mode 100644 index cfb4033..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep +++ /dev/null @@ -1,29 +0,0 @@ -param accountName string - -resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = { - parent: cosmos - name: guid(cosmos.id, accountName, 'sql-role') - properties: { - assignableScopes: [ - cosmos.id - ] - permissions: [ - { - dataActions: [ - 'Microsoft.DocumentDB/databaseAccounts/readMetadata' - 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' - 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' - ] - notDataActions: [] - } - ] - roleName: 'Reader Writer' - type: 'CustomRole' - } -} - -resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { - name: accountName -} - -output id string = roleDefinition.id diff --git a/infra/core/database/sqlserver/sqlserver.bicep b/infra/core/database/sqlserver/sqlserver.bicep deleted file mode 100644 index 821a908..0000000 --- a/infra/core/database/sqlserver/sqlserver.bicep +++ /dev/null @@ -1,129 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param appUser string = 'appUser' -param databaseName string -param keyVaultName string -param sqlAdmin string = 'sqlAdmin' -param connectionStringKey string = 'AZURE-SQL-CONNECTION-STRING' - -@secure() -param sqlAdminPassword string -@secure() -param appUserPassword string - -resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = { - name: name - location: location - tags: tags - properties: { - version: '12.0' - minimalTlsVersion: '1.2' - publicNetworkAccess: 'Enabled' - administratorLogin: sqlAdmin - administratorLoginPassword: sqlAdminPassword - } - - resource database 'databases' = { - name: databaseName - location: location - } - - resource firewall 'firewallRules' = { - name: 'Azure Services' - properties: { - // Allow all clients - // Note: range [0.0.0.0-0.0.0.0] means "allow all Azure-hosted clients only". - // This is not sufficient, because we also want to allow direct access from developer machine, for debugging purposes. - startIpAddress: '0.0.0.1' - endIpAddress: '255.255.255.254' - } - } -} - -resource sqlDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { - name: '${name}-deployment-script' - location: location - kind: 'AzureCLI' - properties: { - azCliVersion: '2.37.0' - retentionInterval: 'PT1H' // Retain the script resource for 1 hour after it ends running - timeout: 'PT5M' // Five minutes - cleanupPreference: 'OnSuccess' - environmentVariables: [ - { - name: 'APPUSERNAME' - value: appUser - } - { - name: 'APPUSERPASSWORD' - secureValue: appUserPassword - } - { - name: 'DBNAME' - value: databaseName - } - { - name: 'DBSERVER' - value: sqlServer.properties.fullyQualifiedDomainName - } - { - name: 'SQLCMDPASSWORD' - secureValue: sqlAdminPassword - } - { - name: 'SQLADMIN' - value: sqlAdmin - } - ] - - scriptContent: ''' -wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 -tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . - -cat < ./initDb.sql -drop user ${APPUSERNAME} -go -create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' -go -alter role db_owner add member ${APPUSERNAME} -go -SCRIPT_END - -./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql - ''' - } -} - -resource sqlAdminPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: 'sqlAdminPassword' - properties: { - value: sqlAdminPassword - } -} - -resource appUserPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: 'appUserPassword' - properties: { - value: appUserPassword - } -} - -resource sqlAzureConnectionStringSercret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: connectionStringKey - properties: { - value: '${connectionString}; Password=${appUserPassword}' - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} - -var connectionString = 'Server=${sqlServer.properties.fullyQualifiedDomainName}; Database=${sqlServer::database.name}; User=${appUser}' -output connectionStringKey string = connectionStringKey -output databaseName string = sqlServer::database.name diff --git a/infra/core/gateway/apim-api-policy.xml b/infra/core/gateway/apim-api-policy.xml deleted file mode 100644 index 2a6d811..0000000 --- a/infra/core/gateway/apim-api-policy.xml +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - {0} - - - PUT - GET - POST - DELETE - PATCH - - -
*
-
- -
*
-
-
- - - - - - - Call to the @(context.Api.Name) - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Failed to process the @(context.Api.Name) - - - - - - - - - - - - - - - - - - We're Sorry. An unexpected error has occurred. If this continues please contact Tech Support. - - -
\ No newline at end of file diff --git a/infra/core/gateway/apim.bicep b/infra/core/gateway/apim.bicep deleted file mode 100644 index 76c5ae7..0000000 --- a/infra/core/gateway/apim.bicep +++ /dev/null @@ -1,61 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('The email address of the owner of the service') -@minLength(1) -param publisherEmail string = 'noreply@microsoft.com' - -@description('The name of the owner of the service') -@minLength(1) -param publisherName string = 'n/a' - -@description('The pricing tier of this API Management service') -@allowed([ - 'Consumption' - 'Developer' - 'Standard' - 'Premium' -]) -param sku string = 'Consumption' - -@description('The instance size of this API Management service.') -@allowed([ 0, 1, 2 ]) -param skuCount int = 0 - -@description('Azure Application Insights Name') -param applicationInsightsName string - -resource apimService 'Microsoft.ApiManagement/service@2021-08-01' = { - name: name - location: location - tags: union(tags, { 'azd-service-name': name }) - sku: { - name: sku - capacity: (sku == 'Consumption') ? 0 : ((sku == 'Developer') ? 1 : skuCount) - } - properties: { - publisherEmail: publisherEmail - publisherName: publisherName - } -} - -resource apimLogger 'Microsoft.ApiManagement/service/loggers@2021-12-01-preview' = if (!empty(applicationInsightsName)) { - name: 'app-insights-logger' - parent: apimService - properties: { - credentials: { - instrumentationKey: applicationInsights.properties.InstrumentationKey - } - description: 'Logger to Azure Application Insights' - isBuffered: false - loggerType: 'applicationInsights' - resourceId: applicationInsights.id - } -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { - name: applicationInsightsName -} - -output apimServiceName string = apimService.name diff --git a/infra/core/host/container-app.bicep b/infra/core/host/container-app.bicep deleted file mode 100644 index dde1bab..0000000 --- a/infra/core/host/container-app.bicep +++ /dev/null @@ -1,77 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param containerAppsEnvironmentName string = '' -param containerName string = 'main' -param containerRegistryName string = '' -param env array = [] -param external bool = true -param imageName string -param keyVaultName string = '' -param managedIdentity bool = !empty(keyVaultName) -param targetPort int = 80 - -@description('CPU cores allocated to a single container instance, e.g. 0.5') -param containerCpuCoreCount string = '0.5' - -@description('Memory allocated to a single container instance, e.g. 1Gi') -param containerMemory string = '1.0Gi' - -resource app 'Microsoft.App/containerApps@2022-03-01' = { - name: name - location: location - tags: tags - identity: { type: managedIdentity ? 'SystemAssigned' : 'None' } - properties: { - managedEnvironmentId: containerAppsEnvironment.id - configuration: { - activeRevisionsMode: 'single' - ingress: { - external: external - targetPort: targetPort - transport: 'auto' - } - secrets: [ - { - name: 'registry-password' - value: containerRegistry.listCredentials().passwords[0].value - } - ] - registries: [ - { - server: '${containerRegistry.name}.azurecr.io' - username: containerRegistry.name - passwordSecretRef: 'registry-password' - } - ] - } - template: { - containers: [ - { - image: imageName - name: containerName - env: env - resources: { - cpu: json(containerCpuCoreCount) - memory: containerMemory - } - } - ] - } - } -} - -resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-03-01' existing = { - name: containerAppsEnvironmentName -} - -// 2022-02-01-preview needed for anonymousPullEnabled -resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { - name: containerRegistryName -} - -output identityPrincipalId string = managedIdentity ? app.identity.principalId : '' -output imageName string = imageName -output name string = app.name -output uri string = 'https://${app.properties.configuration.ingress.fqdn}' diff --git a/infra/core/host/container-apps-environment.bicep b/infra/core/host/container-apps-environment.bicep deleted file mode 100644 index 2dd858c..0000000 --- a/infra/core/host/container-apps-environment.bicep +++ /dev/null @@ -1,26 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param logAnalyticsWorkspaceName string - -resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-03-01' = { - name: name - location: location - tags: tags - properties: { - appLogsConfiguration: { - destination: 'log-analytics' - logAnalyticsConfiguration: { - customerId: logAnalyticsWorkspace.properties.customerId - sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey - } - } - } -} - -resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { - name: logAnalyticsWorkspaceName -} - -output name string = containerAppsEnvironment.name diff --git a/infra/core/host/container-apps.bicep b/infra/core/host/container-apps.bicep deleted file mode 100644 index 395af70..0000000 --- a/infra/core/host/container-apps.bicep +++ /dev/null @@ -1,30 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param containerAppsEnvironmentName string = '' -param containerRegistryName string = '' -param logAnalyticsWorkspaceName string = '' - -module containerAppsEnvironment 'container-apps-environment.bicep' = { - name: '${name}-container-apps-environment' - params: { - name: containerAppsEnvironmentName - location: location - tags: tags - logAnalyticsWorkspaceName: logAnalyticsWorkspaceName - } -} - -module containerRegistry 'container-registry.bicep' = { - name: '${name}-container-registry' - params: { - name: containerRegistryName - location: location - tags: tags - } -} - -output environmentName string = containerAppsEnvironment.outputs.name -output registryLoginServer string = containerRegistry.outputs.loginServer -output registryName string = containerRegistry.outputs.name diff --git a/infra/core/host/container-registry.bicep b/infra/core/host/container-registry.bicep deleted file mode 100644 index 01c3213..0000000 --- a/infra/core/host/container-registry.bicep +++ /dev/null @@ -1,36 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param adminUserEnabled bool = true -param anonymousPullEnabled bool = false -param dataEndpointEnabled bool = false -param encryption object = { - status: 'disabled' -} -param networkRuleBypassOptions string = 'AzureServices' -param publicNetworkAccess string = 'Enabled' -param sku object = { - name: 'Basic' -} -param zoneRedundancy string = 'Disabled' - -// 2022-02-01-preview needed for anonymousPullEnabled -resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' = { - name: name - location: location - tags: tags - sku: sku - properties: { - adminUserEnabled: adminUserEnabled - anonymousPullEnabled: anonymousPullEnabled - dataEndpointEnabled: dataEndpointEnabled - encryption: encryption - networkRuleBypassOptions: networkRuleBypassOptions - publicNetworkAccess: publicNetworkAccess - zoneRedundancy: zoneRedundancy - } -} - -output loginServer string = containerRegistry.properties.loginServer -output name string = containerRegistry.name diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep deleted file mode 100644 index 28a581b..0000000 --- a/infra/core/host/functions.bicep +++ /dev/null @@ -1,82 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -// Reference Properties -param applicationInsightsName string = '' -param appServicePlanId string -param keyVaultName string = '' -param managedIdentity bool = !empty(keyVaultName) -param storageAccountName string - -// Runtime Properties -@allowed([ - 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' -]) -param runtimeName string -param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' -param runtimeVersion string - -// Function Settings -@allowed([ - '~4', '~3', '~2', '~1' -]) -param extensionVersion string = '~4' - -// Microsoft.Web/sites Properties -param kind string = 'functionapp,linux' - -// Microsoft.Web/sites/config -param allowedOrigins array = [] -param alwaysOn bool = true -param appCommandLine string = '' -param appSettings object = {} -param clientAffinityEnabled bool = false -param enableOryxBuild bool = contains(kind, 'linux') -param functionAppScaleLimit int = -1 -param linuxFxVersion string = runtimeNameAndVersion -param minimumElasticInstanceCount int = -1 -param numberOfWorkers int = -1 -param scmDoBuildDuringDeployment bool = true -param use32BitWorkerProcess bool = false - -module functions 'appservice.bicep' = { - name: '${name}-functions' - params: { - name: name - location: location - tags: tags - allowedOrigins: allowedOrigins - alwaysOn: alwaysOn - appCommandLine: appCommandLine - applicationInsightsName: applicationInsightsName - appServicePlanId: appServicePlanId - appSettings: union(appSettings, { - AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' - FUNCTIONS_EXTENSION_VERSION: extensionVersion - FUNCTIONS_WORKER_RUNTIME: runtimeName - }) - clientAffinityEnabled: clientAffinityEnabled - enableOryxBuild: enableOryxBuild - functionAppScaleLimit: functionAppScaleLimit - keyVaultName: keyVaultName - kind: kind - linuxFxVersion: linuxFxVersion - managedIdentity: managedIdentity - minimumElasticInstanceCount: minimumElasticInstanceCount - numberOfWorkers: numberOfWorkers - runtimeName: runtimeName - runtimeVersion: runtimeVersion - runtimeNameAndVersion: runtimeNameAndVersion - scmDoBuildDuringDeployment: scmDoBuildDuringDeployment - use32BitWorkerProcess: use32BitWorkerProcess - } -} - -resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' existing = { - name: storageAccountName -} - -output identityPrincipalId string = managedIdentity ? functions.outputs.identityPrincipalId : '' -output name string = functions.outputs.name -output uri string = functions.outputs.uri diff --git a/infra/core/host/staticwebapp.bicep b/infra/core/host/staticwebapp.bicep deleted file mode 100644 index 91c2d0d..0000000 --- a/infra/core/host/staticwebapp.bicep +++ /dev/null @@ -1,21 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param sku object = { - name: 'Free' - tier: 'Free' -} - -resource web 'Microsoft.Web/staticSites@2022-03-01' = { - name: name - location: location - tags: tags - sku: sku - properties: { - provider: 'Custom' - } -} - -output name string = web.name -output uri string = 'https://${web.properties.defaultHostname}' diff --git a/infra/core/monitor/applicationinsights-dashboard.bicep b/infra/core/monitor/applicationinsights-dashboard.bicep deleted file mode 100644 index b7af2c1..0000000 --- a/infra/core/monitor/applicationinsights-dashboard.bicep +++ /dev/null @@ -1,1235 +0,0 @@ -param name string -param applicationInsightsName string -param location string = resourceGroup().location -param tags object = {} - -// 2020-09-01-preview because that is the latest valid version -resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-preview' = { - name: name - location: location - tags: tags - properties: { - lenses: [ - { - order: 0 - parts: [ - { - position: { - x: 0 - y: 0 - colSpan: 2 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'id' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart' - asset: { - idInputName: 'id' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'overview' - } - } - { - position: { - x: 2 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'ProactiveDetection' - } - } - { - position: { - x: 3 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'ResourceId' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 4 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - endTime: null - createdTime: '2018-05-04T01:20:33.345Z' - isInitialTime: true - grain: 1 - useDashboardTimeRange: false - } - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 5 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - endTime: null - createdTime: '2018-05-08T18:47:35.237Z' - isInitialTime: true - grain: 1 - useDashboardTimeRange: false - } - } - { - name: 'ConfigurationId' - value: '78ce933e-e864-4b05-a27b-71fd55a6afad' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/AppMapButtonPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 0 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Usage' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 3 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - endTime: null - createdTime: '2018-05-04T01:22:35.782Z' - isInitialTime: true - grain: 1 - useDashboardTimeRange: false - } - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 4 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Reliability' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 7 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ResourceId' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - { - name: 'DataModel' - value: { - version: '1.0.0' - timeContext: { - durationMs: 86400000 - createdTime: '2018-05-04T23:42:40.072Z' - isInitialTime: false - grain: 1 - useDashboardTimeRange: false - } - } - isOptional: true - } - { - name: 'ConfigurationId' - value: '8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart' - isAdapter: true - asset: { - idInputName: 'ResourceId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'failures' - } - } - { - position: { - x: 8 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Responsiveness\r\n' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 11 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ResourceId' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - { - name: 'DataModel' - value: { - version: '1.0.0' - timeContext: { - durationMs: 86400000 - createdTime: '2018-05-04T23:43:37.804Z' - isInitialTime: false - grain: 1 - useDashboardTimeRange: false - } - } - isOptional: true - } - { - name: 'ConfigurationId' - value: '2a8ede4f-2bee-4b9c-aed9-2db0e8a01865' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart' - isAdapter: true - asset: { - idInputName: 'ResourceId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'performance' - } - } - { - position: { - x: 12 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Browser' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 15 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'MetricsExplorerJsonDefinitionId' - value: 'BrowserPerformanceTimelineMetrics' - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - createdTime: '2018-05-08T12:16:27.534Z' - isInitialTime: false - grain: 1 - useDashboardTimeRange: false - } - } - { - name: 'CurrentFilter' - value: { - eventTypes: [ - 4 - 1 - 3 - 5 - 2 - 6 - 13 - ] - typeFacets: {} - isPermissive: false - } - } - { - name: 'id' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'browser' - } - } - { - position: { - x: 0 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'sessions/count' - aggregationType: 5 - namespace: 'microsoft.insights/components/kusto' - metricVisualization: { - displayName: 'Sessions' - color: '#47BDF5' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'users/count' - aggregationType: 5 - namespace: 'microsoft.insights/components/kusto' - metricVisualization: { - displayName: 'Users' - color: '#7E58FF' - } - } - ] - title: 'Unique sessions and users' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'segmentationUsers' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 4 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'requests/failed' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Failed requests' - color: '#EC008C' - } - } - ] - title: 'Failed requests' - visualization: { - chartType: 3 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'failures' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 8 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'requests/duration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Server response time' - color: '#00BCF2' - } - } - ] - title: 'Server response time' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'performance' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 12 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/networkDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Page load network connect time' - color: '#7E58FF' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/processingDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Client processing time' - color: '#44F1C8' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/sendDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Send request time' - color: '#EB9371' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/receiveDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Receiving response time' - color: '#0672F1' - } - } - ] - title: 'Average page load time breakdown' - visualization: { - chartType: 3 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 0 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'availabilityResults/availabilityPercentage' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Availability' - color: '#47BDF5' - } - } - ] - title: 'Average availability' - visualization: { - chartType: 3 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'availability' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 4 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'exceptions/server' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Server exceptions' - color: '#47BDF5' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'dependencies/failed' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Dependency failures' - color: '#7E58FF' - } - } - ] - title: 'Server exceptions and Dependency failures' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 8 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/processorCpuPercentage' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Processor time' - color: '#47BDF5' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/processCpuPercentage' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Process CPU' - color: '#7E58FF' - } - } - ] - title: 'Average processor and process CPU utilization' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 12 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'exceptions/browser' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Browser exceptions' - color: '#47BDF5' - } - } - ] - title: 'Browser exceptions' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 0 - y: 8 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'availabilityResults/count' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Availability test results count' - color: '#47BDF5' - } - } - ] - title: 'Availability test results count' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 4 - y: 8 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/processIOBytesPerSecond' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Process IO rate' - color: '#47BDF5' - } - } - ] - title: 'Average process I/O rate' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 8 - y: 8 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/memoryAvailableBytes' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Available memory' - color: '#47BDF5' - } - } - ] - title: 'Average available memory' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - ] - } - ] - } -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = { - name: applicationInsightsName -} diff --git a/infra/core/monitor/applicationinsights.bicep b/infra/core/monitor/applicationinsights.bicep deleted file mode 100644 index f76b292..0000000 --- a/infra/core/monitor/applicationinsights.bicep +++ /dev/null @@ -1,30 +0,0 @@ -param name string -param dashboardName string -param location string = resourceGroup().location -param tags object = {} - -param logAnalyticsWorkspaceId string - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { - name: name - location: location - tags: tags - kind: 'web' - properties: { - Application_Type: 'web' - WorkspaceResourceId: logAnalyticsWorkspaceId - } -} - -module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = { - name: 'application-insights-dashboard' - params: { - name: dashboardName - location: location - applicationInsightsName: applicationInsights.name - } -} - -output connectionString string = applicationInsights.properties.ConnectionString -output instrumentationKey string = applicationInsights.properties.InstrumentationKey -output name string = applicationInsights.name diff --git a/infra/core/monitor/monitoring.bicep b/infra/core/monitor/monitoring.bicep deleted file mode 100644 index 96ba11e..0000000 --- a/infra/core/monitor/monitoring.bicep +++ /dev/null @@ -1,31 +0,0 @@ -param logAnalyticsName string -param applicationInsightsName string -param applicationInsightsDashboardName string -param location string = resourceGroup().location -param tags object = {} - -module logAnalytics 'loganalytics.bicep' = { - name: 'loganalytics' - params: { - name: logAnalyticsName - location: location - tags: tags - } -} - -module applicationInsights 'applicationinsights.bicep' = { - name: 'applicationinsights' - params: { - name: applicationInsightsName - location: location - tags: tags - dashboardName: applicationInsightsDashboardName - logAnalyticsWorkspaceId: logAnalytics.outputs.id - } -} - -output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString -output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey -output applicationInsightsName string = applicationInsights.outputs.name -output logAnalyticsWorkspaceId string = logAnalytics.outputs.id -output logAnalyticsWorkspaceName string = logAnalytics.outputs.name diff --git a/infra/core/security/keyvault-access.bicep b/infra/core/security/keyvault-access.bicep deleted file mode 100644 index 96c9cf7..0000000 --- a/infra/core/security/keyvault-access.bicep +++ /dev/null @@ -1,21 +0,0 @@ -param name string = 'add' - -param keyVaultName string = '' -param permissions object = { secrets: [ 'get', 'list' ] } -param principalId string - -resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { - parent: keyVault - name: name - properties: { - accessPolicies: [ { - objectId: principalId - tenantId: subscription().tenantId - permissions: permissions - } ] - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} diff --git a/infra/core/security/keyvault-secret.bicep b/infra/core/security/keyvault-secret.bicep deleted file mode 100644 index 5f786ce..0000000 --- a/infra/core/security/keyvault-secret.bicep +++ /dev/null @@ -1,30 +0,0 @@ -param name string -param tags object = {} -param keyVaultName string -param contentType string = 'string' -@description('The value of the secret. Provide only derived values like blob storage access, but do not hard code any secrets in your templates') -@secure() -param secretValue string - -param enabled bool = true -param exp int = 0 -param nbf int = 0 - -resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - name: name - tags: tags - parent: keyVault - properties: { - attributes: { - enabled: enabled - exp: exp - nbf: nbf - } - contentType: contentType - value: secretValue - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} diff --git a/infra/core/security/keyvault.bicep b/infra/core/security/keyvault.bicep deleted file mode 100644 index 0eb4a86..0000000 --- a/infra/core/security/keyvault.bicep +++ /dev/null @@ -1,25 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param principalId string = '' - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { - name: name - location: location - tags: tags - properties: { - tenantId: subscription().tenantId - sku: { family: 'A', name: 'standard' } - accessPolicies: !empty(principalId) ? [ - { - objectId: principalId - permissions: { secrets: [ 'get', 'list' ] } - tenantId: subscription().tenantId - } - ] : [] - } -} - -output endpoint string = keyVault.properties.vaultUri -output name string = keyVault.name diff --git a/infra/core/storage/storage-account.bicep b/infra/core/storage/storage-account.bicep deleted file mode 100644 index a41972c..0000000 --- a/infra/core/storage/storage-account.bicep +++ /dev/null @@ -1,38 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param allowBlobPublicAccess bool = false -param containers array = [] -param kind string = 'StorageV2' -param minimumTlsVersion string = 'TLS1_2' -param sku object = { name: 'Standard_LRS' } - -resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = { - name: name - location: location - tags: tags - kind: kind - sku: sku - properties: { - minimumTlsVersion: minimumTlsVersion - allowBlobPublicAccess: allowBlobPublicAccess - networkAcls: { - bypass: 'AzureServices' - defaultAction: 'Allow' - } - } - - resource blobServices 'blobServices' = if (!empty(containers)) { - name: 'default' - resource container 'containers' = [for container in containers: { - name: container.name - properties: { - publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' - } - }] - } -} - -output name string = storage.name -output primaryEndpoints object = storage.properties.primaryEndpoints diff --git a/infra/main.json b/infra/main.json new file mode 100644 index 0000000..51e8e32 --- /dev/null +++ b/infra/main.json @@ -0,0 +1,461 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "13017346756850192451" + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Name which is used to generate a short unique hash for each resource" + }, + "maxLength": 64, + "minLength": 1 + }, + "location": { + "type": "string", + "metadata": { + "description": "Primary location for all resources" + }, + "minLength": 1 + } + }, + "variables": { + "resourceToken": "[toLower(uniqueString(subscription().id, parameters('name'), parameters('location')))]", + "tags": { + "azd-env-name": "[parameters('name')]" + }, + "prefix": "[format('{0}-{1}', parameters('name'), variables('resourceToken'))]" + }, + "resources": [ + { + "type": "Microsoft.Resources/resourceGroups", + "apiVersion": "2021-04-01", + "name": "[format('{0}-rg', parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[variables('tags')]" + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-10-01", + "name": "appservice", + "resourceGroup": "[format('{0}-rg', parameters('name'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-appservice', variables('prefix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[union(variables('tags'), createObject('azd-service-name', 'web'))]" + }, + "appServicePlanId": { + "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, format('{0}-rg', parameters('name'))), 'Microsoft.Resources/deployments', 'serviceplan'), '2020-10-01').outputs.id.value]" + }, + "runtimeName": { + "value": "python" + }, + "runtimeVersion": { + "value": "3.10" + }, + "scmDoBuildDuringDeployment": { + "value": true + }, + "ftpsState": { + "value": "Disabled" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "1795870141244200075" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "" + }, + "appServicePlanId": { + "type": "string" + }, + "keyVaultName": { + "type": "string", + "defaultValue": "" + }, + "managedIdentity": { + "type": "bool", + "defaultValue": "[not(empty(parameters('keyVaultName')))]" + }, + "runtimeName": { + "type": "string", + "allowedValues": [ + "dotnet", + "dotnetcore", + "dotnet-isolated", + "node", + "python", + "java", + "powershell", + "custom" + ] + }, + "runtimeNameAndVersion": { + "type": "string", + "defaultValue": "[format('{0}|{1}', parameters('runtimeName'), parameters('runtimeVersion'))]" + }, + "runtimeVersion": { + "type": "string" + }, + "kind": { + "type": "string", + "defaultValue": "app,linux" + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [] + }, + "alwaysOn": { + "type": "bool", + "defaultValue": true + }, + "appCommandLine": { + "type": "string", + "defaultValue": "" + }, + "appSettings": { + "type": "object", + "defaultValue": {} + }, + "clientAffinityEnabled": { + "type": "bool", + "defaultValue": false + }, + "enableOryxBuild": { + "type": "bool", + "defaultValue": "[contains(parameters('kind'), 'linux')]" + }, + "functionAppScaleLimit": { + "type": "int", + "defaultValue": -1 + }, + "linuxFxVersion": { + "type": "string", + "defaultValue": "[parameters('runtimeNameAndVersion')]" + }, + "minimumElasticInstanceCount": { + "type": "int", + "defaultValue": -1 + }, + "numberOfWorkers": { + "type": "int", + "defaultValue": -1 + }, + "scmDoBuildDuringDeployment": { + "type": "bool", + "defaultValue": false + }, + "use32BitWorkerProcess": { + "type": "bool", + "defaultValue": false + }, + "ftpsState": { + "type": "string", + "defaultValue": "FtpsOnly" + } + }, + "resources": [ + { + "type": "Microsoft.Web/sites/config", + "apiVersion": "2022-03-01", + "name": "[format('{0}/{1}', parameters('name'), 'appsettings')]", + "properties": "[union(parameters('appSettings'), createObject('SCM_DO_BUILD_DURING_DEPLOYMENT', string(parameters('scmDoBuildDuringDeployment')), 'ENABLE_ORYX_BUILD', string(parameters('enableOryxBuild'))), if(not(empty(parameters('applicationInsightsName'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString), createObject()), if(not(empty(parameters('keyVaultName'))), createObject('AZURE_KEY_VAULT_ENDPOINT', reference(resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), '2022-07-01').vaultUri), createObject()))]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', parameters('name'))]" + ] + }, + { + "type": "Microsoft.Web/sites/config", + "apiVersion": "2022-03-01", + "name": "[format('{0}/{1}', parameters('name'), 'logs')]", + "properties": { + "applicationLogs": { + "fileSystem": { + "level": "Verbose" + } + }, + "detailedErrorMessages": { + "enabled": true + }, + "failedRequestsTracing": { + "enabled": true + }, + "httpLogs": { + "fileSystem": { + "enabled": true, + "retentionInDays": 1, + "retentionInMb": 35 + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', parameters('name'))]", + "[resourceId('Microsoft.Web/sites/config', parameters('name'), 'appsettings')]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2022-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "serverFarmId": "[parameters('appServicePlanId')]", + "siteConfig": { + "linuxFxVersion": "[parameters('linuxFxVersion')]", + "alwaysOn": "[parameters('alwaysOn')]", + "ftpsState": "[parameters('ftpsState')]", + "appCommandLine": "[parameters('appCommandLine')]", + "numberOfWorkers": "[if(not(equals(parameters('numberOfWorkers'), -1)), parameters('numberOfWorkers'), null())]", + "minimumElasticInstanceCount": "[if(not(equals(parameters('minimumElasticInstanceCount'), -1)), parameters('minimumElasticInstanceCount'), null())]", + "use32BitWorkerProcess": "[parameters('use32BitWorkerProcess')]", + "functionAppScaleLimit": "[if(not(equals(parameters('functionAppScaleLimit'), -1)), parameters('functionAppScaleLimit'), null())]", + "cors": { + "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" + } + }, + "clientAffinityEnabled": "[parameters('clientAffinityEnabled')]", + "httpsOnly": true + }, + "identity": { + "type": "[if(parameters('managedIdentity'), 'SystemAssigned', 'None')]" + } + } + ], + "outputs": { + "identityPrincipalId": { + "type": "string", + "value": "[if(parameters('managedIdentity'), reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01', 'full').identity.principalId, '')]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "value": "[format('https://{0}', reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01').defaultHostName)]" + } + } + } + }, + "dependsOn": [ + "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, format('{0}-rg', parameters('name'))), 'Microsoft.Resources/deployments', 'serviceplan')]", + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-rg', parameters('name')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-10-01", + "name": "serviceplan", + "resourceGroup": "[format('{0}-rg', parameters('name'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-serviceplan', variables('prefix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[variables('tags')]" + }, + "sku": { + "value": { + "name": "B1" + } + }, + "reserved": { + "value": true + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "13142218918539764077" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "kind": { + "type": "string", + "defaultValue": "" + }, + "reserved": { + "type": "bool", + "defaultValue": true + }, + "sku": { + "type": "object" + } + }, + "resources": [ + { + "type": "Microsoft.Web/serverfarms", + "apiVersion": "2022-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": "[parameters('sku')]", + "kind": "[parameters('kind')]", + "properties": { + "reserved": "[parameters('reserved')]" + } + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.Web/serverfarms', parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-rg', parameters('name')))]" + ] + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-10-01", + "name": "loganalytics", + "resourceGroup": "[format('{0}-rg', parameters('name'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[format('{0}-loganalytics', variables('prefix'))]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[variables('tags')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "5341201376154525718" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-12-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "retentionInDays": 30, + "features": { + "searchVersion": 1 + }, + "sku": { + "name": "PerGB2018" + } + } + } + ], + "outputs": { + "id": { + "type": "string", + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-rg', parameters('name')))]" + ] + } + ], + "outputs": { + "WEB_URI": { + "type": "string", + "value": "[format('https://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, format('{0}-rg', parameters('name'))), 'Microsoft.Resources/deployments', 'appservice'), '2020-10-01').outputs.uri.value)]" + }, + "AZURE_LOCATION": { + "type": "string", + "value": "[parameters('location')]" + } + } +} \ No newline at end of file From 0923f9655840ef976cd02b9c139794f33db83b58 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 21 Mar 2023 19:55:09 +0000 Subject: [PATCH 03/24] Update TLS --- infra/core/host/appservice.bicep | 3 +++ 1 file changed, 3 insertions(+) diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep index 04c2c49..c65f2b8 100644 --- a/infra/core/host/appservice.bicep +++ b/infra/core/host/appservice.bicep @@ -33,6 +33,7 @@ param numberOfWorkers int = -1 param scmDoBuildDuringDeployment bool = false param use32BitWorkerProcess bool = false param ftpsState string = 'FtpsOnly' +param healthCheckPath string = '' resource appService 'Microsoft.Web/sites@2022-03-01' = { name: name @@ -45,11 +46,13 @@ resource appService 'Microsoft.Web/sites@2022-03-01' = { linuxFxVersion: linuxFxVersion alwaysOn: alwaysOn ftpsState: ftpsState + minTlsVersion: '1.2' appCommandLine: appCommandLine numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null use32BitWorkerProcess: use32BitWorkerProcess functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null + healthCheckPath: healthCheckPath cors: { allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins) } From 5fea2f37965bf81e97d3a1c4db9b0e7a1d4c71e9 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 21 Mar 2023 19:57:42 +0000 Subject: [PATCH 04/24] Remove main.json --- infra/main.json | 461 ------------------------------------------------ 1 file changed, 461 deletions(-) delete mode 100644 infra/main.json diff --git a/infra/main.json b/infra/main.json deleted file mode 100644 index 51e8e32..0000000 --- a/infra/main.json +++ /dev/null @@ -1,461 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.15.31.15270", - "templateHash": "13017346756850192451" - } - }, - "parameters": { - "name": { - "type": "string", - "metadata": { - "description": "Name which is used to generate a short unique hash for each resource" - }, - "maxLength": 64, - "minLength": 1 - }, - "location": { - "type": "string", - "metadata": { - "description": "Primary location for all resources" - }, - "minLength": 1 - } - }, - "variables": { - "resourceToken": "[toLower(uniqueString(subscription().id, parameters('name'), parameters('location')))]", - "tags": { - "azd-env-name": "[parameters('name')]" - }, - "prefix": "[format('{0}-{1}', parameters('name'), variables('resourceToken'))]" - }, - "resources": [ - { - "type": "Microsoft.Resources/resourceGroups", - "apiVersion": "2021-04-01", - "name": "[format('{0}-rg', parameters('name'))]", - "location": "[parameters('location')]", - "tags": "[variables('tags')]" - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "appservice", - "resourceGroup": "[format('{0}-rg', parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-appservice', variables('prefix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[union(variables('tags'), createObject('azd-service-name', 'web'))]" - }, - "appServicePlanId": { - "value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, format('{0}-rg', parameters('name'))), 'Microsoft.Resources/deployments', 'serviceplan'), '2020-10-01').outputs.id.value]" - }, - "runtimeName": { - "value": "python" - }, - "runtimeVersion": { - "value": "3.10" - }, - "scmDoBuildDuringDeployment": { - "value": true - }, - "ftpsState": { - "value": "Disabled" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.15.31.15270", - "templateHash": "1795870141244200075" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "applicationInsightsName": { - "type": "string", - "defaultValue": "" - }, - "appServicePlanId": { - "type": "string" - }, - "keyVaultName": { - "type": "string", - "defaultValue": "" - }, - "managedIdentity": { - "type": "bool", - "defaultValue": "[not(empty(parameters('keyVaultName')))]" - }, - "runtimeName": { - "type": "string", - "allowedValues": [ - "dotnet", - "dotnetcore", - "dotnet-isolated", - "node", - "python", - "java", - "powershell", - "custom" - ] - }, - "runtimeNameAndVersion": { - "type": "string", - "defaultValue": "[format('{0}|{1}', parameters('runtimeName'), parameters('runtimeVersion'))]" - }, - "runtimeVersion": { - "type": "string" - }, - "kind": { - "type": "string", - "defaultValue": "app,linux" - }, - "allowedOrigins": { - "type": "array", - "defaultValue": [] - }, - "alwaysOn": { - "type": "bool", - "defaultValue": true - }, - "appCommandLine": { - "type": "string", - "defaultValue": "" - }, - "appSettings": { - "type": "object", - "defaultValue": {} - }, - "clientAffinityEnabled": { - "type": "bool", - "defaultValue": false - }, - "enableOryxBuild": { - "type": "bool", - "defaultValue": "[contains(parameters('kind'), 'linux')]" - }, - "functionAppScaleLimit": { - "type": "int", - "defaultValue": -1 - }, - "linuxFxVersion": { - "type": "string", - "defaultValue": "[parameters('runtimeNameAndVersion')]" - }, - "minimumElasticInstanceCount": { - "type": "int", - "defaultValue": -1 - }, - "numberOfWorkers": { - "type": "int", - "defaultValue": -1 - }, - "scmDoBuildDuringDeployment": { - "type": "bool", - "defaultValue": false - }, - "use32BitWorkerProcess": { - "type": "bool", - "defaultValue": false - }, - "ftpsState": { - "type": "string", - "defaultValue": "FtpsOnly" - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-03-01", - "name": "[format('{0}/{1}', parameters('name'), 'appsettings')]", - "properties": "[union(parameters('appSettings'), createObject('SCM_DO_BUILD_DURING_DEPLOYMENT', string(parameters('scmDoBuildDuringDeployment')), 'ENABLE_ORYX_BUILD', string(parameters('enableOryxBuild'))), if(not(empty(parameters('applicationInsightsName'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString), createObject()), if(not(empty(parameters('keyVaultName'))), createObject('AZURE_KEY_VAULT_ENDPOINT', reference(resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), '2022-07-01').vaultUri), createObject()))]", - "dependsOn": [ - "[resourceId('Microsoft.Web/sites', parameters('name'))]" - ] - }, - { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-03-01", - "name": "[format('{0}/{1}', parameters('name'), 'logs')]", - "properties": { - "applicationLogs": { - "fileSystem": { - "level": "Verbose" - } - }, - "detailedErrorMessages": { - "enabled": true - }, - "failedRequestsTracing": { - "enabled": true - }, - "httpLogs": { - "fileSystem": { - "enabled": true, - "retentionInDays": 1, - "retentionInMb": 35 - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/sites', parameters('name'))]", - "[resourceId('Microsoft.Web/sites/config', parameters('name'), 'appsettings')]" - ] - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2022-03-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "serverFarmId": "[parameters('appServicePlanId')]", - "siteConfig": { - "linuxFxVersion": "[parameters('linuxFxVersion')]", - "alwaysOn": "[parameters('alwaysOn')]", - "ftpsState": "[parameters('ftpsState')]", - "appCommandLine": "[parameters('appCommandLine')]", - "numberOfWorkers": "[if(not(equals(parameters('numberOfWorkers'), -1)), parameters('numberOfWorkers'), null())]", - "minimumElasticInstanceCount": "[if(not(equals(parameters('minimumElasticInstanceCount'), -1)), parameters('minimumElasticInstanceCount'), null())]", - "use32BitWorkerProcess": "[parameters('use32BitWorkerProcess')]", - "functionAppScaleLimit": "[if(not(equals(parameters('functionAppScaleLimit'), -1)), parameters('functionAppScaleLimit'), null())]", - "cors": { - "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" - } - }, - "clientAffinityEnabled": "[parameters('clientAffinityEnabled')]", - "httpsOnly": true - }, - "identity": { - "type": "[if(parameters('managedIdentity'), 'SystemAssigned', 'None')]" - } - } - ], - "outputs": { - "identityPrincipalId": { - "type": "string", - "value": "[if(parameters('managedIdentity'), reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01', 'full').identity.principalId, '')]" - }, - "name": { - "type": "string", - "value": "[parameters('name')]" - }, - "uri": { - "type": "string", - "value": "[format('https://{0}', reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01').defaultHostName)]" - } - } - } - }, - "dependsOn": [ - "[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, format('{0}-rg', parameters('name'))), 'Microsoft.Resources/deployments', 'serviceplan')]", - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-rg', parameters('name')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "serviceplan", - "resourceGroup": "[format('{0}-rg', parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-serviceplan', variables('prefix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[variables('tags')]" - }, - "sku": { - "value": { - "name": "B1" - } - }, - "reserved": { - "value": true - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.15.31.15270", - "templateHash": "13142218918539764077" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "kind": { - "type": "string", - "defaultValue": "" - }, - "reserved": { - "type": "bool", - "defaultValue": true - }, - "sku": { - "type": "object" - } - }, - "resources": [ - { - "type": "Microsoft.Web/serverfarms", - "apiVersion": "2022-03-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "sku": "[parameters('sku')]", - "kind": "[parameters('kind')]", - "properties": { - "reserved": "[parameters('reserved')]" - } - } - ], - "outputs": { - "id": { - "type": "string", - "value": "[resourceId('Microsoft.Web/serverfarms', parameters('name'))]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-rg', parameters('name')))]" - ] - }, - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "loganalytics", - "resourceGroup": "[format('{0}-rg', parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[format('{0}-loganalytics', variables('prefix'))]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[variables('tags')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.15.31.15270", - "templateHash": "5341201376154525718" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - }, - "tags": { - "type": "object", - "defaultValue": {} - } - }, - "resources": [ - { - "type": "Microsoft.OperationalInsights/workspaces", - "apiVersion": "2021-12-01-preview", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "properties": { - "retentionInDays": 30, - "features": { - "searchVersion": 1 - }, - "sku": { - "name": "PerGB2018" - } - } - } - ], - "outputs": { - "id": { - "type": "string", - "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" - }, - "name": { - "type": "string", - "value": "[parameters('name')]" - } - } - } - }, - "dependsOn": [ - "[subscriptionResourceId('Microsoft.Resources/resourceGroups', format('{0}-rg', parameters('name')))]" - ] - } - ], - "outputs": { - "WEB_URI": { - "type": "string", - "value": "[format('https://{0}', reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, format('{0}-rg', parameters('name'))), 'Microsoft.Resources/deployments', 'appservice'), '2020-10-01').outputs.uri.value)]" - }, - "AZURE_LOCATION": { - "type": "string", - "value": "[parameters('location')]" - } - } -} \ No newline at end of file From 1270442d97fe8484af0c0e53345cf98f095ff14a Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 21 Mar 2023 20:08:55 +0000 Subject: [PATCH 05/24] Managed identity --- infra/core/host/appservice.bicep | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep index c65f2b8..6eb9623 100644 --- a/infra/core/host/appservice.bicep +++ b/infra/core/host/appservice.bicep @@ -6,7 +6,6 @@ param tags object = {} param applicationInsightsName string = '' param appServicePlanId string param keyVaultName string = '' -param managedIdentity bool = !empty(keyVaultName) // Runtime Properties @allowed([ @@ -61,7 +60,7 @@ resource appService 'Microsoft.Web/sites@2022-03-01' = { httpsOnly: true } - identity: { type: managedIdentity ? 'SystemAssigned' : 'None' } + identity: { type: 'SystemAssigned' } resource configAppSettings 'config' = { name: 'appsettings' From f64830b8749aaad4c213fbe69bd09e739e670bf1 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Tue, 21 Mar 2023 20:13:13 +0000 Subject: [PATCH 06/24] Manged identity fix --- infra/core/host/appservice.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep index 6eb9623..a56fade 100644 --- a/infra/core/host/appservice.bicep +++ b/infra/core/host/appservice.bicep @@ -95,6 +95,6 @@ resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing name: applicationInsightsName } -output identityPrincipalId string = managedIdentity ? appService.identity.principalId : '' +output identityPrincipalId string = appService.identity.principalId output name string = appService.name output uri string = 'https://${appService.properties.defaultHostName}' From 236cb787a47e703128091a5b47a14f7a50740527 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 03:47:38 +0000 Subject: [PATCH 07/24] Stdout --- .github/workflows/azure-bicep-validate.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/azure-bicep-validate.yaml b/.github/workflows/azure-bicep-validate.yaml index 78446c7..2cc6218 100644 --- a/.github/workflows/azure-bicep-validate.yaml +++ b/.github/workflows/azure-bicep-validate.yaml @@ -20,7 +20,7 @@ jobs: - name: Azure CLI script uses: azure/CLI@v1 with: - inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f infra/main.bicep + inlineScript: az config set bicep.use_binary_from_path=false && az bicep build -f infra/main.bicep --stdout - name: Run Microsoft Security DevOps Analysis uses: microsoft/security-devops-action@preview From b47943824bf20a4c6864226dc2e4256a2cab3f42 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 03:54:39 +0000 Subject: [PATCH 08/24] bring db back --- .../core/database/cosmos/cosmos-account.bicep | 48 +++++++ .../cosmos/mongo/cosmos-mongo-account.bicep | 22 +++ .../cosmos/mongo/cosmos-mongo-db.bicep | 46 +++++++ .../cosmos/sql/cosmos-sql-account.bicep | 21 +++ .../database/cosmos/sql/cosmos-sql-db.bicep | 73 ++++++++++ .../cosmos/sql/cosmos-sql-role-assign.bicep | 18 +++ .../cosmos/sql/cosmos-sql-role-def.bicep | 29 ++++ infra/core/database/sqlserver/sqlserver.bicep | 129 ++++++++++++++++++ 8 files changed, 386 insertions(+) create mode 100644 infra/core/database/cosmos/cosmos-account.bicep create mode 100644 infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep create mode 100644 infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep create mode 100644 infra/core/database/cosmos/sql/cosmos-sql-account.bicep create mode 100644 infra/core/database/cosmos/sql/cosmos-sql-db.bicep create mode 100644 infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep create mode 100644 infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep create mode 100644 infra/core/database/sqlserver/sqlserver.bicep diff --git a/infra/core/database/cosmos/cosmos-account.bicep b/infra/core/database/cosmos/cosmos-account.bicep new file mode 100644 index 0000000..6bc1f2e --- /dev/null +++ b/infra/core/database/cosmos/cosmos-account.bicep @@ -0,0 +1,48 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' +param keyVaultName string + +@allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ]) +param kind string + +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = { + name: name + kind: kind + location: location + tags: tags + properties: { + consistencyPolicy: { defaultConsistencyLevel: 'Session' } + locations: [ + { + locationName: location + failoverPriority: 0 + isZoneRedundant: false + } + ] + databaseAccountOfferType: 'Standard' + enableAutomaticFailover: false + enableMultipleWriteLocations: false + apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.0' } : {} + capabilities: [ { name: 'EnableServerless' } ] + } +} + +resource cosmosConnectionString 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVault + name: connectionStringKey + properties: { + value: cosmos.listConnectionStrings().connectionStrings[0].connectionString + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +output connectionStringKey string = connectionStringKey +output endpoint string = cosmos.properties.documentEndpoint +output id string = cosmos.id +output name string = cosmos.name diff --git a/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep b/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep new file mode 100644 index 0000000..bd2a2b5 --- /dev/null +++ b/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep @@ -0,0 +1,22 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param keyVaultName string +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' + +module cosmos '../../cosmos/cosmos-account.bicep' = { + name: 'cosmos-account' + params: { + name: name + location: location + connectionStringKey: connectionStringKey + keyVaultName: keyVaultName + kind: 'MongoDB' + tags: tags + } +} + +output connectionStringKey string = cosmos.outputs.connectionStringKey +output endpoint string = cosmos.outputs.endpoint +output id string = cosmos.outputs.id diff --git a/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep b/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep new file mode 100644 index 0000000..2c9688e --- /dev/null +++ b/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep @@ -0,0 +1,46 @@ +param accountName string +param databaseName string +param location string = resourceGroup().location +param tags object = {} + +param collections array = [] +param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' +param keyVaultName string + +module cosmos 'cosmos-mongo-account.bicep' = { + name: 'cosmos-mongo-account' + params: { + name: accountName + location: location + keyVaultName: keyVaultName + tags: tags + connectionStringKey: connectionStringKey + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2022-08-15' = { + name: '${accountName}/${databaseName}' + tags: tags + properties: { + resource: { id: databaseName } + } + + resource list 'collections' = [for collection in collections: { + name: collection.name + properties: { + resource: { + id: collection.id + shardKey: { _id: collection.shardKey } + indexes: [ { key: { keys: [ collection.indexKey ] } } ] + } + } + }] + + dependsOn: [ + cosmos + ] +} + +output connectionStringKey string = connectionStringKey +output databaseName string = databaseName +output endpoint string = cosmos.outputs.endpoint diff --git a/infra/core/database/cosmos/sql/cosmos-sql-account.bicep b/infra/core/database/cosmos/sql/cosmos-sql-account.bicep new file mode 100644 index 0000000..e8b030f --- /dev/null +++ b/infra/core/database/cosmos/sql/cosmos-sql-account.bicep @@ -0,0 +1,21 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param keyVaultName string + +module cosmos '../../cosmos/cosmos-account.bicep' = { + name: 'cosmos-account' + params: { + name: name + location: location + tags: tags + keyVaultName: keyVaultName + kind: 'GlobalDocumentDB' + } +} + +output connectionStringKey string = cosmos.outputs.connectionStringKey +output endpoint string = cosmos.outputs.endpoint +output id string = cosmos.outputs.id +output name string = cosmos.outputs.name diff --git a/infra/core/database/cosmos/sql/cosmos-sql-db.bicep b/infra/core/database/cosmos/sql/cosmos-sql-db.bicep new file mode 100644 index 0000000..5a4de20 --- /dev/null +++ b/infra/core/database/cosmos/sql/cosmos-sql-db.bicep @@ -0,0 +1,73 @@ +param accountName string +param databaseName string +param location string = resourceGroup().location +param tags object = {} + +param containers array = [] +param keyVaultName string +param principalIds array = [] + +module cosmos 'cosmos-sql-account.bicep' = { + name: 'cosmos-sql-account' + params: { + name: accountName + location: location + tags: tags + keyVaultName: keyVaultName + } +} + +resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = { + name: '${accountName}/${databaseName}' + properties: { + resource: { id: databaseName } + } + + resource list 'containers' = [for container in containers: { + name: container.name + properties: { + resource: { + id: container.id + partitionKey: { paths: [ container.partitionKey ] } + } + options: {} + } + }] + + dependsOn: [ + cosmos + ] +} + +module roleDefintion 'cosmos-sql-role-def.bicep' = { + name: 'cosmos-sql-role-definition' + params: { + accountName: accountName + } + dependsOn: [ + cosmos + database + ] +} + +// We need batchSize(1) here because sql role assignments have to be done sequentially +@batchSize(1) +module userRole 'cosmos-sql-role-assign.bicep' = [for principalId in principalIds: if (!empty(principalId)) { + name: 'cosmos-sql-user-role-${uniqueString(principalId)}' + params: { + accountName: accountName + roleDefinitionId: roleDefintion.outputs.id + principalId: principalId + } + dependsOn: [ + cosmos + database + ] +}] + +output accountId string = cosmos.outputs.id +output accountName string = cosmos.outputs.name +output connectionStringKey string = cosmos.outputs.connectionStringKey +output databaseName string = databaseName +output endpoint string = cosmos.outputs.endpoint +output roleDefinitionId string = roleDefintion.outputs.id diff --git a/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep b/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep new file mode 100644 index 0000000..6855edf --- /dev/null +++ b/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep @@ -0,0 +1,18 @@ +param accountName string + +param roleDefinitionId string +param principalId string = '' + +resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = { + parent: cosmos + name: guid(roleDefinitionId, principalId, cosmos.id) + properties: { + principalId: principalId + roleDefinitionId: roleDefinitionId + scope: cosmos.id + } +} + +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { + name: accountName +} diff --git a/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep b/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep new file mode 100644 index 0000000..cfb4033 --- /dev/null +++ b/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep @@ -0,0 +1,29 @@ +param accountName string + +resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = { + parent: cosmos + name: guid(cosmos.id, accountName, 'sql-role') + properties: { + assignableScopes: [ + cosmos.id + ] + permissions: [ + { + dataActions: [ + 'Microsoft.DocumentDB/databaseAccounts/readMetadata' + 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' + 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' + ] + notDataActions: [] + } + ] + roleName: 'Reader Writer' + type: 'CustomRole' + } +} + +resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { + name: accountName +} + +output id string = roleDefinition.id diff --git a/infra/core/database/sqlserver/sqlserver.bicep b/infra/core/database/sqlserver/sqlserver.bicep new file mode 100644 index 0000000..821a908 --- /dev/null +++ b/infra/core/database/sqlserver/sqlserver.bicep @@ -0,0 +1,129 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param appUser string = 'appUser' +param databaseName string +param keyVaultName string +param sqlAdmin string = 'sqlAdmin' +param connectionStringKey string = 'AZURE-SQL-CONNECTION-STRING' + +@secure() +param sqlAdminPassword string +@secure() +param appUserPassword string + +resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = { + name: name + location: location + tags: tags + properties: { + version: '12.0' + minimalTlsVersion: '1.2' + publicNetworkAccess: 'Enabled' + administratorLogin: sqlAdmin + administratorLoginPassword: sqlAdminPassword + } + + resource database 'databases' = { + name: databaseName + location: location + } + + resource firewall 'firewallRules' = { + name: 'Azure Services' + properties: { + // Allow all clients + // Note: range [0.0.0.0-0.0.0.0] means "allow all Azure-hosted clients only". + // This is not sufficient, because we also want to allow direct access from developer machine, for debugging purposes. + startIpAddress: '0.0.0.1' + endIpAddress: '255.255.255.254' + } + } +} + +resource sqlDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: '${name}-deployment-script' + location: location + kind: 'AzureCLI' + properties: { + azCliVersion: '2.37.0' + retentionInterval: 'PT1H' // Retain the script resource for 1 hour after it ends running + timeout: 'PT5M' // Five minutes + cleanupPreference: 'OnSuccess' + environmentVariables: [ + { + name: 'APPUSERNAME' + value: appUser + } + { + name: 'APPUSERPASSWORD' + secureValue: appUserPassword + } + { + name: 'DBNAME' + value: databaseName + } + { + name: 'DBSERVER' + value: sqlServer.properties.fullyQualifiedDomainName + } + { + name: 'SQLCMDPASSWORD' + secureValue: sqlAdminPassword + } + { + name: 'SQLADMIN' + value: sqlAdmin + } + ] + + scriptContent: ''' +wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 +tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . + +cat < ./initDb.sql +drop user ${APPUSERNAME} +go +create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' +go +alter role db_owner add member ${APPUSERNAME} +go +SCRIPT_END + +./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql + ''' + } +} + +resource sqlAdminPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVault + name: 'sqlAdminPassword' + properties: { + value: sqlAdminPassword + } +} + +resource appUserPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVault + name: 'appUserPassword' + properties: { + value: appUserPassword + } +} + +resource sqlAzureConnectionStringSercret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + parent: keyVault + name: connectionStringKey + properties: { + value: '${connectionString}; Password=${appUserPassword}' + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +var connectionString = 'Server=${sqlServer.properties.fullyQualifiedDomainName}; Database=${sqlServer::database.name}; User=${appUser}' +output connectionStringKey string = connectionStringKey +output databaseName string = sqlServer::database.name From 4cb9e6fee8b128bcdcd3a11d024175554b22d4cf Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:01:40 +0000 Subject: [PATCH 09/24] bring back more --- infra/core/gateway/apim-api-policy.xml | 92 ++ infra/core/gateway/apim.bicep | 61 + .../applicationinsights-dashboard.bicep | 1235 +++++++++++++++++ infra/core/monitor/applicationinsights.bicep | 30 + infra/core/monitor/monitoring.bicep | 31 + infra/core/security/keyvault-access.bicep | 21 + infra/core/security/keyvault-secret.bicep | 30 + infra/core/security/keyvault.bicep | 25 + 8 files changed, 1525 insertions(+) create mode 100644 infra/core/gateway/apim-api-policy.xml create mode 100644 infra/core/gateway/apim.bicep create mode 100644 infra/core/monitor/applicationinsights-dashboard.bicep create mode 100644 infra/core/monitor/applicationinsights.bicep create mode 100644 infra/core/monitor/monitoring.bicep create mode 100644 infra/core/security/keyvault-access.bicep create mode 100644 infra/core/security/keyvault-secret.bicep create mode 100644 infra/core/security/keyvault.bicep diff --git a/infra/core/gateway/apim-api-policy.xml b/infra/core/gateway/apim-api-policy.xml new file mode 100644 index 0000000..2a6d811 --- /dev/null +++ b/infra/core/gateway/apim-api-policy.xml @@ -0,0 +1,92 @@ + + + + + + + + {0} + + + PUT + GET + POST + DELETE + PATCH + + +
*
+
+ +
*
+
+
+ + + + + + + Call to the @(context.Api.Name) + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Failed to process the @(context.Api.Name) + + + + + + + + + + + + + + + + + + We're Sorry. An unexpected error has occurred. If this continues please contact Tech Support. + + +
\ No newline at end of file diff --git a/infra/core/gateway/apim.bicep b/infra/core/gateway/apim.bicep new file mode 100644 index 0000000..76c5ae7 --- /dev/null +++ b/infra/core/gateway/apim.bicep @@ -0,0 +1,61 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +@description('The email address of the owner of the service') +@minLength(1) +param publisherEmail string = 'noreply@microsoft.com' + +@description('The name of the owner of the service') +@minLength(1) +param publisherName string = 'n/a' + +@description('The pricing tier of this API Management service') +@allowed([ + 'Consumption' + 'Developer' + 'Standard' + 'Premium' +]) +param sku string = 'Consumption' + +@description('The instance size of this API Management service.') +@allowed([ 0, 1, 2 ]) +param skuCount int = 0 + +@description('Azure Application Insights Name') +param applicationInsightsName string + +resource apimService 'Microsoft.ApiManagement/service@2021-08-01' = { + name: name + location: location + tags: union(tags, { 'azd-service-name': name }) + sku: { + name: sku + capacity: (sku == 'Consumption') ? 0 : ((sku == 'Developer') ? 1 : skuCount) + } + properties: { + publisherEmail: publisherEmail + publisherName: publisherName + } +} + +resource apimLogger 'Microsoft.ApiManagement/service/loggers@2021-12-01-preview' = if (!empty(applicationInsightsName)) { + name: 'app-insights-logger' + parent: apimService + properties: { + credentials: { + instrumentationKey: applicationInsights.properties.InstrumentationKey + } + description: 'Logger to Azure Application Insights' + isBuffered: false + loggerType: 'applicationInsights' + resourceId: applicationInsights.id + } +} + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { + name: applicationInsightsName +} + +output apimServiceName string = apimService.name diff --git a/infra/core/monitor/applicationinsights-dashboard.bicep b/infra/core/monitor/applicationinsights-dashboard.bicep new file mode 100644 index 0000000..b7af2c1 --- /dev/null +++ b/infra/core/monitor/applicationinsights-dashboard.bicep @@ -0,0 +1,1235 @@ +param name string +param applicationInsightsName string +param location string = resourceGroup().location +param tags object = {} + +// 2020-09-01-preview because that is the latest valid version +resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-preview' = { + name: name + location: location + tags: tags + properties: { + lenses: [ + { + order: 0 + parts: [ + { + position: { + x: 0 + y: 0 + colSpan: 2 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'id' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart' + asset: { + idInputName: 'id' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'overview' + } + } + { + position: { + x: 2 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'ProactiveDetection' + } + } + { + position: { + x: 3 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'ResourceId' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 4 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + endTime: null + createdTime: '2018-05-04T01:20:33.345Z' + isInitialTime: true + grain: 1 + useDashboardTimeRange: false + } + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 5 + y: 0 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + endTime: null + createdTime: '2018-05-08T18:47:35.237Z' + isInitialTime: true + grain: 1 + useDashboardTimeRange: false + } + } + { + name: 'ConfigurationId' + value: '78ce933e-e864-4b05-a27b-71fd55a6afad' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/AppMapButtonPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 0 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Usage' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 3 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + endTime: null + createdTime: '2018-05-04T01:22:35.782Z' + isInitialTime: true + grain: 1 + useDashboardTimeRange: false + } + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + } + } + { + position: { + x: 4 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Reliability' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 7 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ResourceId' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + { + name: 'DataModel' + value: { + version: '1.0.0' + timeContext: { + durationMs: 86400000 + createdTime: '2018-05-04T23:42:40.072Z' + isInitialTime: false + grain: 1 + useDashboardTimeRange: false + } + } + isOptional: true + } + { + name: 'ConfigurationId' + value: '8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart' + isAdapter: true + asset: { + idInputName: 'ResourceId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'failures' + } + } + { + position: { + x: 8 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Responsiveness\r\n' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 11 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ResourceId' + value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + { + name: 'DataModel' + value: { + version: '1.0.0' + timeContext: { + durationMs: 86400000 + createdTime: '2018-05-04T23:43:37.804Z' + isInitialTime: false + grain: 1 + useDashboardTimeRange: false + } + } + isOptional: true + } + { + name: 'ConfigurationId' + value: '2a8ede4f-2bee-4b9c-aed9-2db0e8a01865' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart' + isAdapter: true + asset: { + idInputName: 'ResourceId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'performance' + } + } + { + position: { + x: 12 + y: 1 + colSpan: 3 + rowSpan: 1 + } + metadata: { + inputs: [] + type: 'Extension/HubsExtension/PartType/MarkdownPart' + settings: { + content: { + settings: { + content: '# Browser' + title: '' + subtitle: '' + } + } + } + } + } + { + position: { + x: 15 + y: 1 + colSpan: 1 + rowSpan: 1 + } + metadata: { + inputs: [ + { + name: 'ComponentId' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'MetricsExplorerJsonDefinitionId' + value: 'BrowserPerformanceTimelineMetrics' + } + { + name: 'TimeContext' + value: { + durationMs: 86400000 + createdTime: '2018-05-08T12:16:27.534Z' + isInitialTime: false + grain: 1 + useDashboardTimeRange: false + } + } + { + name: 'CurrentFilter' + value: { + eventTypes: [ + 4 + 1 + 3 + 5 + 2 + 6 + 13 + ] + typeFacets: {} + isPermissive: false + } + } + { + name: 'id' + value: { + Name: applicationInsights.name + SubscriptionId: subscription().subscriptionId + ResourceGroup: resourceGroup().name + } + } + { + name: 'Version' + value: '1.0' + } + ] + #disable-next-line BCP036 + type: 'Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart' + asset: { + idInputName: 'ComponentId' + type: 'ApplicationInsights' + } + defaultMenuItemId: 'browser' + } + } + { + position: { + x: 0 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'sessions/count' + aggregationType: 5 + namespace: 'microsoft.insights/components/kusto' + metricVisualization: { + displayName: 'Sessions' + color: '#47BDF5' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'users/count' + aggregationType: 5 + namespace: 'microsoft.insights/components/kusto' + metricVisualization: { + displayName: 'Users' + color: '#7E58FF' + } + } + ] + title: 'Unique sessions and users' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'segmentationUsers' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 4 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'requests/failed' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Failed requests' + color: '#EC008C' + } + } + ] + title: 'Failed requests' + visualization: { + chartType: 3 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'failures' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 8 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'requests/duration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Server response time' + color: '#00BCF2' + } + } + ] + title: 'Server response time' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'performance' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 12 + y: 2 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/networkDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Page load network connect time' + color: '#7E58FF' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/processingDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Client processing time' + color: '#44F1C8' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/sendDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Send request time' + color: '#EB9371' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'browserTimings/receiveDuration' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Receiving response time' + color: '#0672F1' + } + } + ] + title: 'Average page load time breakdown' + visualization: { + chartType: 3 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 0 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'availabilityResults/availabilityPercentage' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Availability' + color: '#47BDF5' + } + } + ] + title: 'Average availability' + visualization: { + chartType: 3 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + openBladeOnClick: { + openBlade: true + destinationBlade: { + extensionName: 'HubsExtension' + bladeName: 'ResourceMenuBlade' + parameters: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + menuid: 'availability' + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 4 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'exceptions/server' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Server exceptions' + color: '#47BDF5' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'dependencies/failed' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Dependency failures' + color: '#7E58FF' + } + } + ] + title: 'Server exceptions and Dependency failures' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 8 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/processorCpuPercentage' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Processor time' + color: '#47BDF5' + } + } + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/processCpuPercentage' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Process CPU' + color: '#7E58FF' + } + } + ] + title: 'Average processor and process CPU utilization' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 12 + y: 5 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'exceptions/browser' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Browser exceptions' + color: '#47BDF5' + } + } + ] + title: 'Browser exceptions' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 0 + y: 8 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'availabilityResults/count' + aggregationType: 7 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Availability test results count' + color: '#47BDF5' + } + } + ] + title: 'Availability test results count' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 4 + y: 8 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/processIOBytesPerSecond' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Process IO rate' + color: '#47BDF5' + } + } + ] + title: 'Average process I/O rate' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + { + position: { + x: 8 + y: 8 + colSpan: 4 + rowSpan: 3 + } + metadata: { + inputs: [ + { + name: 'options' + value: { + chart: { + metrics: [ + { + resourceMetadata: { + id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' + } + name: 'performanceCounters/memoryAvailableBytes' + aggregationType: 4 + namespace: 'microsoft.insights/components' + metricVisualization: { + displayName: 'Available memory' + color: '#47BDF5' + } + } + ] + title: 'Average available memory' + visualization: { + chartType: 2 + legendVisualization: { + isVisible: true + position: 2 + hideSubtitle: false + } + axisVisualization: { + x: { + isVisible: true + axisType: 2 + } + y: { + isVisible: true + axisType: 1 + } + } + } + } + } + } + { + name: 'sharedTimeRange' + isOptional: true + } + ] + #disable-next-line BCP036 + type: 'Extension/HubsExtension/PartType/MonitorChartPart' + settings: {} + } + } + ] + } + ] + } +} + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = { + name: applicationInsightsName +} diff --git a/infra/core/monitor/applicationinsights.bicep b/infra/core/monitor/applicationinsights.bicep new file mode 100644 index 0000000..f76b292 --- /dev/null +++ b/infra/core/monitor/applicationinsights.bicep @@ -0,0 +1,30 @@ +param name string +param dashboardName string +param location string = resourceGroup().location +param tags object = {} + +param logAnalyticsWorkspaceId string + +resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { + name: name + location: location + tags: tags + kind: 'web' + properties: { + Application_Type: 'web' + WorkspaceResourceId: logAnalyticsWorkspaceId + } +} + +module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = { + name: 'application-insights-dashboard' + params: { + name: dashboardName + location: location + applicationInsightsName: applicationInsights.name + } +} + +output connectionString string = applicationInsights.properties.ConnectionString +output instrumentationKey string = applicationInsights.properties.InstrumentationKey +output name string = applicationInsights.name diff --git a/infra/core/monitor/monitoring.bicep b/infra/core/monitor/monitoring.bicep new file mode 100644 index 0000000..96ba11e --- /dev/null +++ b/infra/core/monitor/monitoring.bicep @@ -0,0 +1,31 @@ +param logAnalyticsName string +param applicationInsightsName string +param applicationInsightsDashboardName string +param location string = resourceGroup().location +param tags object = {} + +module logAnalytics 'loganalytics.bicep' = { + name: 'loganalytics' + params: { + name: logAnalyticsName + location: location + tags: tags + } +} + +module applicationInsights 'applicationinsights.bicep' = { + name: 'applicationinsights' + params: { + name: applicationInsightsName + location: location + tags: tags + dashboardName: applicationInsightsDashboardName + logAnalyticsWorkspaceId: logAnalytics.outputs.id + } +} + +output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString +output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey +output applicationInsightsName string = applicationInsights.outputs.name +output logAnalyticsWorkspaceId string = logAnalytics.outputs.id +output logAnalyticsWorkspaceName string = logAnalytics.outputs.name diff --git a/infra/core/security/keyvault-access.bicep b/infra/core/security/keyvault-access.bicep new file mode 100644 index 0000000..96c9cf7 --- /dev/null +++ b/infra/core/security/keyvault-access.bicep @@ -0,0 +1,21 @@ +param name string = 'add' + +param keyVaultName string = '' +param permissions object = { secrets: [ 'get', 'list' ] } +param principalId string + +resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { + parent: keyVault + name: name + properties: { + accessPolicies: [ { + objectId: principalId + tenantId: subscription().tenantId + permissions: permissions + } ] + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} diff --git a/infra/core/security/keyvault-secret.bicep b/infra/core/security/keyvault-secret.bicep new file mode 100644 index 0000000..5f786ce --- /dev/null +++ b/infra/core/security/keyvault-secret.bicep @@ -0,0 +1,30 @@ +param name string +param tags object = {} +param keyVaultName string +param contentType string = 'string' +@description('The value of the secret. Provide only derived values like blob storage access, but do not hard code any secrets in your templates') +@secure() +param secretValue string + +param enabled bool = true +param exp int = 0 +param nbf int = 0 + +resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { + name: name + tags: tags + parent: keyVault + properties: { + attributes: { + enabled: enabled + exp: exp + nbf: nbf + } + contentType: contentType + value: secretValue + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} diff --git a/infra/core/security/keyvault.bicep b/infra/core/security/keyvault.bicep new file mode 100644 index 0000000..0eb4a86 --- /dev/null +++ b/infra/core/security/keyvault.bicep @@ -0,0 +1,25 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param principalId string = '' + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: name + location: location + tags: tags + properties: { + tenantId: subscription().tenantId + sku: { family: 'A', name: 'standard' } + accessPolicies: !empty(principalId) ? [ + { + objectId: principalId + permissions: { secrets: [ 'get', 'list' ] } + tenantId: subscription().tenantId + } + ] : [] + } +} + +output endpoint string = keyVault.properties.vaultUri +output name string = keyVault.name From 7c9ec27f1747fd741d414db46b255be98e9ed876 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:09:05 +0000 Subject: [PATCH 10/24] keyvault string --- infra/core/security/keyvault-access.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/core/security/keyvault-access.bicep b/infra/core/security/keyvault-access.bicep index 96c9cf7..aa989eb 100644 --- a/infra/core/security/keyvault-access.bicep +++ b/infra/core/security/keyvault-access.bicep @@ -1,6 +1,6 @@ param name string = 'add' -param keyVaultName string = '' +param keyVaultName string param permissions object = { secrets: [ 'get', 'list' ] } param principalId string From 6b862ec92b5e3340f85167235a9384a38e80b995 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:11:49 +0000 Subject: [PATCH 11/24] Bring storage back --- infra/core/storage/storage-account.bicep | 38 ++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 infra/core/storage/storage-account.bicep diff --git a/infra/core/storage/storage-account.bicep b/infra/core/storage/storage-account.bicep new file mode 100644 index 0000000..a41972c --- /dev/null +++ b/infra/core/storage/storage-account.bicep @@ -0,0 +1,38 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param allowBlobPublicAccess bool = false +param containers array = [] +param kind string = 'StorageV2' +param minimumTlsVersion string = 'TLS1_2' +param sku object = { name: 'Standard_LRS' } + +resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = { + name: name + location: location + tags: tags + kind: kind + sku: sku + properties: { + minimumTlsVersion: minimumTlsVersion + allowBlobPublicAccess: allowBlobPublicAccess + networkAcls: { + bypass: 'AzureServices' + defaultAction: 'Allow' + } + } + + resource blobServices 'blobServices' = if (!empty(containers)) { + name: 'default' + resource container 'containers' = [for container in containers: { + name: container.name + properties: { + publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' + } + }] + } +} + +output name string = storage.name +output primaryEndpoints object = storage.properties.primaryEndpoints From 13c56750e43dfa101ac6648c645c21aea55e83fa Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:22:32 +0000 Subject: [PATCH 12/24] bring back more --- infra/core/host/container-registry.bicep | 36 +++++++++++ infra/core/host/functions.bicep | 82 ++++++++++++++++++++++++ infra/core/host/staticwebapp.bicep | 21 ++++++ 3 files changed, 139 insertions(+) create mode 100644 infra/core/host/container-registry.bicep create mode 100644 infra/core/host/functions.bicep create mode 100644 infra/core/host/staticwebapp.bicep diff --git a/infra/core/host/container-registry.bicep b/infra/core/host/container-registry.bicep new file mode 100644 index 0000000..01c3213 --- /dev/null +++ b/infra/core/host/container-registry.bicep @@ -0,0 +1,36 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param adminUserEnabled bool = true +param anonymousPullEnabled bool = false +param dataEndpointEnabled bool = false +param encryption object = { + status: 'disabled' +} +param networkRuleBypassOptions string = 'AzureServices' +param publicNetworkAccess string = 'Enabled' +param sku object = { + name: 'Basic' +} +param zoneRedundancy string = 'Disabled' + +// 2022-02-01-preview needed for anonymousPullEnabled +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' = { + name: name + location: location + tags: tags + sku: sku + properties: { + adminUserEnabled: adminUserEnabled + anonymousPullEnabled: anonymousPullEnabled + dataEndpointEnabled: dataEndpointEnabled + encryption: encryption + networkRuleBypassOptions: networkRuleBypassOptions + publicNetworkAccess: publicNetworkAccess + zoneRedundancy: zoneRedundancy + } +} + +output loginServer string = containerRegistry.properties.loginServer +output name string = containerRegistry.name diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep new file mode 100644 index 0000000..28a581b --- /dev/null +++ b/infra/core/host/functions.bicep @@ -0,0 +1,82 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +// Reference Properties +param applicationInsightsName string = '' +param appServicePlanId string +param keyVaultName string = '' +param managedIdentity bool = !empty(keyVaultName) +param storageAccountName string + +// Runtime Properties +@allowed([ + 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' +]) +param runtimeName string +param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' +param runtimeVersion string + +// Function Settings +@allowed([ + '~4', '~3', '~2', '~1' +]) +param extensionVersion string = '~4' + +// Microsoft.Web/sites Properties +param kind string = 'functionapp,linux' + +// Microsoft.Web/sites/config +param allowedOrigins array = [] +param alwaysOn bool = true +param appCommandLine string = '' +param appSettings object = {} +param clientAffinityEnabled bool = false +param enableOryxBuild bool = contains(kind, 'linux') +param functionAppScaleLimit int = -1 +param linuxFxVersion string = runtimeNameAndVersion +param minimumElasticInstanceCount int = -1 +param numberOfWorkers int = -1 +param scmDoBuildDuringDeployment bool = true +param use32BitWorkerProcess bool = false + +module functions 'appservice.bicep' = { + name: '${name}-functions' + params: { + name: name + location: location + tags: tags + allowedOrigins: allowedOrigins + alwaysOn: alwaysOn + appCommandLine: appCommandLine + applicationInsightsName: applicationInsightsName + appServicePlanId: appServicePlanId + appSettings: union(appSettings, { + AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' + FUNCTIONS_EXTENSION_VERSION: extensionVersion + FUNCTIONS_WORKER_RUNTIME: runtimeName + }) + clientAffinityEnabled: clientAffinityEnabled + enableOryxBuild: enableOryxBuild + functionAppScaleLimit: functionAppScaleLimit + keyVaultName: keyVaultName + kind: kind + linuxFxVersion: linuxFxVersion + managedIdentity: managedIdentity + minimumElasticInstanceCount: minimumElasticInstanceCount + numberOfWorkers: numberOfWorkers + runtimeName: runtimeName + runtimeVersion: runtimeVersion + runtimeNameAndVersion: runtimeNameAndVersion + scmDoBuildDuringDeployment: scmDoBuildDuringDeployment + use32BitWorkerProcess: use32BitWorkerProcess + } +} + +resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' existing = { + name: storageAccountName +} + +output identityPrincipalId string = managedIdentity ? functions.outputs.identityPrincipalId : '' +output name string = functions.outputs.name +output uri string = functions.outputs.uri diff --git a/infra/core/host/staticwebapp.bicep b/infra/core/host/staticwebapp.bicep new file mode 100644 index 0000000..91c2d0d --- /dev/null +++ b/infra/core/host/staticwebapp.bicep @@ -0,0 +1,21 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param sku object = { + name: 'Free' + tier: 'Free' +} + +resource web 'Microsoft.Web/staticSites@2022-03-01' = { + name: name + location: location + tags: tags + sku: sku + properties: { + provider: 'Custom' + } +} + +output name string = web.name +output uri string = 'https://${web.properties.defaultHostname}' From e265be6f2cea1c273f2c758c5e6eb0bb59e0cc43 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:26:53 +0000 Subject: [PATCH 13/24] Fix functions --- infra/core/host/functions.bicep | 1 - 1 file changed, 1 deletion(-) diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index 28a581b..f841adc 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -62,7 +62,6 @@ module functions 'appservice.bicep' = { keyVaultName: keyVaultName kind: kind linuxFxVersion: linuxFxVersion - managedIdentity: managedIdentity minimumElasticInstanceCount: minimumElasticInstanceCount numberOfWorkers: numberOfWorkers runtimeName: runtimeName From d00eb5b511d7c8bd2aae210b911d82a5250b1147 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:35:52 +0000 Subject: [PATCH 14/24] Fix functions --- infra/core/host/functions.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index f841adc..eee5e88 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -13,7 +13,7 @@ param storageAccountName string @allowed([ 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' ]) -param runtimeName string +param runtimeName string = 'custom' param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' param runtimeVersion string From c39ed13221ffcf10d5b788285086ef9bed5312fa Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:47:08 +0000 Subject: [PATCH 15/24] bring back more --- infra/core/host/functions.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index eee5e88..f841adc 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -13,7 +13,7 @@ param storageAccountName string @allowed([ 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' ]) -param runtimeName string = 'custom' +param runtimeName string param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' param runtimeVersion string From a556a536ce3e4a1f393c6525290d1022f9b7e6f6 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 04:53:18 +0000 Subject: [PATCH 16/24] bring back container --- infra/core/host/container-app.bicep | 77 +++++++++++++++++++ .../host/container-apps-environment.bicep | 26 +++++++ infra/core/host/container-apps.bicep | 30 ++++++++ 3 files changed, 133 insertions(+) create mode 100644 infra/core/host/container-app.bicep create mode 100644 infra/core/host/container-apps-environment.bicep create mode 100644 infra/core/host/container-apps.bicep diff --git a/infra/core/host/container-app.bicep b/infra/core/host/container-app.bicep new file mode 100644 index 0000000..a679b80 --- /dev/null +++ b/infra/core/host/container-app.bicep @@ -0,0 +1,77 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param containerAppsEnvironmentName string +param containerName string = 'main' +param containerRegistryName string +param env array = [] +param external bool = true +param imageName string +param keyVaultName string = '' +param managedIdentity bool = !empty(keyVaultName) +param targetPort int = 80 + +@description('CPU cores allocated to a single container instance, e.g. 0.5') +param containerCpuCoreCount string = '0.5' + +@description('Memory allocated to a single container instance, e.g. 1Gi') +param containerMemory string = '1.0Gi' + +resource app 'Microsoft.App/containerApps@2022-03-01' = { + name: name + location: location + tags: tags + identity: { type: managedIdentity ? 'SystemAssigned' : 'None' } + properties: { + managedEnvironmentId: containerAppsEnvironment.id + configuration: { + activeRevisionsMode: 'single' + ingress: { + external: external + targetPort: targetPort + transport: 'auto' + } + secrets: [ + { + name: 'registry-password' + value: containerRegistry.listCredentials().passwords[0].value + } + ] + registries: [ + { + server: '${containerRegistry.name}.azurecr.io' + username: containerRegistry.name + passwordSecretRef: 'registry-password' + } + ] + } + template: { + containers: [ + { + image: imageName + name: containerName + env: env + resources: { + cpu: json(containerCpuCoreCount) + memory: containerMemory + } + } + ] + } + } +} + +resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-03-01' existing = { + name: containerAppsEnvironmentName +} + +// 2022-02-01-preview needed for anonymousPullEnabled +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = { + name: containerRegistryName +} + +output identityPrincipalId string = managedIdentity ? app.identity.principalId : '' +output imageName string = imageName +output name string = app.name +output uri string = 'https://${app.properties.configuration.ingress.fqdn}' diff --git a/infra/core/host/container-apps-environment.bicep b/infra/core/host/container-apps-environment.bicep new file mode 100644 index 0000000..2dd858c --- /dev/null +++ b/infra/core/host/container-apps-environment.bicep @@ -0,0 +1,26 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param logAnalyticsWorkspaceName string + +resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-03-01' = { + name: name + location: location + tags: tags + properties: { + appLogsConfiguration: { + destination: 'log-analytics' + logAnalyticsConfiguration: { + customerId: logAnalyticsWorkspace.properties.customerId + sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey + } + } + } +} + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { + name: logAnalyticsWorkspaceName +} + +output name string = containerAppsEnvironment.name diff --git a/infra/core/host/container-apps.bicep b/infra/core/host/container-apps.bicep new file mode 100644 index 0000000..395af70 --- /dev/null +++ b/infra/core/host/container-apps.bicep @@ -0,0 +1,30 @@ +param name string +param location string = resourceGroup().location +param tags object = {} + +param containerAppsEnvironmentName string = '' +param containerRegistryName string = '' +param logAnalyticsWorkspaceName string = '' + +module containerAppsEnvironment 'container-apps-environment.bicep' = { + name: '${name}-container-apps-environment' + params: { + name: containerAppsEnvironmentName + location: location + tags: tags + logAnalyticsWorkspaceName: logAnalyticsWorkspaceName + } +} + +module containerRegistry 'container-registry.bicep' = { + name: '${name}-container-registry' + params: { + name: containerRegistryName + location: location + tags: tags + } +} + +output environmentName string = containerAppsEnvironment.outputs.name +output registryLoginServer string = containerRegistry.outputs.loginServer +output registryName string = containerRegistry.outputs.name From 7c0e198607389b5e000faab653a65c5287ebee44 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 14:42:41 +0000 Subject: [PATCH 17/24] Fix container apps --- infra/core/host/container-apps.bicep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/infra/core/host/container-apps.bicep b/infra/core/host/container-apps.bicep index 395af70..501d924 100644 --- a/infra/core/host/container-apps.bicep +++ b/infra/core/host/container-apps.bicep @@ -2,9 +2,9 @@ param name string param location string = resourceGroup().location param tags object = {} -param containerAppsEnvironmentName string = '' -param containerRegistryName string = '' -param logAnalyticsWorkspaceName string = '' +param containerAppsEnvironmentName string +param containerRegistryName string +param logAnalyticsWorkspaceName string module containerAppsEnvironment 'container-apps-environment.bicep' = { name: '${name}-container-apps-environment' From 6ce3fa3b0784d1ea71001f3ddffc85ce70cf7c96 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 14:49:11 +0000 Subject: [PATCH 18/24] Remove allowed --- infra/core/host/appservice.bicep | 3 --- 1 file changed, 3 deletions(-) diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep index a56fade..a846bf9 100644 --- a/infra/core/host/appservice.bicep +++ b/infra/core/host/appservice.bicep @@ -8,9 +8,6 @@ param appServicePlanId string param keyVaultName string = '' // Runtime Properties -@allowed([ - 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' -]) param runtimeName string param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' param runtimeVersion string From 05b52dd769cf9d202696e8cf59e08a1689fc2a27 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 14:56:16 +0000 Subject: [PATCH 19/24] Add json --- infra/core/host/functions.json | 409 +++++++++++++++++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 infra/core/host/functions.json diff --git a/infra/core/host/functions.json b/infra/core/host/functions.json new file mode 100644 index 0000000..c0789fb --- /dev/null +++ b/infra/core/host/functions.json @@ -0,0 +1,409 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "1219981596644994228" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "" + }, + "appServicePlanId": { + "type": "string" + }, + "keyVaultName": { + "type": "string", + "defaultValue": "" + }, + "managedIdentity": { + "type": "bool", + "defaultValue": "[not(empty(parameters('keyVaultName')))]" + }, + "storageAccountName": { + "type": "string" + }, + "runtimeName": { + "type": "string", + "allowedValues": [ + "dotnet", + "dotnetcore", + "dotnet-isolated", + "node", + "python", + "java", + "powershell", + "custom" + ] + }, + "runtimeNameAndVersion": { + "type": "string", + "defaultValue": "[format('{0}|{1}', parameters('runtimeName'), parameters('runtimeVersion'))]" + }, + "runtimeVersion": { + "type": "string" + }, + "extensionVersion": { + "type": "string", + "defaultValue": "~4", + "allowedValues": [ + "~4", + "~3", + "~2", + "~1" + ] + }, + "kind": { + "type": "string", + "defaultValue": "functionapp,linux" + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [] + }, + "alwaysOn": { + "type": "bool", + "defaultValue": true + }, + "appCommandLine": { + "type": "string", + "defaultValue": "" + }, + "appSettings": { + "type": "object", + "defaultValue": {} + }, + "clientAffinityEnabled": { + "type": "bool", + "defaultValue": false + }, + "enableOryxBuild": { + "type": "bool", + "defaultValue": "[contains(parameters('kind'), 'linux')]" + }, + "functionAppScaleLimit": { + "type": "int", + "defaultValue": -1 + }, + "linuxFxVersion": { + "type": "string", + "defaultValue": "[parameters('runtimeNameAndVersion')]" + }, + "minimumElasticInstanceCount": { + "type": "int", + "defaultValue": -1 + }, + "numberOfWorkers": { + "type": "int", + "defaultValue": -1 + }, + "scmDoBuildDuringDeployment": { + "type": "bool", + "defaultValue": true + }, + "use32BitWorkerProcess": { + "type": "bool", + "defaultValue": false + } + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2020-10-01", + "name": "[format('{0}-functions', parameters('name'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "allowedOrigins": { + "value": "[parameters('allowedOrigins')]" + }, + "alwaysOn": { + "value": "[parameters('alwaysOn')]" + }, + "appCommandLine": { + "value": "[parameters('appCommandLine')]" + }, + "applicationInsightsName": { + "value": "[parameters('applicationInsightsName')]" + }, + "appServicePlanId": { + "value": "[parameters('appServicePlanId')]" + }, + "appSettings": { + "value": "[union(parameters('appSettings'), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('storageAccountName'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value, environment().suffixes.storage), 'FUNCTIONS_EXTENSION_VERSION', parameters('extensionVersion'), 'FUNCTIONS_WORKER_RUNTIME', parameters('runtimeName')))]" + }, + "clientAffinityEnabled": { + "value": "[parameters('clientAffinityEnabled')]" + }, + "enableOryxBuild": { + "value": "[parameters('enableOryxBuild')]" + }, + "functionAppScaleLimit": { + "value": "[parameters('functionAppScaleLimit')]" + }, + "keyVaultName": { + "value": "[parameters('keyVaultName')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "linuxFxVersion": { + "value": "[parameters('linuxFxVersion')]" + }, + "minimumElasticInstanceCount": { + "value": "[parameters('minimumElasticInstanceCount')]" + }, + "numberOfWorkers": { + "value": "[parameters('numberOfWorkers')]" + }, + "runtimeName": { + "value": "[parameters('runtimeName')]" + }, + "runtimeVersion": { + "value": "[parameters('runtimeVersion')]" + }, + "runtimeNameAndVersion": { + "value": "[parameters('runtimeNameAndVersion')]" + }, + "scmDoBuildDuringDeployment": { + "value": "[parameters('scmDoBuildDuringDeployment')]" + }, + "use32BitWorkerProcess": { + "value": "[parameters('use32BitWorkerProcess')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.15.31.15270", + "templateHash": "7338301272393773865" + } + }, + "parameters": { + "name": { + "type": "string" + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]" + }, + "tags": { + "type": "object", + "defaultValue": {} + }, + "applicationInsightsName": { + "type": "string", + "defaultValue": "" + }, + "appServicePlanId": { + "type": "string" + }, + "keyVaultName": { + "type": "string", + "defaultValue": "" + }, + "runtimeName": { + "type": "string" + }, + "runtimeNameAndVersion": { + "type": "string", + "defaultValue": "[format('{0}|{1}', parameters('runtimeName'), parameters('runtimeVersion'))]" + }, + "runtimeVersion": { + "type": "string" + }, + "kind": { + "type": "string", + "defaultValue": "app,linux" + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [] + }, + "alwaysOn": { + "type": "bool", + "defaultValue": true + }, + "appCommandLine": { + "type": "string", + "defaultValue": "" + }, + "appSettings": { + "type": "object", + "defaultValue": {} + }, + "clientAffinityEnabled": { + "type": "bool", + "defaultValue": false + }, + "enableOryxBuild": { + "type": "bool", + "defaultValue": "[contains(parameters('kind'), 'linux')]" + }, + "functionAppScaleLimit": { + "type": "int", + "defaultValue": -1 + }, + "linuxFxVersion": { + "type": "string", + "defaultValue": "[parameters('runtimeNameAndVersion')]" + }, + "minimumElasticInstanceCount": { + "type": "int", + "defaultValue": -1 + }, + "numberOfWorkers": { + "type": "int", + "defaultValue": -1 + }, + "scmDoBuildDuringDeployment": { + "type": "bool", + "defaultValue": false + }, + "use32BitWorkerProcess": { + "type": "bool", + "defaultValue": false + }, + "ftpsState": { + "type": "string", + "defaultValue": "FtpsOnly" + }, + "healthCheckPath": { + "type": "string", + "defaultValue": "" + } + }, + "resources": [ + { + "type": "Microsoft.Web/sites/config", + "apiVersion": "2022-03-01", + "name": "[format('{0}/{1}', parameters('name'), 'appsettings')]", + "properties": "[union(parameters('appSettings'), createObject('SCM_DO_BUILD_DURING_DEPLOYMENT', string(parameters('scmDoBuildDuringDeployment')), 'ENABLE_ORYX_BUILD', string(parameters('enableOryxBuild'))), if(not(empty(parameters('applicationInsightsName'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString), createObject()), if(not(empty(parameters('keyVaultName'))), createObject('AZURE_KEY_VAULT_ENDPOINT', reference(resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), '2022-07-01').vaultUri), createObject()))]", + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', parameters('name'))]" + ] + }, + { + "type": "Microsoft.Web/sites/config", + "apiVersion": "2022-03-01", + "name": "[format('{0}/{1}', parameters('name'), 'logs')]", + "properties": { + "applicationLogs": { + "fileSystem": { + "level": "Verbose" + } + }, + "detailedErrorMessages": { + "enabled": true + }, + "failedRequestsTracing": { + "enabled": true + }, + "httpLogs": { + "fileSystem": { + "enabled": true, + "retentionInDays": 1, + "retentionInMb": 35 + } + } + }, + "dependsOn": [ + "[resourceId('Microsoft.Web/sites', parameters('name'))]", + "[resourceId('Microsoft.Web/sites/config', parameters('name'), 'appsettings')]" + ] + }, + { + "type": "Microsoft.Web/sites", + "apiVersion": "2022-03-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "serverFarmId": "[parameters('appServicePlanId')]", + "siteConfig": { + "linuxFxVersion": "[parameters('linuxFxVersion')]", + "alwaysOn": "[parameters('alwaysOn')]", + "ftpsState": "[parameters('ftpsState')]", + "minTlsVersion": "1.2", + "appCommandLine": "[parameters('appCommandLine')]", + "numberOfWorkers": "[if(not(equals(parameters('numberOfWorkers'), -1)), parameters('numberOfWorkers'), null())]", + "minimumElasticInstanceCount": "[if(not(equals(parameters('minimumElasticInstanceCount'), -1)), parameters('minimumElasticInstanceCount'), null())]", + "use32BitWorkerProcess": "[parameters('use32BitWorkerProcess')]", + "functionAppScaleLimit": "[if(not(equals(parameters('functionAppScaleLimit'), -1)), parameters('functionAppScaleLimit'), null())]", + "healthCheckPath": "[parameters('healthCheckPath')]", + "cors": { + "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" + } + }, + "clientAffinityEnabled": "[parameters('clientAffinityEnabled')]", + "httpsOnly": true + }, + "identity": { + "type": "SystemAssigned" + } + } + ], + "outputs": { + "identityPrincipalId": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01', 'full').identity.principalId]" + }, + "name": { + "type": "string", + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "value": "[format('https://{0}', reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01').defaultHostName)]" + } + } + } + } + } + ], + "outputs": { + "identityPrincipalId": { + "type": "string", + "value": "[if(parameters('managedIdentity'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-functions', parameters('name'))), '2020-10-01').outputs.identityPrincipalId.value, '')]" + }, + "name": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-functions', parameters('name'))), '2020-10-01').outputs.name.value]" + }, + "uri": { + "type": "string", + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-functions', parameters('name'))), '2020-10-01').outputs.uri.value]" + } + } +} \ No newline at end of file From 028cca68a0a349ea0d926982d9aacd595f7402bc Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 16:51:37 +0000 Subject: [PATCH 20/24] Rm functions.json --- infra/core/host/functions.json | 409 --------------------------------- 1 file changed, 409 deletions(-) delete mode 100644 infra/core/host/functions.json diff --git a/infra/core/host/functions.json b/infra/core/host/functions.json deleted file mode 100644 index c0789fb..0000000 --- a/infra/core/host/functions.json +++ /dev/null @@ -1,409 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.15.31.15270", - "templateHash": "1219981596644994228" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "applicationInsightsName": { - "type": "string", - "defaultValue": "" - }, - "appServicePlanId": { - "type": "string" - }, - "keyVaultName": { - "type": "string", - "defaultValue": "" - }, - "managedIdentity": { - "type": "bool", - "defaultValue": "[not(empty(parameters('keyVaultName')))]" - }, - "storageAccountName": { - "type": "string" - }, - "runtimeName": { - "type": "string", - "allowedValues": [ - "dotnet", - "dotnetcore", - "dotnet-isolated", - "node", - "python", - "java", - "powershell", - "custom" - ] - }, - "runtimeNameAndVersion": { - "type": "string", - "defaultValue": "[format('{0}|{1}', parameters('runtimeName'), parameters('runtimeVersion'))]" - }, - "runtimeVersion": { - "type": "string" - }, - "extensionVersion": { - "type": "string", - "defaultValue": "~4", - "allowedValues": [ - "~4", - "~3", - "~2", - "~1" - ] - }, - "kind": { - "type": "string", - "defaultValue": "functionapp,linux" - }, - "allowedOrigins": { - "type": "array", - "defaultValue": [] - }, - "alwaysOn": { - "type": "bool", - "defaultValue": true - }, - "appCommandLine": { - "type": "string", - "defaultValue": "" - }, - "appSettings": { - "type": "object", - "defaultValue": {} - }, - "clientAffinityEnabled": { - "type": "bool", - "defaultValue": false - }, - "enableOryxBuild": { - "type": "bool", - "defaultValue": "[contains(parameters('kind'), 'linux')]" - }, - "functionAppScaleLimit": { - "type": "int", - "defaultValue": -1 - }, - "linuxFxVersion": { - "type": "string", - "defaultValue": "[parameters('runtimeNameAndVersion')]" - }, - "minimumElasticInstanceCount": { - "type": "int", - "defaultValue": -1 - }, - "numberOfWorkers": { - "type": "int", - "defaultValue": -1 - }, - "scmDoBuildDuringDeployment": { - "type": "bool", - "defaultValue": true - }, - "use32BitWorkerProcess": { - "type": "bool", - "defaultValue": false - } - }, - "resources": [ - { - "type": "Microsoft.Resources/deployments", - "apiVersion": "2020-10-01", - "name": "[format('{0}-functions', parameters('name'))]", - "properties": { - "expressionEvaluationOptions": { - "scope": "inner" - }, - "mode": "Incremental", - "parameters": { - "name": { - "value": "[parameters('name')]" - }, - "location": { - "value": "[parameters('location')]" - }, - "tags": { - "value": "[parameters('tags')]" - }, - "allowedOrigins": { - "value": "[parameters('allowedOrigins')]" - }, - "alwaysOn": { - "value": "[parameters('alwaysOn')]" - }, - "appCommandLine": { - "value": "[parameters('appCommandLine')]" - }, - "applicationInsightsName": { - "value": "[parameters('applicationInsightsName')]" - }, - "appServicePlanId": { - "value": "[parameters('appServicePlanId')]" - }, - "appSettings": { - "value": "[union(parameters('appSettings'), createObject('AzureWebJobsStorage', format('DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1};EndpointSuffix={2}', parameters('storageAccountName'), listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2021-09-01').keys[0].value, environment().suffixes.storage), 'FUNCTIONS_EXTENSION_VERSION', parameters('extensionVersion'), 'FUNCTIONS_WORKER_RUNTIME', parameters('runtimeName')))]" - }, - "clientAffinityEnabled": { - "value": "[parameters('clientAffinityEnabled')]" - }, - "enableOryxBuild": { - "value": "[parameters('enableOryxBuild')]" - }, - "functionAppScaleLimit": { - "value": "[parameters('functionAppScaleLimit')]" - }, - "keyVaultName": { - "value": "[parameters('keyVaultName')]" - }, - "kind": { - "value": "[parameters('kind')]" - }, - "linuxFxVersion": { - "value": "[parameters('linuxFxVersion')]" - }, - "minimumElasticInstanceCount": { - "value": "[parameters('minimumElasticInstanceCount')]" - }, - "numberOfWorkers": { - "value": "[parameters('numberOfWorkers')]" - }, - "runtimeName": { - "value": "[parameters('runtimeName')]" - }, - "runtimeVersion": { - "value": "[parameters('runtimeVersion')]" - }, - "runtimeNameAndVersion": { - "value": "[parameters('runtimeNameAndVersion')]" - }, - "scmDoBuildDuringDeployment": { - "value": "[parameters('scmDoBuildDuringDeployment')]" - }, - "use32BitWorkerProcess": { - "value": "[parameters('use32BitWorkerProcess')]" - } - }, - "template": { - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", - "contentVersion": "1.0.0.0", - "metadata": { - "_generator": { - "name": "bicep", - "version": "0.15.31.15270", - "templateHash": "7338301272393773865" - } - }, - "parameters": { - "name": { - "type": "string" - }, - "location": { - "type": "string", - "defaultValue": "[resourceGroup().location]" - }, - "tags": { - "type": "object", - "defaultValue": {} - }, - "applicationInsightsName": { - "type": "string", - "defaultValue": "" - }, - "appServicePlanId": { - "type": "string" - }, - "keyVaultName": { - "type": "string", - "defaultValue": "" - }, - "runtimeName": { - "type": "string" - }, - "runtimeNameAndVersion": { - "type": "string", - "defaultValue": "[format('{0}|{1}', parameters('runtimeName'), parameters('runtimeVersion'))]" - }, - "runtimeVersion": { - "type": "string" - }, - "kind": { - "type": "string", - "defaultValue": "app,linux" - }, - "allowedOrigins": { - "type": "array", - "defaultValue": [] - }, - "alwaysOn": { - "type": "bool", - "defaultValue": true - }, - "appCommandLine": { - "type": "string", - "defaultValue": "" - }, - "appSettings": { - "type": "object", - "defaultValue": {} - }, - "clientAffinityEnabled": { - "type": "bool", - "defaultValue": false - }, - "enableOryxBuild": { - "type": "bool", - "defaultValue": "[contains(parameters('kind'), 'linux')]" - }, - "functionAppScaleLimit": { - "type": "int", - "defaultValue": -1 - }, - "linuxFxVersion": { - "type": "string", - "defaultValue": "[parameters('runtimeNameAndVersion')]" - }, - "minimumElasticInstanceCount": { - "type": "int", - "defaultValue": -1 - }, - "numberOfWorkers": { - "type": "int", - "defaultValue": -1 - }, - "scmDoBuildDuringDeployment": { - "type": "bool", - "defaultValue": false - }, - "use32BitWorkerProcess": { - "type": "bool", - "defaultValue": false - }, - "ftpsState": { - "type": "string", - "defaultValue": "FtpsOnly" - }, - "healthCheckPath": { - "type": "string", - "defaultValue": "" - } - }, - "resources": [ - { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-03-01", - "name": "[format('{0}/{1}', parameters('name'), 'appsettings')]", - "properties": "[union(parameters('appSettings'), createObject('SCM_DO_BUILD_DURING_DEPLOYMENT', string(parameters('scmDoBuildDuringDeployment')), 'ENABLE_ORYX_BUILD', string(parameters('enableOryxBuild'))), if(not(empty(parameters('applicationInsightsName'))), createObject('APPLICATIONINSIGHTS_CONNECTION_STRING', reference(resourceId('Microsoft.Insights/components', parameters('applicationInsightsName')), '2020-02-02').ConnectionString), createObject()), if(not(empty(parameters('keyVaultName'))), createObject('AZURE_KEY_VAULT_ENDPOINT', reference(resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName')), '2022-07-01').vaultUri), createObject()))]", - "dependsOn": [ - "[resourceId('Microsoft.Web/sites', parameters('name'))]" - ] - }, - { - "type": "Microsoft.Web/sites/config", - "apiVersion": "2022-03-01", - "name": "[format('{0}/{1}', parameters('name'), 'logs')]", - "properties": { - "applicationLogs": { - "fileSystem": { - "level": "Verbose" - } - }, - "detailedErrorMessages": { - "enabled": true - }, - "failedRequestsTracing": { - "enabled": true - }, - "httpLogs": { - "fileSystem": { - "enabled": true, - "retentionInDays": 1, - "retentionInMb": 35 - } - } - }, - "dependsOn": [ - "[resourceId('Microsoft.Web/sites', parameters('name'))]", - "[resourceId('Microsoft.Web/sites/config', parameters('name'), 'appsettings')]" - ] - }, - { - "type": "Microsoft.Web/sites", - "apiVersion": "2022-03-01", - "name": "[parameters('name')]", - "location": "[parameters('location')]", - "tags": "[parameters('tags')]", - "kind": "[parameters('kind')]", - "properties": { - "serverFarmId": "[parameters('appServicePlanId')]", - "siteConfig": { - "linuxFxVersion": "[parameters('linuxFxVersion')]", - "alwaysOn": "[parameters('alwaysOn')]", - "ftpsState": "[parameters('ftpsState')]", - "minTlsVersion": "1.2", - "appCommandLine": "[parameters('appCommandLine')]", - "numberOfWorkers": "[if(not(equals(parameters('numberOfWorkers'), -1)), parameters('numberOfWorkers'), null())]", - "minimumElasticInstanceCount": "[if(not(equals(parameters('minimumElasticInstanceCount'), -1)), parameters('minimumElasticInstanceCount'), null())]", - "use32BitWorkerProcess": "[parameters('use32BitWorkerProcess')]", - "functionAppScaleLimit": "[if(not(equals(parameters('functionAppScaleLimit'), -1)), parameters('functionAppScaleLimit'), null())]", - "healthCheckPath": "[parameters('healthCheckPath')]", - "cors": { - "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" - } - }, - "clientAffinityEnabled": "[parameters('clientAffinityEnabled')]", - "httpsOnly": true - }, - "identity": { - "type": "SystemAssigned" - } - } - ], - "outputs": { - "identityPrincipalId": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01', 'full').identity.principalId]" - }, - "name": { - "type": "string", - "value": "[parameters('name')]" - }, - "uri": { - "type": "string", - "value": "[format('https://{0}', reference(resourceId('Microsoft.Web/sites', parameters('name')), '2022-03-01').defaultHostName)]" - } - } - } - } - } - ], - "outputs": { - "identityPrincipalId": { - "type": "string", - "value": "[if(parameters('managedIdentity'), reference(resourceId('Microsoft.Resources/deployments', format('{0}-functions', parameters('name'))), '2020-10-01').outputs.identityPrincipalId.value, '')]" - }, - "name": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-functions', parameters('name'))), '2020-10-01').outputs.name.value]" - }, - "uri": { - "type": "string", - "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-functions', parameters('name'))), '2020-10-01').outputs.uri.value]" - } - } -} \ No newline at end of file From af0f94d6619f8f3e66b7eee21f8936a44b491015 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 16:58:59 +0000 Subject: [PATCH 21/24] Bring back managed identity --- infra/core/host/functions.bicep | 1 + 1 file changed, 1 insertion(+) diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index f841adc..28a581b 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -62,6 +62,7 @@ module functions 'appservice.bicep' = { keyVaultName: keyVaultName kind: kind linuxFxVersion: linuxFxVersion + managedIdentity: managedIdentity minimumElasticInstanceCount: minimumElasticInstanceCount numberOfWorkers: numberOfWorkers runtimeName: runtimeName From 0726037ced889b303cddd09271552ce87bbf1d9c Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 17:04:45 +0000 Subject: [PATCH 22/24] Bring back allowed --- infra/core/host/appservice.bicep | 3 +++ infra/core/host/functions.bicep | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep index a846bf9..a56fade 100644 --- a/infra/core/host/appservice.bicep +++ b/infra/core/host/appservice.bicep @@ -8,6 +8,9 @@ param appServicePlanId string param keyVaultName string = '' // Runtime Properties +@allowed([ + 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' +]) param runtimeName string param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' param runtimeVersion string diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index 28a581b..f841adc 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -62,7 +62,6 @@ module functions 'appservice.bicep' = { keyVaultName: keyVaultName kind: kind linuxFxVersion: linuxFxVersion - managedIdentity: managedIdentity minimumElasticInstanceCount: minimumElasticInstanceCount numberOfWorkers: numberOfWorkers runtimeName: runtimeName From 123484dbb8ed68e9036f4d6deafd7c76170543e9 Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 17:19:34 +0000 Subject: [PATCH 23/24] Specify a param --- infra/core/host/functions.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index f841adc..eee5e88 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -13,7 +13,7 @@ param storageAccountName string @allowed([ 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' ]) -param runtimeName string +param runtimeName string = 'custom' param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' param runtimeVersion string From 236a5ade5cc1fc4d590684da44de58ec647394ee Mon Sep 17 00:00:00 2001 From: Pamela Fox Date: Wed, 22 Mar 2023 17:28:37 +0000 Subject: [PATCH 24/24] Specifying doesnt help --- infra/core/host/functions.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep index eee5e88..f841adc 100644 --- a/infra/core/host/functions.bicep +++ b/infra/core/host/functions.bicep @@ -13,7 +13,7 @@ param storageAccountName string @allowed([ 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' ]) -param runtimeName string = 'custom' +param runtimeName string param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' param runtimeVersion string