Skip to content

Commit 4c7e5fe

Browse files
Merge branch 'main' into psl-re-use-log-update
2 parents bb3fff7 + 60076cc commit 4c7e5fe

32 files changed

+1724
-1636
lines changed

.github/workflows/deploy-KMGeneric.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,15 @@ jobs:
112112
echo "Generated SOLUTION_PREFIX: ${UNIQUE_SOLUTION_PREFIX}"
113113
- name: Determine Tag Name Based on Branch
114114
id: determine_tag
115-
run: echo "tagname=${{ github.ref_name == 'main' && 'latest' || github.ref_name == 'dev' && 'dev' || github.ref_name == 'demo' && 'demo' || github.ref_name == 'dependabotchanges' && 'dependabotchanges' || github.head_ref || 'default' }}" >> $GITHUB_OUTPUT
115+
run: echo "tagname=${{ github.ref_name == 'main' && 'latest_fdp' || github.ref_name == 'dev' && 'dev' || github.ref_name == 'demo' && 'demo' || github.ref_name == 'dependabotchanges' && 'dependabotchanges' || github.head_ref || 'default' }}" >> $GITHUB_OUTPUT
116116
- name: Deploy Bicep Template
117117
id: deploy
118118
run: |
119119
set -e
120120
az deployment group create \
121121
--resource-group ${{ env.RESOURCE_GROUP_NAME }} \
122122
--template-file infra/main.bicep \
123-
--parameters environmentName=${{env.SOLUTION_PREFIX}} contentUnderstandingLocation="swedencentral" secondaryLocation="${{ env.AZURE_LOCATION }}" imageTag=${{ steps.determine_tag.outputs.tagname }} gptDeploymentCapacity=150
123+
--parameters environmentName=${{env.SOLUTION_PREFIX}} contentUnderstandingLocation="swedencentral" secondaryLocation="${{ env.AZURE_LOCATION }}" imageTag=${{ steps.determine_tag.outputs.tagname }} gptDeploymentCapacity=150 aiDeploymentsLocation="${{ env.AZURE_LOCATION }}"
124124
125125
126126

.github/workflows/docker-build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ jobs:
4949
id: determine_tag
5050
run: |
5151
if [[ "${{ github.ref_name }}" == "main" ]]; then
52-
echo "tagname=latest" >> $GITHUB_OUTPUT
52+
echo "tagname=latest_fdp" >> $GITHUB_OUTPUT
5353
elif [[ "${{ github.ref_name }}" == "dev" ]]; then
5454
echo "tagname=dev" >> $GITHUB_OUTPUT
5555
elif [[ "${{ github.ref_name }}" == "demo" ]]; then
@@ -78,4 +78,4 @@ jobs:
7878
push: ${{ github.ref_name == 'main' || github.ref_name == 'dev' || github.ref_name == 'demo' || github.ref_name == 'dependabotchanges' }}
7979
tags: |
8080
${{ secrets.ACR_LOGIN_SERVER || 'acrlogin.azurecr.io' }}/km-api:${{ steps.determine_tag.outputs.tagname }}
81-
${{ secrets.ACR_LOGIN_SERVER || 'acrlogin.azurecr.io' }}/km-api:${{ steps.determine_tag.outputs.tagname }}_${{ steps.date.outputs.date }}_${{ github.run_number }}
81+
${{ secrets.ACR_LOGIN_SERVER || 'acrlogin.azurecr.io' }}/km-api:${{ steps.determine_tag.outputs.tagname }}_${{ steps.date.outputs.date }}_${{ github.run_number }}

azure.yaml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,6 @@ metadata:
99
1010

