diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a8db954c1..7640f2547 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,6 +25,9 @@ jobs: AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + AZURE_PRINCIPAL_ID: ${{ secrets.AZURE_PRINCIPAL_ID }} + AZURE_PRINCIPAL_NAME: ${{ secrets.AZURE_PRINCIPAL_NAME }} + AZURE_PRINCIPAL_TYPE: 'ServicePrincipal' outputs: imageTag: ${{ steps.set-image-tag.outputs.imageTag }} @@ -203,6 +206,9 @@ jobs: DISABLE_AUTHENTICATION=true NO_AUTH=true SKIP_AUTH=true + AZURE_PRINCIPAL_ID + AZURE_PRINCIPAL_NAME + AZURE_PRINCIPAL_TYPE - name: Extract URLs from deployment id: extract-urls @@ -299,8 +305,6 @@ jobs: echo "=== PostgreSQL Configuration Summary ===" echo "Host Endpoint: $PG_HOST_DESTINATION" - echo "Username: admintest (hardcoded)" - echo "Password: Initial_0524 (hardcoded)" echo "Database: postgres (hardcoded)" echo "Port: 5432 (hardcoded)" @@ -311,19 +315,28 @@ jobs: - name: Install Python dependencies run: | - pip install psycopg2-binary python-dotenv - + pip install psycopg2-binary python-dotenv azure-identity - name: Populate PostgreSQL Database run: | python - <` and `` with your actual Function App name and function key +4. Locate the environment variables _AZURE_FUNCTION_URL_ and _AZURE_APP_API_BASE_URL_. +5. Replace the `` and `` with your actual Function App name and function key, and replace `` with your actual App Service name ```env AZURE_FUNCTION_URL=https://.azurewebsites.net/api/GetConversationResponse?code= - + AZURE_APP_API_BASE_URL=https://.azurewebsites.net/ ``` ![Env](images/teams-deploy-env.png) 6. Save the file. diff --git a/extensions/teams/cards/cardBuilder.ts b/extensions/teams/cards/cardBuilder.ts index 13d73e274..c22085039 100644 --- a/extensions/teams/cards/cardBuilder.ts +++ b/extensions/teams/cards/cardBuilder.ts @@ -1,11 +1,12 @@ import { Attachment, CardFactory } from "botbuilder"; import { Citation, CardType } from "../model"; +import config from "../config"; export function actionBuilder(citation: Citation, docId: number): any { - const urlParts = citation.url.split("]"); - let url = urlParts[urlParts.length - 1].replaceAll("(", "").replaceAll(")", ""); let title = citation.title.replaceAll("/documents/", ""); + const filename = title; + let fileApiUrl = `${config.getFileEndpoint}/${filename}`; let content = citation.content.replaceAll(citation.title, "").replaceAll("url", ""); content = content.replaceAll(/(<([^>]+)>)/ig, "\n").replaceAll("<>", ""); let citationCardAction = { @@ -37,7 +38,7 @@ export function actionBuilder(citation: Citation, docId: number): any { { type: CardType.OpenUrl, title: "Go to the source", - url: decodeURI(url), + url: decodeURI(fileApiUrl), } ] } diff --git a/extensions/teams/config.ts b/extensions/teams/config.ts index 8330fc537..9298ecacf 100644 --- a/extensions/teams/config.ts +++ b/extensions/teams/config.ts @@ -2,7 +2,11 @@ const config = { botId: process.env.BOT_ID, botPassword: process.env.BOT_PASSWORD, azureFunctionUrl: process.env.AZURE_FUNCTION_URL, + azureAppApiBaseUrl: process.env.AZURE_APP_API_BASE_URL, tenantId: process.env.TEAMS_APP_TENANT_ID, + getFileEndpoint: process.env.AZURE_APP_API_BASE_URL ? + `${process.env.AZURE_APP_API_BASE_URL}api/files` : + null, }; export default config; diff --git a/extensions/teams/env/.env.dev b/extensions/teams/env/.env.dev index f391f611b..76ef4cf7a 100644 --- a/extensions/teams/env/.env.dev +++ b/extensions/teams/env/.env.dev @@ -14,4 +14,5 @@ BOT_ID= TEAMS_APP_ID= BOT_AZURE_APP_SERVICE_RESOURCE_ID= BOT_DOMAIN= -AZURE_FUNCTION_URL=https://backend-.azurewebsites.net/api/GetConversationResponse?code=&clientId=clientKey +AZURE_FUNCTION_URL=https://.azurewebsites.net/api/GetConversationResponse?code= +AZURE_APP_API_BASE_URL=https://.azurewebsites.net/ diff --git a/extensions/teams/env/.env.test b/extensions/teams/env/.env.test index a9770c383..130b0fb69 100644 --- a/extensions/teams/env/.env.test +++ b/extensions/teams/env/.env.test @@ -14,6 +14,7 @@ BOT_ID= TEAMS_APP_ID= BOT_AZURE_APP_SERVICE_RESOURCE_ID= BOT_DOMAIN= -AZURE_FUNCTION_URL=https://backend-.azurewebsites.net/api/GetConversationResponse?code=&clientId=clientKey +AZURE_FUNCTION_URL=https://.azurewebsites.net/api/GetConversationResponse?code= +AZURE_APP_API_BASE_URL=https://.azurewebsites.net/ TEAMS_APP_TENANT_ID= TEAMS_APP_PUBLISHED_APP_ID= diff --git a/extensions/teams/env/.env.testtool b/extensions/teams/env/.env.testtool index e98ad3918..236eea70a 100644 --- a/extensions/teams/env/.env.testtool +++ b/extensions/teams/env/.env.testtool @@ -6,4 +6,5 @@ TEAMSFX_ENV=testtool # Environment variables used by test tool TEAMSAPPTESTER_PORT=56150 TEAMSFX_NOTIFICATION_STORE_FILENAME=.notification.testtoolstore.json -AZURE_FUNCTION_URL=https://backend-.azurewebsites.net/api/GetConversationResponse?code=&clientId=clientKey +AZURE_FUNCTION_URL=https://.azurewebsites.net/api/GetConversationResponse?code= +AZURE_APP_API_BASE_URL=https://.azurewebsites.net/ diff --git a/extensions/teams/index.ts b/extensions/teams/index.ts index 3eae007b8..d0b16d72a 100644 --- a/extensions/teams/index.ts +++ b/extensions/teams/index.ts @@ -19,7 +19,7 @@ import config from "./config"; const credentialsFactory = new ConfigurationServiceClientCredentialFactory({ MicrosoftAppId: config.botId, MicrosoftAppPassword: config.botPassword, - MicrosoftAppType: "SingleTenant", + MicrosoftAppType: "SingleTenant", // Enable multitenant mode for local development MicrosoftAppTenantId: config.tenantId }); diff --git a/extensions/teams/infra/azure.bicep b/extensions/teams/infra/azure.bicep index b5b57237f..5471b10bf 100644 --- a/extensions/teams/infra/azure.bicep +++ b/extensions/teams/infra/azure.bicep @@ -17,6 +17,9 @@ param botAadAppClientSecret string @description('Required by Bot Framework azureFunctionURL') param azureFunctionURL string +@description('Base URL for the Azure Web App API endpoints used for file access') +param azureAppApiBaseUrl string + param webAppSKU string @maxLength(42) @@ -72,6 +75,10 @@ resource webApp 'Microsoft.Web/sites@2021-02-01' = { name: 'AZURE_FUNCTION_URL' value: azureFunctionURL } + { + name: 'AZURE_APP_API_BASE_URL' + value: azureAppApiBaseUrl + } { name: 'TEAMS_APP_TENANT_ID' value: botAadAppTenantId diff --git a/extensions/teams/infra/azure.parameters.json b/extensions/teams/infra/azure.parameters.json index c342ec592..987093289 100644 --- a/extensions/teams/infra/azure.parameters.json +++ b/extensions/teams/infra/azure.parameters.json @@ -17,6 +17,9 @@ "azureFunctionURL": { "value": "${{AZURE_FUNCTION_URL}}" }, + "azureAppApiBaseUrl": { + "value": "${{AZURE_APP_API_BASE_URL}}" + }, "webAppSKU": { "value": "B1" }, @@ -24,4 +27,4 @@ "value": "teams-bot-toolkit" } } -} \ No newline at end of file +} diff --git a/extensions/teams/teamsapp.local.yml b/extensions/teams/teamsapp.local.yml index 7572ae882..d38c1113b 100644 --- a/extensions/teams/teamsapp.local.yml +++ b/extensions/teams/teamsapp.local.yml @@ -25,6 +25,14 @@ provision: # The Microsoft Entra application's client secret created for bot. botPassword: SECRET_BOT_PASSWORD + # Create service principal for the Microsoft Entra application + - uses: cli/runNpmCommand + name: Enable Service Principal + with: + args: run enable-sp + env: + BOT_ID: ${{BOT_ID}} + # Create or update the bot registration on dev.botframework.com - uses: botFramework/create with: @@ -76,4 +84,6 @@ deploy: envs: BOT_ID: ${{BOT_ID}} BOT_PASSWORD: ${{SECRET_BOT_PASSWORD}} + TEAMS_APP_TENANT_ID: ${{TEAMS_APP_TENANT_ID}} AZURE_FUNCTION_URL: ${{AZURE_FUNCTION_URL}} + AZURE_APP_API_BASE_URL: ${{AZURE_APP_API_BASE_URL}} diff --git a/extensions/teams/teamsapp.testtool.yml b/extensions/teams/teamsapp.testtool.yml index 0f9c03103..1a0e1e4b9 100644 --- a/extensions/teams/teamsapp.testtool.yml +++ b/extensions/teams/teamsapp.testtool.yml @@ -22,4 +22,5 @@ deploy: target: ./.localConfigs.testTool envs: TEAMSFX_NOTIFICATION_STORE_FILENAME: ${{TEAMSFX_NOTIFICATION_STORE_FILENAME}} - AZURE_FUNCTION_URL: ${{AZURE_FUNCTION_URL}} \ No newline at end of file + AZURE_FUNCTION_URL: ${{AZURE_FUNCTION_URL}} + AZURE_APP_API_BASE_URL: ${{AZURE_APP_API_BASE_URL}} diff --git a/infra/main.bicep b/infra/main.bicep index e1141271f..4742cbbfb 100644 --- a/infra/main.bicep +++ b/infra/main.bicep @@ -9,13 +9,15 @@ param solutionName string = 'cwyd' @description('Optional. A unique text value for the solution. This is used to ensure resource names are unique for global resources. Defaults to a 5-character substring of the unique string generated from the subscription ID, resource group name, and solution name.') param solutionUniqueText string = take(uniqueString(subscription().id, resourceGroup().name, solutionName), 5) -@description('Optional. Location for all resources, if you are using existing resource group provide the location of the resorce group.') -@metadata({ - azd: { - type: 'location' - } -}) -param location string = resourceGroup().location +@allowed([ + 'australiaeast' + 'eastus2' + 'japaneast' + 'uksouth' +]) +@metadata({ azd: { type: 'location' } }) +@description('Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions).') +param location string @description('Optional. Existing Log Analytics Workspace Resource ID.') param existingLogAnalyticsWorkspaceId string = '' @@ -185,7 +187,7 @@ param azureOpenAITopP string = '1' param azureOpenAIMaxTokens string = '1000' @description('Optional. Azure OpenAI Stop Sequence.') -param azureOpenAIStopSequence string = '\n' +param azureOpenAIStopSequence string = '\\n' @description('Optional. Azure OpenAI System Message.') param azureOpenAISystemMessage string = 'You are an AI assistant that helps people find information.' @@ -284,8 +286,12 @@ var logAnalyticsName string = 'log-${solutionSuffix}' @description('Optional. A new GUID string generated for this deployment. This can be used for unique naming if needed.') param newGuidString string = newGuid() -@description('Optional. Id of the user or app to assign application roles.') -param principalId string = '' +@description('Optional. Principal object for user or service principal to assign application roles. Format: {"id":"", "name":"", "type":"User|Group|ServicePrincipal"}') +param principal object = { + id: '' // Principal ID + name: '' // Principal name + type: 'User' // Principal type ('User', 'Group', or 'ServicePrincipal') +} @description('Optional. Application Environment.') param appEnvironment string = 'Prod' @@ -647,15 +653,26 @@ module postgresDBModule 'br/public:avm/res/db-for-postgre-sql/flexible-server:0. ] : [] - administrators: managedIdentityModule.outputs.principalId != '' - ? [ - { - objectId: managedIdentityModule.outputs.principalId - principalName: managedIdentityModule.outputs.name - principalType: 'ServicePrincipal' - } - ] - : null + administrators: concat( + managedIdentityModule.outputs.principalId != '' + ? [ + { + objectId: managedIdentityModule.outputs.principalId + principalName: managedIdentityModule.outputs.name + principalType: 'ServicePrincipal' + } + ] + : [], + !empty(principal.id) + ? [ + { + objectId: principal.id + principalName: principal.name + principalType: principal.type + } + ] + : [] + ) firewallRules: enablePrivateNetworking ? [] @@ -756,10 +773,10 @@ module keyvault './modules/key-vault/vault/vault.bicep' = { } ] : [], - principalId != '' + !empty(principal.id) ? [ { - principalId: principalId + principalId: principal.id roleDefinitionIdOrName: 'Key Vault Secrets User' } ] @@ -860,15 +877,15 @@ module openai 'modules/core/ai/cognitiveservices.bicep' = { principalType: 'ServicePrincipal' } ], - !empty(principalId) + !empty(principal.id) ? [ { roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908' //Cognitive Services User - principalId: principalId + principalId: principal.id } { roleDefinitionIdOrName: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd' // Cognitive Services Contributor - principalId: principalId + principalId: principal.id } ] : [] @@ -905,11 +922,11 @@ module computerVision 'modules/core/ai/cognitiveservices.bicep' = if (useAdvance principalType: 'ServicePrincipal' } ], - !empty(principalId) + !empty(principal.id) ? [ { roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908' //Cognitive Services User - principalId: principalId + principalId: principal.id } ] : [] @@ -949,11 +966,11 @@ module speechService 'modules/core/ai/cognitiveservices.bicep' = { principalType: 'ServicePrincipal' } ], - !empty(principalId) + !empty(principal.id) ? [ { roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908' //Cognitive Services User - principalId: principalId + principalId: principal.id } ] : [] @@ -1030,19 +1047,19 @@ module search 'br/public:avm/res/search/search-service:0.11.1' = if (databaseTyp principalType: 'ServicePrincipal' } ], - !empty(principalId) + !empty(principal.id) ? [ { roleDefinitionIdOrName: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' // Search Index Data Contributor - principalId: principalId + principalId: principal.id } { roleDefinitionIdOrName: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' // Search Service Contributor - principalId: principalId + principalId: principal.id } { roleDefinitionIdOrName: '1407120a-92aa-4202-b7e9-c0e197c71c8f' // Search Index Data Reader - principalId: principalId + principalId: principal.id } ] : [] @@ -1420,11 +1437,11 @@ module formrecognizer 'modules/core/ai/cognitiveservices.bicep' = { principalType: 'ServicePrincipal' } ], - !empty(principalId) + !empty(principal.id) ? [ { roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908' //Cognitive Services User - principalId: principalId + principalId: principal.id } ] : [] @@ -1460,11 +1477,11 @@ module contentsafety 'modules/core/ai/cognitiveservices.bicep' = { principalType: 'ServicePrincipal' } ], - !empty(principalId) + !empty(principal.id) ? [ { roleDefinitionIdOrName: 'a97b65f3-24c7-4388-baec-2e87135dc908' //Cognitive Services User - principalId: principalId + principalId: principal.id } ] : [] diff --git a/infra/main.json b/infra/main.json index 69d45af41..942472aca 100644 --- a/infra/main.json +++ b/infra/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.37.4.10188", - "templateHash": "14151002700383033945" + "templateHash": "5895320887545019006" } }, "parameters": { @@ -29,12 +29,17 @@ }, "location": { "type": "string", - "defaultValue": "[resourceGroup().location]", + "allowedValues": [ + "australiaeast", + "eastus2", + "japaneast", + "uksouth" + ], "metadata": { "azd": { "type": "location" }, - "description": "Optional. Location for all resources, if you are using existing resource group provide the location of the resorce group." + "description": "Required. Azure region for all services. Regions are restricted to guarantee compatibility with paired regions and replica locations for data redundancy and failover scenarios based on articles [Azure regions list](https://learn.microsoft.com/azure/reliability/regions-list) and [Azure Database for MySQL Flexible Server - Azure Regions](https://learn.microsoft.com/azure/mysql/flexible-server/overview#azure-regions)." } }, "existingLogAnalyticsWorkspaceId": { @@ -324,7 +329,7 @@ }, "azureOpenAIStopSequence": { "type": "string", - "defaultValue": "\n", + "defaultValue": "\\n", "metadata": { "description": "Optional. Azure OpenAI Stop Sequence." } @@ -448,11 +453,15 @@ "description": "Optional. A new GUID string generated for this deployment. This can be used for unique naming if needed." } }, - "principalId": { - "type": "string", - "defaultValue": "", + "principal": { + "type": "object", + "defaultValue": { + "id": "", + "name": "", + "type": "User" + }, "metadata": { - "description": "Optional. Id of the user or app to assign application roles." + "description": "Optional. Principal object for user or service principal to assign application roles. Format: {\"id\":\"\", \"name\":\"\", \"type\":\"User|Group|ServicePrincipal\"}" } }, "appEnvironment": { @@ -17667,7 +17676,9 @@ "highAvailabilityZone": "[if(parameters('enableRedundancy'), createObject('value', 2), createObject('value', -1))]", "publicNetworkAccess": "[if(parameters('enablePrivateNetworking'), createObject('value', 'Disabled'), createObject('value', 'Enabled'))]", "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-{0}', variables('postgresResourceName')), 'customNetworkInterfaceName', format('nic-{0}', variables('postgresResourceName')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').postgresDB)).outputs.resourceId.value))), 'service', 'postgresqlServer', 'subnetResourceId', reference('network').outputs.subnetPrivateEndpointsResourceId.value))), createObject('value', createArray()))]", - "administrators": "[if(not(equals(reference('managedIdentityModule').outputs.principalId.value, '')), createObject('value', createArray(createObject('objectId', reference('managedIdentityModule').outputs.principalId.value, 'principalName', reference('managedIdentityModule').outputs.name.value, 'principalType', 'ServicePrincipal'))), createObject('value', null()))]", + "administrators": { + "value": "[concat(if(not(equals(reference('managedIdentityModule').outputs.principalId.value, '')), createArray(createObject('objectId', reference('managedIdentityModule').outputs.principalId.value, 'principalName', reference('managedIdentityModule').outputs.name.value, 'principalType', 'ServicePrincipal')), createArray()), if(not(empty(parameters('principal').id)), createArray(createObject('objectId', parameters('principal').id, 'principalName', parameters('principal').name, 'principalType', parameters('principal').type)), createArray()))]" + }, "firewallRules": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray()), createObject('value', concat(if(variables('allowAllIPsFirewall'), createArray(createObject('name', 'allow-all-IPs', 'startIpAddress', '0.0.0.0', 'endIpAddress', '255.255.255.255')), createArray()), if(variables('allowAzureIPsFirewall'), createArray(createObject('name', 'allow-all-azure-internal-IPs', 'startIpAddress', '0.0.0.0', 'endIpAddress', '0.0.0.0')), createArray()))))]", "configurations": { "value": [ @@ -21067,7 +21078,7 @@ "diagnosticSettings": "[if(parameters('enableMonitoring'), createObject('value', createArray(createObject('workspaceResourceId', reference('monitoring').outputs.logAnalyticsWorkspaceId.value))), createObject('value', null()))]", "privateEndpoints": "[if(parameters('enablePrivateNetworking'), createObject('value', createArray(createObject('name', format('pep-{0}', variables('keyVaultName')), 'customNetworkInterfaceName', format('nic-{0}', variables('keyVaultName')), 'privateDnsZoneGroup', createObject('privateDnsZoneGroupConfigs', createArray(createObject('privateDnsZoneResourceId', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').keyVault)).outputs.resourceId.value))), 'service', 'vault', 'subnetResourceId', reference('network').outputs.subnetPrivateEndpointsResourceId.value))), createObject('value', createArray()))]", "roleAssignments": { - "value": "[concat(if(not(equals(reference('managedIdentityModule').outputs.principalId.value, '')), createArray(createObject('principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal', 'roleDefinitionIdOrName', 'Key Vault Secrets User')), createArray()), if(not(equals(parameters('principalId'), '')), createArray(createObject('principalId', parameters('principalId'), 'roleDefinitionIdOrName', 'Key Vault Secrets User')), createArray()))]" + "value": "[concat(if(not(equals(reference('managedIdentityModule').outputs.principalId.value, '')), createArray(createObject('principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal', 'roleDefinitionIdOrName', 'Key Vault Secrets User')), createArray()), if(not(empty(parameters('principal').id)), createArray(createObject('principalId', parameters('principal').id, 'roleDefinitionIdOrName', 'Key Vault Secrets User')), createArray()))]" }, "secrets": { "value": [ @@ -23249,7 +23260,7 @@ "logAnalyticsWorkspaceId": "[if(parameters('enableMonitoring'), createObject('value', reference('monitoring').outputs.logAnalyticsWorkspaceId.value), createObject('value', null()))]", "privateDnsZoneResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').openAI)).outputs.resourceId.value), createObject('value', ''))]", "roleAssignments": { - "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principalId'))), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principalId')), createObject('roleDefinitionIdOrName', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd', 'principalId', parameters('principalId'))), createArray()))]" + "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principal').id)), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principal').id), createObject('roleDefinitionIdOrName', '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd', 'principalId', parameters('principal').id)), createArray()))]" } }, "template": { @@ -25855,7 +25866,7 @@ }, "privateDnsZoneResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value), createObject('value', ''))]", "roleAssignments": { - "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principalId'))), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principalId'))), createArray()))]" + "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principal').id)), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principal').id)), createArray()))]" } }, "template": { @@ -28462,7 +28473,7 @@ }, "privateDnsZoneResourceId": "[if(variables('enablePrivateNetworkingSpeech'), createObject('value', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value), createObject('value', ''))]", "roleAssignments": { - "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principalId'))), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principalId'))), createArray()))]" + "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principal').id)), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principal').id)), createArray()))]" } }, "template": { @@ -31092,7 +31103,7 @@ } }, "roleAssignments": { - "value": "[concat(createArray(createObject('roleDefinitionIdOrName', '8ebe5a00-799e-43f5-93ac-243d3dce84a7', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', '7ca78c08-252a-4471-8644-bb5ff32d4ba0', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', '1407120a-92aa-4202-b7e9-c0e197c71c8f', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principalId'))), createArray(createObject('roleDefinitionIdOrName', '8ebe5a00-799e-43f5-93ac-243d3dce84a7', 'principalId', parameters('principalId')), createObject('roleDefinitionIdOrName', '7ca78c08-252a-4471-8644-bb5ff32d4ba0', 'principalId', parameters('principalId')), createObject('roleDefinitionIdOrName', '1407120a-92aa-4202-b7e9-c0e197c71c8f', 'principalId', parameters('principalId'))), createArray()))]" + "value": "[concat(createArray(createObject('roleDefinitionIdOrName', '8ebe5a00-799e-43f5-93ac-243d3dce84a7', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', '7ca78c08-252a-4471-8644-bb5ff32d4ba0', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', '1407120a-92aa-4202-b7e9-c0e197c71c8f', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principal').id)), createArray(createObject('roleDefinitionIdOrName', '8ebe5a00-799e-43f5-93ac-243d3dce84a7', 'principalId', parameters('principal').id), createObject('roleDefinitionIdOrName', '7ca78c08-252a-4471-8644-bb5ff32d4ba0', 'principalId', parameters('principal').id), createObject('roleDefinitionIdOrName', '1407120a-92aa-4202-b7e9-c0e197c71c8f', 'principalId', parameters('principal').id)), createArray()))]" } }, "template": { @@ -46978,7 +46989,7 @@ "value": true }, "roleAssignments": { - "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principalId'))), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principalId'))), createArray()))]" + "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal'), createObject('roleDefinitionIdOrName', 'ba92f5b4-2d11-453d-a403-e96b0029c9fe', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principal').id)), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principal').id)), createArray()))]" } }, "template": { @@ -49582,7 +49593,7 @@ }, "privateDnsZoneResourceId": "[if(parameters('enablePrivateNetworking'), createObject('value', reference(format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').cognitiveServices)).outputs.resourceId.value), createObject('value', ''))]", "roleAssignments": { - "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principalId'))), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principalId'))), createArray()))]" + "value": "[concat(createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', reference('managedIdentityModule').outputs.principalId.value, 'principalType', 'ServicePrincipal')), if(not(empty(parameters('principal').id)), createArray(createObject('roleDefinitionIdOrName', 'a97b65f3-24c7-4388-baec-2e87135dc908', 'principalId', parameters('principal').id)), createArray()))]" } }, "template": { @@ -55429,8 +55440,8 @@ }, "dependsOn": [ "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageQueue)]", - "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageFile)]", + "[format('avmPrivateDnsZones[{0}]', variables('dnsZoneIndex').storageBlob)]", "managedIdentityModule", "network" ] diff --git a/infra/main.parameters.json b/infra/main.parameters.json index 11416b9fb..a83b0b8f3 100644 --- a/infra/main.parameters.json +++ b/infra/main.parameters.json @@ -8,8 +8,12 @@ "location": { "value": "${AZURE_LOCATION}" }, - "principalId": { - "value": "${AZURE_PRINCIPAL_ID}" + "principal": { + "value": { + "id": "${AZURE_PRINCIPAL_ID}", + "name": "${AZURE_PRINCIPAL_NAME}", + "type": "${AZURE_PRINCIPAL_TYPE=User}" + } }, "appEnvironment": { "value": "${APP_ENV=Prod}" diff --git a/infra/main.waf.parameters.json b/infra/main.waf.parameters.json index d7e990bae..7d5423ca1 100644 --- a/infra/main.waf.parameters.json +++ b/infra/main.waf.parameters.json @@ -8,8 +8,12 @@ "location": { "value": "${AZURE_LOCATION}" }, - "principalId": { - "value": "${AZURE_PRINCIPAL_ID}" + "principal": { + "value": { + "id": "${AZURE_PRINCIPAL_ID}", + "name": "${AZURE_PRINCIPAL_NAME}", + "type": "${AZURE_PRINCIPAL_TYPE=User}" + } }, "appEnvironment": { "value": "${APP_ENV=Prod}"