diff --git a/deploy/starter/infra/app/acaService.bicep b/deploy/starter/infra/app/acaService.bicep index 8b2b5aa193..38983c251b 100644 --- a/deploy/starter/infra/app/acaService.bicep +++ b/deploy/starter/infra/app/acaService.bicep @@ -230,4 +230,5 @@ output defaultDomain string = containerAppsEnvironment.properties.defaultDomain output name string = app.name output uri string = hasIngress ? 'https://${app.properties.configuration.ingress.fqdn}' : '' output id string = app.id +output identityPrincipalId string = identity.properties.principalId output miPrincipalId string = identity.properties.principalId diff --git a/deploy/starter/infra/main.bicep b/deploy/starter/infra/main.bicep index e16615ef0d..9fd78eaf49 100644 --- a/deploy/starter/infra/main.bicep +++ b/deploy/starter/infra/main.bicep @@ -3,6 +3,9 @@ targetScope = 'subscription' param adminGroupObjectId string param authAppRegistration object +param timestamp string = utcNow() + +@secure() param authClientSecret string param appRegistrations array @@ -112,11 +115,12 @@ resource customerOpenAi 'Microsoft.CognitiveServices/accounts@2023-05-01' existi /********** Nested Modules **********/ module appConfig './shared/app-config.bicep' = { - name: 'app-config' + name: 'app-config-${timestamp}' params: { keyvaultName: keyVault.outputs.name location: location name: '${abbrs.appConfigurationConfigurationStores}${resourceToken}' + services: services sku: 'standard' tags: tags } @@ -125,7 +129,7 @@ module appConfig './shared/app-config.bicep' = { } module authKeyvault './shared/keyvault.bicep' = { - name: 'auth-kv' + name: 'auth-kv-${timestamp}' params: { location: location name: '${abbrs.keyVaultVaults}auth${resourceToken}' @@ -170,7 +174,7 @@ module authKeyvault './shared/keyvault.bicep' = { } module authStore './shared/authorization-store.bicep' = { - name: 'auth-store' + name: 'auth-store-${timestamp}' params: { adminGroupObjectId: adminGroupObjectId location: location @@ -181,7 +185,7 @@ module authStore './shared/authorization-store.bicep' = { } module contentSafety './shared/content-safety.bicep' = { - name: 'content-safety' + name: 'content-safety-${timestamp}' params: { keyvaultName: keyVault.outputs.name location: location @@ -194,7 +198,7 @@ module contentSafety './shared/content-safety.bicep' = { } module cosmosDb './shared/cosmosdb.bicep' = { - name: 'cosmos' + name: 'cosmos-${timestamp}' params: { containers: [ { @@ -229,7 +233,7 @@ module cosmosDb './shared/cosmosdb.bicep' = { } module cogSearch './shared/search.bicep' = { - name: 'cogsearch' + name: 'cogsearch-${timestamp}' params: { location: location name: '${abbrs.searchSearchServices}${resourceToken}' @@ -252,7 +256,7 @@ var searchWriterRoleTargets = [ module searchReaderRoles './shared/roleAssignments.bicep' = [ for target in searchReaderRoleTargets: { scope: rg - name: '${target}-search-reader-role' + name: '${target}-search-reader-role-${timestamp}' params: { principalId: acaServices[indexOf(serviceNames, target)].outputs.miPrincipalId roleDefinitionIds: { @@ -265,7 +269,7 @@ module searchReaderRoles './shared/roleAssignments.bicep' = [ module searchWriterRoles './shared/roleAssignments.bicep' = [ for target in searchWriterRoleTargets: { scope: rg - name: '${target}-search-contrib-role' + name: '${target}-search-contrib-role-${timestamp}' params: { principalId: acaServices[indexOf(serviceNames, target)].outputs.miPrincipalId roleDefinitionIds: { @@ -277,7 +281,7 @@ module searchWriterRoles './shared/roleAssignments.bicep' = [ ] module dashboard './shared/dashboard-web.bicep' = { - name: 'dashboard' + name: 'dashboard-${timestamp}' params: { name: '${abbrs.portalDashboards}${resourceToken}' applicationInsightsName: monitoring.outputs.applicationInsightsName @@ -288,7 +292,7 @@ module dashboard './shared/dashboard-web.bicep' = { } module eventgrid './shared/eventgrid.bicep' = { - name: 'eventgrid' + name: 'eventgrid-${timestamp}' params: { name: '${abbrs.eventGridDomains}${resourceToken}' location: location @@ -310,7 +314,7 @@ module eventgrid './shared/eventgrid.bicep' = { } module keyVault './shared/keyvault.bicep' = { - name: 'keyvault' + name: 'keyvault-${timestamp}' params: { location: location tags: tags @@ -322,7 +326,7 @@ module keyVault './shared/keyvault.bicep' = { } module monitoring './shared/monitoring.bicep' = { - name: 'monitoring' + name: 'monitoring-${timestamp}' params: { keyvaultName: keyVault.outputs.name location: location @@ -334,10 +338,11 @@ module monitoring './shared/monitoring.bicep' = { dependsOn: [ keyVault ] } -module openAi './shared/openai.bicep' = if (deployOpenAi) { - dependsOn: [ keyVault ] - name: 'openai' - scope: rg +module openAi './shared/openai.bicep' = + if (deployOpenAi) { + dependsOn: [keyVault] + name: 'openai-${timestamp}' + scope: rg params: { location: location @@ -373,7 +378,7 @@ module openAi './shared/openai.bicep' = if (deployOpenAi) { } module openAiSecrets './shared/openai-secrets.bicep' = { - name: 'openaiSecrets' + name: 'openaiSecrets-${timestamp}' scope: rg params: { @@ -384,7 +389,7 @@ module openAiSecrets './shared/openai-secrets.bicep' = { } module storage './shared/storage.bicep' = { - name: 'storage' + name: 'storage-${timestamp}' params: { containers: [ { @@ -434,7 +439,7 @@ module storage './shared/storage.bicep' = { } module configTopic 'shared/config-system-topic.bicep' = { - name: 'configTopic' + name: 'configTopic-${timestamp}' params: { name: '${abbrs.eventGridDomainsTopics}config${resourceToken}' location: location @@ -445,7 +450,7 @@ module configTopic 'shared/config-system-topic.bicep' = { } module storageTopic 'shared/storage-system-topic.bicep' = { - name: 'storageTopic' + name: 'storageTopic-${timestamp}' params: { name: '${abbrs.eventGridDomainsTopics}storage${resourceToken}' location: location @@ -456,7 +461,7 @@ module storageTopic 'shared/storage-system-topic.bicep' = { } module storageSub 'shared/system-topic-subscription.bicep' = { - name: 'storageSub' + name: 'storageSub-${timestamp}' params: { name: 'foundationallm-storage' eventGridName: eventgrid.outputs.name @@ -471,7 +476,7 @@ module storageSub 'shared/system-topic-subscription.bicep' = { { key: 'subject' operatorType: 'StringNotEndsWith' - values: [ + values: [ '_agent-references.json' '_data-source-references.json' '_prompt-references.json' @@ -484,7 +489,7 @@ module storageSub 'shared/system-topic-subscription.bicep' = { } module configSub 'shared/system-topic-subscription.bicep' = { - name: 'configSub' + name: 'configSub-${timestamp}' params: { name: 'app-config' eventGridName: eventgrid.outputs.name @@ -499,7 +504,7 @@ module configSub 'shared/system-topic-subscription.bicep' = { } module appsEnv './shared/apps-env.bicep' = { - name: 'apps-env' + name: 'apps-env-${timestamp}' params: { name: '${abbrs.appManagedEnvironments}${resourceToken}' location: location @@ -511,7 +516,7 @@ module appsEnv './shared/apps-env.bicep' = { } module authAcaService './app/authAcaService.bicep' = { - name: authService.name + name: '${authService.name}-${timestamp}' params: { name: '${abbrs.appContainerApps}authapi${resourceToken}' location: location @@ -539,42 +544,72 @@ module authAcaService './app/authAcaService.bicep' = { } @batchSize(3) -module acaServices './app/acaService.bicep' = [for service in services: { - name: service.name - params: { - name: '${abbrs.appContainerApps}${service.name}${resourceToken}' - location: location - tags: tags - appConfigName: appConfig.outputs.name - eventgridName: eventgrid.outputs.name - identityName: '${abbrs.managedIdentityUserAssignedIdentities}${service.name}-${resourceToken}' - keyvaultName: keyVault.outputs.name - applicationInsightsName: monitoring.outputs.applicationInsightsName - containerAppsEnvironmentName: appsEnv.outputs.name - storageAccountName: storage.outputs.name - exists: servicesExist['${service.name}'] == 'true' - appDefinition: serviceDefinition - hasIngress: service.hasIngress - imageName: service.image - envSettings: service.useEndpoint ? [ - { - name: service.appConfigEnvironmentVarName - value: appConfig.outputs.endpoint - } - ] : [] - secretSettings: service.useEndpoint ? [] : [ - { - name: service.appConfigEnvironmentVarName - value: appConfig.outputs.connectionStringSecretRef - secretRef: 'appconfig-connection-string' +module acaServices './app/acaService.bicep' = [ + for service in services: { + dependsOn: [appConfig, cogSearch, contentSafety, cosmosDb, keyVault, monitoring, storage] + name: '${service.name}-${timestamp}' + scope: rg + params: { + apiKeySecretName: service.apiKeySecretName + appConfigName: appConfig.outputs.name + appDefinition: serviceDefinition + applicationInsightsName: monitoring.outputs.applicationInsightsName + containerAppsEnvironmentName: appsEnv.outputs.name + eventgridName: eventgrid.outputs.name + exists: servicesExist['${service.name}'] == 'true' + hasIngress: service.hasIngress + identityName: '${abbrs.managedIdentityUserAssignedIdentities}${service.name}-${resourceToken}' + imageName: service.image + keyvaultName: keyVault.outputs.name + location: location + name: '${abbrs.appContainerApps}${service.name}${resourceToken}' + serviceName: service.name + storageAccountName: storage.outputs.name + tags: tags + + envSettings: service.useEndpoint + ? [ + { + name: service.appConfigEnvironmentVarName + value: appConfig.outputs.endpoint + } + ] + : [] + + secretSettings: service.useEndpoint + ? [] + : [ + { + name: service.appConfigEnvironmentVarName + value: filter(appConfig.outputs.connectionStringSecret, item => item.name == service.name)[0].uri + secretRef: 'appconfig-connection-string' + } + ] + } + } +] + +module cosmosRoles './shared/sqlRoleAssignments.bicep' = [ + for target in cosmosRoleTargets: { + scope: rg + name: '${target}-cosmos-role-${timestamp}' + params: { + accountName: cosmosDb.outputs.name + principalId: acaServices[indexOf(serviceNames, target)].outputs.miPrincipalId + roleDefinitionIds: { + 'Cosmos DB Built-in Data Contributor': '00000000-0000-0000-0000-000000000002' } - ] - apiKeySecretName: service.apiKeySecretName - serviceName: service.name + } } - scope: rg - dependsOn: [ appConfig, cogSearch, contentSafety, cosmosDb, keyVault, monitoring, storage ] -}] +] + +var cosmosRoleTargets = [ + 'core-api' + 'core-job' +] + + + output AZURE_APP_CONFIG_NAME string = appConfig.outputs.name output AZURE_AUTHORIZATION_STORAGE_ACCOUNT_NAME string = authStore.outputs.name diff --git a/deploy/starter/infra/shared/app-config.bicep b/deploy/starter/infra/shared/app-config.bicep index 270633962d..58c782f4cb 100644 --- a/deploy/starter/infra/shared/app-config.bicep +++ b/deploy/starter/infra/shared/app-config.bicep @@ -1,9 +1,20 @@ +/** Inputs **/ param keyvaultName string -param name string param location string = resourceGroup().location +param name string +param services array param sku string = 'standard' param tags object = {} +/** Locals **/ +var readWriteServices = ['management-api'] + +/** Data Sources **/ +resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' existing = { + name: keyvaultName +} + +/** Resources **/ resource appconfig 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = { name: name location: location @@ -18,20 +29,36 @@ resource appconfig 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = } } -resource keyvault 'Microsoft.KeyVault/vaults@2023-07-01' existing = { - name: keyvaultName +resource connectionStringReadOnlySecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { + name: 'appconfig-connection-string-readonly' + parent: keyvault + tags: tags + properties: { + value: appconfig.listKeys().value[2].connectionString + } } -resource connectionStringSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { - name: 'appconfig-connnection-string' +resource connectionStringReadWriteSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { + name: 'appconfig-connection-string' parent: keyvault tags: tags properties: { - value: appconfig.listKeys().value[2].connectionString + value: appconfig.listKeys().value[0].connectionString } } +/** Outputs **/ output endpoint string = appconfig.properties.endpoint -output connectionStringSecretName string = connectionStringSecret.name -output connectionStringSecretRef string = connectionStringSecret.properties.secretUri output name string = appconfig.name + +output connectionStringSecret array = [ + for service in services: { + name: service.name + uri: contains(readWriteServices, service.name) + ? connectionStringReadWriteSecret.properties.secretUri + : connectionStringReadOnlySecret.properties.secretUri + secretName: contains(readWriteServices, service.name) + ? connectionStringReadWriteSecret.name + : connectionStringReadOnlySecret.name + } +] diff --git a/deploy/starter/infra/shared/sqlRoleAssignments.bicep b/deploy/starter/infra/shared/sqlRoleAssignments.bicep new file mode 100644 index 0000000000..b4e88ae312 --- /dev/null +++ b/deploy/starter/infra/shared/sqlRoleAssignments.bicep @@ -0,0 +1,32 @@ +@description('Principal ID to assign roles to.') +param principalId string + +@description('Roles to assign.') +param roleDefinitionIds object + +@description('CosmosDB Resource Id') +param accountName string + +resource cosmosDb 'Microsoft.DocumentDB/databaseAccounts@2023-11-15' existing = { + name: accountName +} + +/** Locals **/ +@description('Role Assignments to create') +var roleAssignmentsToCreate = [for roleDefinitionId in items(roleDefinitionIds): { + name: guid(principalId, resourceGroup().id, roleDefinitionId.value) + roleDefinitionId: roleDefinitionId.value +}] + +/** Resources **/ +resource roleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-11-15' = [ + for roleAssignmentToCreate in roleAssignmentsToCreate: { + name: guid(roleAssignmentToCreate.roleDefinitionId, principalId, cosmosDb.id) + parent: cosmosDb + properties: { + principalId: principalId + roleDefinitionId: resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', cosmosDb.name, roleAssignmentToCreate.roleDefinitionId) + scope: cosmosDb.id + } + } +] diff --git a/src/python/PythonSDK/foundationallm/hubs/data_source/data_sources/search_service/search_service_data_source_metadata.py b/src/python/PythonSDK/foundationallm/hubs/data_source/data_sources/search_service/search_service_data_source_metadata.py index 7537fce83a..21383b9dea 100644 --- a/src/python/PythonSDK/foundationallm/hubs/data_source/data_sources/search_service/search_service_data_source_metadata.py +++ b/src/python/PythonSDK/foundationallm/hubs/data_source/data_sources/search_service/search_service_data_source_metadata.py @@ -8,7 +8,7 @@ class SearchServiceDataSourceMetadata(DataSourceMetadata): """ - Represents search service data source that details authentication, connnection, + Represents search service data source that details authentication, connection, and details on the content contained within """ index_name: str