From 159bad87d1b27c4d2b5d861bdf78cc6c634f4a0c Mon Sep 17 00:00:00 2001 From: Yunge Zhu Date: Wed, 1 Feb 2023 15:56:02 +0800 Subject: [PATCH] add serviceconnector --- infra/app/api.bicep | 11 ++++ infra/app/db.bicep | 1 + infra/core/database/sqlserver/sqlserver.bicep | 10 +-- infra/core/host/appservice.bicep | 65 ++++++++++++++++++- infra/main.bicep | 15 ++--- 5 files changed, 81 insertions(+), 21 deletions(-) diff --git a/infra/app/api.bicep b/infra/app/api.bicep index 55954f1e..213c1faa 100644 --- a/infra/app/api.bicep +++ b/infra/app/api.bicep @@ -10,6 +10,13 @@ param appSettings object = {} param keyVaultName string param serviceName string = 'api' +// Target DB properties +param connectionStringKey string = '' +param targetResourceId string = '' +param appUser string = '' +@secure() +param appUserPassword string + module api '../core/host/appservice.bicep' = { name: '${name}-app-module' params: { @@ -25,6 +32,10 @@ module api '../core/host/appservice.bicep' = { runtimeName: 'dotnetcore' runtimeVersion: '6.0' scmDoBuildDuringDeployment: false + targetResourceId: targetResourceId + appUser: appUser + appUserPassword: appUserPassword + connectionStringKey: connectionStringKey } } diff --git a/infra/app/db.bicep b/infra/app/db.bicep index a21cc0ff..add48c21 100644 --- a/infra/app/db.bicep +++ b/infra/app/db.bicep @@ -29,3 +29,4 @@ module sqlServer '../core/database/sqlserver/sqlserver.bicep' = { output connectionStringKey string = sqlServer.outputs.connectionStringKey output databaseName string = sqlServer.outputs.databaseName +output id string = sqlServer.outputs.id diff --git a/infra/core/database/sqlserver/sqlserver.bicep b/infra/core/database/sqlserver/sqlserver.bicep index 821a9087..6dff5025 100644 --- a/infra/core/database/sqlserver/sqlserver.bicep +++ b/infra/core/database/sqlserver/sqlserver.bicep @@ -112,18 +112,10 @@ resource appUserPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = } } -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 +output id string = sqlServer.id diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep index 62e34a65..26d3ea7f 100644 --- a/infra/core/host/appservice.bicep +++ b/infra/core/host/appservice.bicep @@ -33,6 +33,13 @@ param numberOfWorkers int = -1 param scmDoBuildDuringDeployment bool = false param use32BitWorkerProcess bool = false +// Target DB properties +param connectionStringKey string = 'AZURE-SQL-CONNECTION-STRING' +param targetResourceId string = '' +param appUser string = '' +@secure() +param appUserPassword string = '' + resource appService 'Microsoft.Web/sites@2022-03-01' = { name: name location: location @@ -66,8 +73,7 @@ resource appService 'Microsoft.Web/sites@2022-03-01' = { SCM_DO_BUILD_DURING_DEPLOYMENT: string(scmDoBuildDuringDeployment) ENABLE_ORYX_BUILD: string(enableOryxBuild) }, - !empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {}, - !empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault.properties.vaultUri } : {}) + !empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {}) } resource configLogs 'config' = { @@ -92,6 +98,61 @@ resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing name: applicationInsightsName } +// if !empty(keyVaultName), create connection to keyvault so that db credentials could be saved into keyvault, +// and app service could retrieve secrets from keyvault using managed identity +resource connectionToKeyVault 'Microsoft.ServiceLinker/linkers@2022-11-01-preview' = if(!empty(keyVaultName)) { + name: 'conn_kv' + scope: appService + properties: { + targetService: { + id: keyVault.id + type: 'AzureResource' + } + clientType: 'none' + authInfo: { + authType: 'systemAssignedIdentity' + roles: [ + '4633458b-17de-408a-b874-0445c86b69e6' + ] + } + configurationInfo: { + customizedKeys: { + 'AZURE_KEYVAULT_RESOURCEENDPOINT': 'AZURE_KEY_VAULT_ENDPOINT' + } + } + } +} + +// if !empty(targetResourceId), create connection to target database, including: +// - add db connectionstr (from keyvault if applicable) in webapp appsettings or connectionString(for dotnetcore convention) +// - allow webapp firewall at target database if applicable (target allows firewall instead of public access) +resource connectionToTargetDB 'Microsoft.ServiceLinker/linkers@2022-11-01-preview' = if (!empty(targetResourceId)) { + name: 'conn_db' + scope: appService + properties: { + targetService: { + id: targetResourceId + type: 'AzureResource' + } + secretStore: { + keyVaultId: !empty(keyVaultName) ? keyVault.id : '' + keyVaultSecretName: !empty(keyVaultName) ? connectionStringKey : '' + } + authInfo: { + authType: 'secret' + name: appUser + secretInfo: { + secretType: 'rawValue' + value: appUserPassword + } + } + clientType: 'dotnet' + } + dependsOn: [ + connectionToKeyVault + ] +} + output identityPrincipalId string = managedIdentity ? appService.identity.principalId : '' output name string = appService.name output uri string = 'https://${appService.properties.defaultHostName}' diff --git a/infra/main.bicep b/infra/main.bicep index f78e41dd..8e154b6f 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -24,6 +24,7 @@ param sqlServerName string = '' param sqlDatabaseName string = '' param webServiceName string = '' param apimServiceName string = '' +param appUser string = 'appUser' @description('Flag to use Azure API Management to mediate the calls between the Web frontend and the backend API') param useAPIM bool = false @@ -78,16 +79,10 @@ module api './app/api.bicep' = { appSettings: { AZURE_SQL_CONNECTION_STRING_KEY: sqlServer.outputs.connectionStringKey } - } -} - -// Give the API access to KeyVault -module apiKeyVaultAccess './core/security/keyvault-access.bicep' = { - name: 'api-keyvault-access' - scope: rg - params: { - keyVaultName: keyVault.outputs.name - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID + targetResourceId: '${sqlServer.outputs.id}/databases/${sqlServer.outputs.databaseName}' + appUser: appUser + appUserPassword: appUserPassword + connectionStringKey: sqlServer.outputs.connectionStringKey } }