1111
hooks:
12-
preprovision:
13-
windows:
14-
run: |
15-
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"; $logFile = "azd_preprovision_$timestamp.log"; ./infra/scripts/docker-build.ps1 $env:AZURE_SUBSCRIPTION_ID $env:AZURE_ENV_NAME $env:AZURE_LOCATION $env:AZURE_RESOURCE_GROUP $env:USE_LOCAL_BUILD $env:AZURE_ENV_IMAGETAG *>&1 | Tee-Object -FilePath $logFile
16-
shell: pwsh
17-
continueOnError: false
18-
interactive: true
19-
posix:
20-
run: |
21-
timestamp=$(date +"%Y%m%d-%H%M%S"); logFile="azd_preprovision_$timestamp.log"; sed -i 's/\r$//' ./infra/scripts/docker-build.sh; ./infra/scripts/docker-build.sh "$AZURE_SUBSCRIPTION_ID" "$AZURE_ENV_NAME" "$AZURE_LOCATION" "$AZURE_RESOURCE_GROUP" "$USE_LOCAL_BUILD" "$AZURE_ENV_IMAGETAG" 2>&1 | tee "$logFile"
22-
shell: sh
23-
continueOnError: false
24-
interactive: true
2512
postprovision:
2613
windows:
2714
run: |

documents/DeploymentGuide.md

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -177,33 +177,6 @@ Once you've opened the project in [Codespaces](#github-codespaces), [Dev Contain
177177
178178
6. If you are done trying out the application, you can delete the resources by running `azd down`.
179179
180-
### Publishing Local Build Container to Azure Container Registry
181-
182-
If you need to rebuild the source code and push the updated container to the deployed Azure Container Registry, follow these steps:
183-
184-
1. Set the environment variable `USE_LOCAL_BUILD` to `True`:
185-
186-
- **Linux/macOS**:
187-
```bash
188-
export USE_LOCAL_BUILD=True
189-
```
190-
191-
- **Windows (PowerShell)**:
192-
```powershell
193-
$env:USE_LOCAL_BUILD = $true
194-
```
195-
2. Run the `az login` command
196-
```bash
197-
az login
198-
```
199-
200-
3. Run the `azd up` command again to rebuild and push the updated container:
201-
```bash
202-
azd up
203-
```
204-
205-
This will rebuild the source code, package it into a container, and push it to the Azure Container Registry associated with your deployment.
206-
207180
## Post Deployment Steps
208181
209182
1. **Add App Authentication**

infra/deploy_ai_foundry.bicep

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var keyvaultName = '${abbrs.security.keyVault}${solutionName}'
2424
var location = solutionLocation //'eastus2'
2525
var aiProjectName = '${abbrs.ai.aiFoundryProject}${solutionName}'
2626
var aiSearchName = '${abbrs.ai.aiSearch}${solutionName}'
27+
var aiSearchConnectionName = 'myVectorStoreProjectConnectionName-${solutionName}'
2728

2829
var aiModelDeployments = [
2930
{
@@ -56,8 +57,8 @@ var existingOpenAIEndpoint = !empty(azureExistingAIProjectResourceId) ? format('
5657
var existingProjEndpoint = !empty(azureExistingAIProjectResourceId) ? format('https://{0}.services.ai.azure.com/api/projects/{1}', split(azureExistingAIProjectResourceId, '/')[8], split(azureExistingAIProjectResourceId, '/')[10]) : ''
5758
var existingAIServicesName = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[8] : ''
5859
var existingAIProjectName = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[10] : ''
59-
var existingAIServiceSubscription = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[2] : ''
60-
var existingAIServiceResourceGroup = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[4] : ''
60+
var existingAIServiceSubscription = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[2] : subscription().subscriptionId
61+
var existingAIServiceResourceGroup = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[4] : resourceGroup().name
6162

6263
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {
6364
name: keyVaultName
@@ -161,6 +162,9 @@ resource aiSearch 'Microsoft.Search/searchServices@2024-06-01-preview' = {
161162
sku: {
162163
name: 'basic'
163164
}
165+
identity: {
166+
type: 'SystemAssigned'
167+
}
164168
properties: {
165169
replicaCount: 1
166170
partitionCount: 1
@@ -172,10 +176,7 @@ resource aiSearch 'Microsoft.Search/searchServices@2024-06-01-preview' = {
172176
encryptionWithCmk: {
173177
enforcement: 'Unspecified'
174178
}
175-
disableLocalAuth: false
176-
authOptions: {
177-
apiKeyOnly: {}
178-
}
179+
disableLocalAuth: true
179180
semanticSearch: 'free'
180181
}
181182
}
@@ -192,7 +193,7 @@ resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-pre
192193
}
193194

194195
resource aiproject_aisearch_connection_new 'Microsoft.CognitiveServices/accounts/projects/connections@2025-04-01-preview' = if (empty(azureExistingAIProjectResourceId)) {
195-
name: 'myVectorStoreProjectConnectionName-${solutionName}'
196+
name: aiSearchConnectionName
196197
parent: aiProject
197198
properties: {
198199
category: 'CognitiveSearch'
@@ -216,31 +217,121 @@ module existing_AIProject_SearchConnectionModule 'deploy_aifp_aisearch_connectio
216217
aiSearchName: aiSearchName
217218
aiSearchResourceId: aiSearch.id
218219
aiSearchLocation: aiSearch.location
219-
solutionName: solutionName
220+
aiSearchConnectionName: aiSearchConnectionName
220221
}
221222
}
222223

223224
resource aiUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
224225
name: '53ca6127-db72-4b80-b1b0-d745d6d5456d'
225226
}
226227

227-
resource aiUserAccessFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
228-
name: guid(resourceGroup().id, managedIdentityObjectId, aiUser.id)
228+
resource assignFoundryRoleToMI 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (empty(azureExistingAIProjectResourceId)) {
229+
name: guid(resourceGroup().id, aiServices.id, aiUser.id)
230+
scope: aiServices
229231
properties: {
230232
principalId: managedIdentityObjectId
231233
roleDefinitionId: aiUser.id
232-
principalType: 'ServicePrincipal'
234+
principalType: 'ServicePrincipal'
233235
}
234236
}
235237

236-
module assignAiUserRoleToManagedIdentity 'deploy_foundry_role_assignment.bicep' = if(!empty(azureExistingAIProjectResourceId)) {
237-
name: 'assignAiUserRoleToManagedIdentity'
238+
module assignFoundryRoleToMIExisting 'deploy_foundry_role_assignment.bicep' = if (!empty(azureExistingAIProjectResourceId)) {
239+
name: 'assignFoundryRoleToMI'
238240
scope: resourceGroup(existingAIServiceSubscription, existingAIServiceResourceGroup)
239241
params: {
240242
roleDefinitionId: aiUser.id
241-
roleAssignmentName: guid(managedIdentityObjectId, aiServices.id, aiUser.id)
243+
roleAssignmentName: guid(resourceGroup().id, managedIdentityObjectId, aiUser.id, 'foundry')
244+
aiServicesName: !empty(azureExistingAIProjectResourceId) ? existingAIServicesName : aiServicesName
245+
aiProjectName: !empty(azureExistingAIProjectResourceId) ? existingAIProjectName : aiProjectName
246+
principalId: managedIdentityObjectId
247+
}
248+
}
249+
250+
resource assignAiUserToAiFoundryCU 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
251+
name: guid(resourceGroup().id, aiServices_CU.id, aiUser.id)
252+
scope: aiServices_CU
253+
properties: {
254+
principalId: managedIdentityObjectId
255+
roleDefinitionId: aiUser.id
256+
principalType: 'ServicePrincipal'
257+
}
258+
}
259+
260+
resource cognitiveServicesOpenAIUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
261+
name: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd'
262+
}
263+
264+
module assignOpenAIRoleToAISearch 'deploy_foundry_role_assignment.bicep' = {
265+
name: 'assignOpenAIRoleToAISearch'
266+
scope: resourceGroup(existingAIServiceSubscription, existingAIServiceResourceGroup)
267+
params: {
268+
roleDefinitionId: cognitiveServicesOpenAIUser.id
269+
roleAssignmentName: guid(resourceGroup().id, aiSearch.id, cognitiveServicesOpenAIUser.id, 'openai-foundry')
242270
aiServicesName: !empty(azureExistingAIProjectResourceId) ? existingAIServicesName : aiServicesName
243-
userassignedIdentityId: managedIdentityObjectId
271+
aiProjectName: !empty(azureExistingAIProjectResourceId) ? existingAIProjectName : aiProjectName
272+
principalId: aiSearch.identity.principalId
273+
}
274+
}
275+
276+
resource searchIndexDataReader 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
277+
name: '1407120a-92aa-4202-b7e9-c0e197c71c8f'
278+
}
279+
280+
resource assignSearchIndexDataReaderToAiProject 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (empty(azureExistingAIProjectResourceId)) {
281+
name: guid(resourceGroup().id, aiProject.id, searchIndexDataReader.id)
282+
scope: aiSearch
283+
properties: {
284+
principalId: aiProject.identity.principalId
285+
roleDefinitionId: searchIndexDataReader.id
286+
principalType: 'ServicePrincipal'
287+
}
288+
}
289+
290+
resource assignSearchIndexDataReaderToExistingAiProject 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(azureExistingAIProjectResourceId)) {
291+
name: guid(resourceGroup().id, existingAIProjectName, searchIndexDataReader.id, 'Existing')
292+
scope: aiSearch
293+
properties: {
294+
principalId: assignOpenAIRoleToAISearch.outputs.aiProjectPrincipalId
295+
roleDefinitionId: searchIndexDataReader.id
296+
principalType: 'ServicePrincipal'
297+
}
298+
}
299+
300+
resource searchServiceContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
301+
name: '7ca78c08-252a-4471-8644-bb5ff32d4ba0'
302+
}
303+
304+
resource assignSearchServiceContributorToAiProject 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (empty(azureExistingAIProjectResourceId)) {
305+
name: guid(resourceGroup().id, aiProject.id, searchServiceContributor.id)
306+
scope: aiSearch
307+
properties: {
308+
principalId: aiProject.identity.principalId
309+
roleDefinitionId: searchServiceContributor.id
310+
principalType: 'ServicePrincipal'
311+
}
312+
}
313+
314+
resource assignSearchServiceContributorToExistingAiProject 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(azureExistingAIProjectResourceId)) {
315+
name: guid(resourceGroup().id, existingAIProjectName, searchServiceContributor.id, 'Existing')
316+
scope: aiSearch
317+
properties: {
318+
principalId: assignOpenAIRoleToAISearch.outputs.aiProjectPrincipalId
319+
roleDefinitionId: searchServiceContributor.id
320+
principalType: 'ServicePrincipal'
321+
}
322+
}
323+
324+
resource searchIndexDataContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
325+
name: '8ebe5a00-799e-43f5-93ac-243d3dce84a7'
326+
}
327+
328+
resource assignSearchIndexDataContributorToMI 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
329+
name: guid(resourceGroup().id, aiProject.id, searchIndexDataContributor.id)
330+
scope: aiSearch
331+
properties: {
332+
principalId: managedIdentityObjectId
333+
roleDefinitionId: searchIndexDataContributor.id
334+
principalType: 'ServicePrincipal'
244335
}
245336
}
246337

@@ -292,6 +383,14 @@ resource azureOpenAIEndpointEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-
292383
}
293384
}
294385

386+
resource azureOpenAIEmbeddingDeploymentModel 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
387+
parent: keyVault
388+
name: 'AZURE-OPENAI-EMBEDDING-MODEL'
389+
properties: {
390+
value: embeddingModel
391+
}
392+
}
393+
295394
resource azureOpenAICUEndpointEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
296395
parent: keyVault
297396
name: 'AZURE-OPENAI-CU-ENDPOINT'
@@ -308,14 +407,6 @@ resource azureOpenAICUApiVersionEntry 'Microsoft.KeyVault/vaults/secrets@2021-11
308407
}
309408
}
310409

311-
resource azureSearchAdminKeyEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
312-
parent: keyVault
313-
name: 'AZURE-SEARCH-KEY'
314-
properties: {
315-
value: aiSearch.listAdminKeys().primaryKey
316-
}
317-
}
318-
319410
resource azureSearchServiceEndpointEntry 'Microsoft.KeyVault/vaults/secrets@2021-11-01-preview' = {
320411
parent: keyVault
321412
name: 'AZURE-SEARCH-ENDPOINT'
@@ -390,6 +481,7 @@ output aiSearchId string = aiSearch.id
390481
output aiSearchTarget string = 'https://${aiSearch.name}.search.windows.net'
391482
output aiSearchService string = aiSearch.name
392483
output aiProjectName string = !empty(existingAIProjectName) ? existingAIProjectName : aiProject.name
484+
output aiSearchConnectionName string = aiSearchConnectionName
393485

394486
output applicationInsightsId string = applicationInsights.id
395487
output logAnalyticsWorkspaceResourceName string = useExisting ? existingLogAnalyticsWorkspace.name : logAnalytics.name

infra/deploy_aifp_aisearch_connection.bicep

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ param existingAIServicesName string
33
param aiSearchName string
44
param aiSearchResourceId string
55
param aiSearchLocation string
6-
param solutionName string
6+
param aiSearchConnectionName string
77

88
resource projectAISearchConnection 'Microsoft.CognitiveServices/accounts/projects/connections@2025-04-01-preview' = {
9-
name: '${existingAIServicesName}/${existingAIProjectName}/myVectorStoreProjectConnectionName-${solutionName}'
9+
name: '${existingAIServicesName}/${existingAIProjectName}/${aiSearchConnectionName}'
1010
properties: {
1111
category: 'CognitiveSearch'
1212
target: 'https://${aiSearchName}.search.windows.net'

infra/deploy_backend_docker.bicep

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ param keyVaultName string
1313
param aiServicesName string
1414
param useLocalBuild string
1515
param azureExistingAIProjectResourceId string = ''
16+
param aiSearchName string
1617
var existingAIServiceSubscription = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[2] : subscription().subscriptionId
1718
var existingAIServiceResourceGroup = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[4] : resourceGroup().name
1819
var existingAIServicesName = !empty(azureExistingAIProjectResourceId) ? split(azureExistingAIProjectResourceId, '/')[8] : ''
@@ -143,6 +144,23 @@ resource keyVaultSecretsUserAssignment 'Microsoft.Authorization/roleAssignments@
143144
}
144145
}
145146

147+
resource aiSearch 'Microsoft.Search/searchServices@2024-06-01-preview' existing = {
148+
name: aiSearchName
149+
}
150+
151+
resource searchIndexDataReader 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
152+
name: '1407120a-92aa-4202-b7e9-c0e197c71c8f'
153+
}
154+
155+
resource searchIndexDataReaderAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
156+
name: guid(appService.name, aiSearch.name, searchIndexDataReader.id)
157+
scope: aiSearch
158+
properties: {
159+
roleDefinitionId: searchIndexDataReader.id
160+
principalId: appService.outputs.identityPrincipalId
161+
}
162+
}
163+
146164
resource aiUser 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
147165
name: '53ca6127-db72-4b80-b1b0-d745d6d5456d'
148166
}

infra/deploy_foundry_role_assignment.bicep

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,25 @@ param principalId string = ''
22
param roleDefinitionId string
33
param roleAssignmentName string = ''
44
param aiServicesName string
5-
param userassignedIdentityId string = ''
5+
param aiProjectName string = ''
66

77
resource aiServices 'Microsoft.CognitiveServices/accounts@2025-04-01-preview' existing = {
88
name: aiServicesName
99
}
1010

11-
resource roleAssignmentToFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(aiServicesName) && !empty(principalId)) {
12-
name: roleAssignmentName
13-
scope: aiServices
14-
properties: {
15-
roleDefinitionId: roleDefinitionId
16-
principalId: principalId
17-
}
11+
resource aiProject 'Microsoft.CognitiveServices/accounts/projects@2025-04-01-preview' existing = if (!empty(aiProjectName)) {
12+
name: aiProjectName
13+
parent: aiServices
1814
}
1915

20-
resource roleAssignmentToManagedIdentity 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(userassignedIdentityId)) {
16+
resource roleAssignmentToFoundry 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
2117
name: roleAssignmentName
2218
scope: aiServices
2319
properties: {
2420
roleDefinitionId: roleDefinitionId
25-
principalId: userassignedIdentityId
26-
principalType: 'ServicePrincipal'
21+
principalId: principalId
2722
}
2823
}
24+
25+
output aiServicesPrincipalId string = aiServices.identity.principalId
26+
output aiProjectPrincipalId string = !empty(aiProjectName) ? aiProject.identity.principalId : ''

0 commit comments

Comments
 (0)