Skip to content

Commit 5905349

Browse files
infra: add processor app RBAC roles for Storage and Cosmos DB
Processor container app also needs Storage Blob Data Contributor and Cosmos DB Contributor roles. Added processorAppServicePrincipalId param to role-assignments and wired it from both avm and bicep main.bicep. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6e50f97 commit 5905349

7 files changed

Lines changed: 197 additions & 11 deletions

File tree

infra/avm/main.bicep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,7 @@ module role_assignments './modules/identity/role-assignments.bicep' = {
505505
aiProjectPrincipalId: aiProjectPrincipalId
506506
aiSearchPrincipalId: ''
507507
backendAppServicePrincipalId: ca_backend_api.outputs.principalId
508+
processorAppServicePrincipalId: ca_processor.outputs.principalId
508509
cosmosDbAccountName: cosmosDBModule.outputs.name
509510
}
510511
scope: resourceGroup(resourceGroup().name)

infra/avm/main.json

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"_generator": {
77
"name": "bicep",
88
"version": "0.43.8.12551",
9-
"templateHash": "15764079419575495208"
9+
"templateHash": "12508925618781201963"
1010
}
1111
},
1212
"parameters": {
@@ -37788,6 +37788,9 @@
3778837788
"backendAppServicePrincipalId": {
3778937789
"value": "[reference('ca_backend_api').outputs.principalId.value]"
3779037790
},
37791+
"processorAppServicePrincipalId": {
37792+
"value": "[reference('ca_processor').outputs.principalId.value]"
37793+
},
3779137794
"cosmosDbAccountName": {
3779237795
"value": "[reference('cosmosDBModule').outputs.name.value]"
3779337796
}
@@ -37799,7 +37802,7 @@
3779937802
"_generator": {
3780037803
"name": "bicep",
3780137804
"version": "0.43.8.12551",
37802-
"templateHash": "16220137308567374453"
37805+
"templateHash": "2474904975964647902"
3780337806
}
3780437807
},
3780537808
"parameters": {
@@ -37845,6 +37848,13 @@
3784537848
"description": "Principal ID of the backend App Service system-assigned identity (empty if not deployed)."
3784637849
}
3784737850
},
37851+
"processorAppServicePrincipalId": {
37852+
"type": "string",
37853+
"defaultValue": "",
37854+
"metadata": {
37855+
"description": "Principal ID of the processor App Service system-assigned identity (empty if not deployed)."
37856+
}
37857+
},
3784837858
"aiFoundryResourceId": {
3784937859
"type": "string",
3785037860
"defaultValue": "",
@@ -37997,6 +38007,18 @@
3799738007
"principalType": "ServicePrincipal"
3799838008
}
3799938009
},
38010+
{
38011+
"condition": "[and(not(empty(parameters('storageAccountResourceId'))), not(empty(parameters('processorAppServicePrincipalId'))))]",
38012+
"type": "Microsoft.Authorization/roleAssignments",
38013+
"apiVersion": "2022-04-01",
38014+
"scope": "[resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/')))]",
38015+
"name": "[guid(parameters('solutionName'), resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), parameters('processorAppServicePrincipalId'), variables('roleDefinitions').storageBlobDataContributor)]",
38016+
"properties": {
38017+
"principalId": "[parameters('processorAppServicePrincipalId')]",
38018+
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]",
38019+
"principalType": "ServicePrincipal"
38020+
}
38021+
},
3800038022
{
3800138023
"condition": "[and(not(empty(parameters('cosmosDbAccountName'))), not(empty(parameters('backendAppServicePrincipalId'))))]",
3800238024
"type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments",
@@ -38008,6 +38030,17 @@
3800838030
"scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName'))]"
3800938031
}
3801038032
},
38033+
{
38034+
"condition": "[and(not(empty(parameters('cosmosDbAccountName'))), not(empty(parameters('processorAppServicePrincipalId'))))]",
38035+
"type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments",
38036+
"apiVersion": "2025-10-15",
38037+
"name": "[format('{0}/{1}', parameters('cosmosDbAccountName'), guid(parameters('solutionName'), resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('cosmosDbAccountName'), '00000000-0000-0000-0000-000000000002'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName')), parameters('processorAppServicePrincipalId')))]",
38038+
"properties": {
38039+
"principalId": "[parameters('processorAppServicePrincipalId')]",
38040+
"roleDefinitionId": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('cosmosDbAccountName'), '00000000-0000-0000-0000-000000000002')]",
38041+
"scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName'))]"
38042+
}
38043+
},
3801138044
{
3801238045
"condition": "[and(parameters('useExistingAIProject'), not(empty(parameters('aiSearchPrincipalId'))))]",
3801338046
"type": "Microsoft.Resources/deployments",
@@ -38192,6 +38225,7 @@
3819238225
"dependsOn": [
3819338226
"ai_foundry_project",
3819438227
"ca_backend_api",
38228+
"ca_processor",
3819538229
"cosmosDBModule",
3819638230
"existing_project_setup",
3819738231
"storage_account"

infra/avm/modules/identity/role-assignments.bicep

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ param aiSearchPrincipalId string = ''
2828
@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).')
2929
param backendAppServicePrincipalId string = ''
3030

31+
@description('Principal ID of the processor App Service system-assigned identity (empty if not deployed).')
32+
param processorAppServicePrincipalId string = ''
33+
3134
// --- Resource References ---
3235

3336
@description('Resource ID of the AI Foundry account (empty if not deployed — new project path).')
@@ -227,9 +230,20 @@ resource backendAppStorageContributor 'Microsoft.Authorization/roleAssignments@2
227230
}
228231
}
229232

233+
// Processor App → Storage Blob Data Contributor
234+
resource processorAppStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(processorAppServicePrincipalId)) {
235+
name: guid(solutionName, storageAccount.id, processorAppServicePrincipalId, roleDefinitions.storageBlobDataContributor)
236+
scope: storageAccount
237+
properties: {
238+
principalId: processorAppServicePrincipalId
239+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor)
240+
principalType: 'ServicePrincipal'
241+
}
242+
}
243+
230244
// ============================================================================
231245
// 4. COSMOS DB ROLE ASSIGNMENTS
232-
// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments)
246+
// Backend and Processor App Service → Cosmos DB (data-plane, uses sqlRoleAssignments)
233247
// ============================================================================
234248

235249
resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) {
@@ -242,3 +256,13 @@ resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/s
242256
}
243257
}
244258

259+
resource processorAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(processorAppServicePrincipalId)) {
260+
parent: cosmosAccount
261+
name: guid(solutionName, cosmosContributorRoleDefinition.id, cosmosAccount.id, processorAppServicePrincipalId)
262+
properties: {
263+
principalId: processorAppServicePrincipalId
264+
roleDefinitionId: cosmosContributorRoleDefinition.id
265+
scope: cosmosAccount.id
266+
}
267+
}
268+

infra/bicep/main.bicep

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ module role_assignments './modules/identity/role-assignments.bicep' = {
460460
deployerPrincipalId: deployingUserPrincipalId
461461
deployerPrincipalType: deployingUserPrincipalType
462462
backendAppServicePrincipalId: ca_backend_api.outputs.principalId
463+
processorAppServicePrincipalId: ca_processor.outputs.principalId
463464
cosmosDbAccountName: cosmosDBModule.outputs.name
464465
}
465466
scope: resourceGroup(resourceGroup().name)

infra/bicep/main.json

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"_generator": {
66
"name": "bicep",
77
"version": "0.43.8.12551",
8-
"templateHash": "2315337546245675369"
8+
"templateHash": "8972167897125395354"
99
}
1010
},
1111
"parameters": {
@@ -2571,6 +2571,9 @@
25712571
"backendAppServicePrincipalId": {
25722572
"value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ca-backend-api.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]"
25732573
},
2574+
"processorAppServicePrincipalId": {
2575+
"value": "[reference(resourceId('Microsoft.Resources/deployments', take(format('module.ca-processor.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.principalId.value]"
2576+
},
25742577
"cosmosDbAccountName": {
25752578
"value": "[reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', take(format('module.cosmos-db.{0}', parameters('solutionName')), 64)), '2025-04-01').outputs.name.value]"
25762579
}
@@ -2582,7 +2585,7 @@
25822585
"_generator": {
25832586
"name": "bicep",
25842587
"version": "0.43.8.12551",
2585-
"templateHash": "17859174180959627964"
2588+
"templateHash": "14585030683408144049"
25862589
}
25872590
},
25882591
"parameters": {
@@ -2628,6 +2631,13 @@
26282631
"description": "Principal ID of the backend App Service system-assigned identity (empty if not deployed)."
26292632
}
26302633
},
2634+
"processorAppServicePrincipalId": {
2635+
"type": "string",
2636+
"defaultValue": "",
2637+
"metadata": {
2638+
"description": "Principal ID of the processor App Service system-assigned identity (empty if not deployed)."
2639+
}
2640+
},
26312641
"deployerPrincipalId": {
26322642
"type": "string",
26332643
"defaultValue": "",
@@ -2799,6 +2809,18 @@
27992809
"principalType": "ServicePrincipal"
28002810
}
28012811
},
2812+
{
2813+
"condition": "[and(not(empty(parameters('storageAccountResourceId'))), not(empty(parameters('processorAppServicePrincipalId'))))]",
2814+
"type": "Microsoft.Authorization/roleAssignments",
2815+
"apiVersion": "2022-04-01",
2816+
"scope": "[resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/')))]",
2817+
"name": "[guid(parameters('solutionName'), resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), parameters('processorAppServicePrincipalId'), variables('roleDefinitions').storageBlobDataContributor)]",
2818+
"properties": {
2819+
"principalId": "[parameters('processorAppServicePrincipalId')]",
2820+
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('roleDefinitions').storageBlobDataContributor)]",
2821+
"principalType": "ServicePrincipal"
2822+
}
2823+
},
28022824
{
28032825
"condition": "[and(not(empty(parameters('cosmosDbAccountName'))), not(empty(parameters('backendAppServicePrincipalId'))))]",
28042826
"type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments",
@@ -2810,6 +2832,17 @@
28102832
"scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName'))]"
28112833
}
28122834
},
2835+
{
2836+
"condition": "[and(not(empty(parameters('cosmosDbAccountName'))), not(empty(parameters('processorAppServicePrincipalId'))))]",
2837+
"type": "Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments",
2838+
"apiVersion": "2025-10-15",
2839+
"name": "[format('{0}/{1}', parameters('cosmosDbAccountName'), guid(parameters('solutionName'), resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('cosmosDbAccountName'), '00000000-0000-0000-0000-000000000002'), resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName')), parameters('processorAppServicePrincipalId')))]",
2840+
"properties": {
2841+
"principalId": "[parameters('processorAppServicePrincipalId')]",
2842+
"roleDefinitionId": "[resourceId('Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions', parameters('cosmosDbAccountName'), '00000000-0000-0000-0000-000000000002')]",
2843+
"scope": "[resourceId('Microsoft.DocumentDB/databaseAccounts', parameters('cosmosDbAccountName'))]"
2844+
}
2845+
},
28132846
{
28142847
"condition": "[and(and(not(parameters('useExistingAIProject')), not(empty(parameters('deployerPrincipalId')))), not(empty(parameters('aiFoundryResourceId'))))]",
28152848
"type": "Microsoft.Authorization/roleAssignments",
@@ -3054,6 +3087,7 @@
30543087
"dependsOn": [
30553088
"[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', take(format('module.ai-foundry-project.{0}', parameters('solutionName')), 64))]",
30563089
"[resourceId('Microsoft.Resources/deployments', take(format('module.ca-backend-api.{0}', parameters('solutionName')), 64))]",
3090+
"[resourceId('Microsoft.Resources/deployments', take(format('module.ca-processor.{0}', parameters('solutionName')), 64))]",
30573091
"[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', take(format('module.cosmos-db.{0}', parameters('solutionName')), 64))]",
30583092
"[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', variables('aiServiceSubscription'), variables('aiServiceResourceGroup')), 'Microsoft.Resources/deployments', take(format('module.existing-project-setup.{0}', parameters('solutionName')), 64))]",
30593093
"[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, resourceGroup().name), 'Microsoft.Resources/deployments', take(format('module.storage-account.{0}', parameters('solutionName')), 64))]"

infra/bicep/modules/identity/role-assignments.bicep

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ param aiSearchPrincipalId string = ''
2828
@description('Principal ID of the backend App Service system-assigned identity (empty if not deployed).')
2929
param backendAppServicePrincipalId string = ''
3030

31+
@description('Principal ID of the processor App Service system-assigned identity (empty if not deployed).')
32+
param processorAppServicePrincipalId string = ''
33+
3134
@description('Principal ID of the deploying user (for user access roles).')
3235
param deployerPrincipalId string = ''
3336

@@ -235,9 +238,20 @@ resource backendAppStorageContributor 'Microsoft.Authorization/roleAssignments@2
235238
}
236239
}
237240

241+
// Processor App → Storage Blob Data Contributor
242+
resource processorAppStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (!empty(storageAccountResourceId) && !empty(processorAppServicePrincipalId)) {
243+
name: guid(solutionName, storageAccount.id, processorAppServicePrincipalId, roleDefinitions.storageBlobDataContributor)
244+
scope: storageAccount
245+
properties: {
246+
principalId: processorAppServicePrincipalId
247+
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitions.storageBlobDataContributor)
248+
principalType: 'ServicePrincipal'
249+
}
250+
}
251+
238252
// ============================================================================
239253
// 4. COSMOS DB ROLE ASSIGNMENTS
240-
// Backend App Service → Cosmos DB (data-plane, uses sqlRoleAssignments)
254+
// Backend and Processor App Service → Cosmos DB (data-plane, uses sqlRoleAssignments)
241255
// ============================================================================
242256

243257
resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(backendAppServicePrincipalId)) {
@@ -250,6 +264,16 @@ resource backendAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/s
250264
}
251265
}
252266

267+
resource processorAppCosmosRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2025-10-15' = if (!empty(cosmosDbAccountName) && !empty(processorAppServicePrincipalId)) {
268+
parent: cosmosAccount
269+
name: guid(solutionName, cosmosContributorRoleDefinition.id, cosmosAccount.id, processorAppServicePrincipalId)
270+
properties: {
271+
principalId: processorAppServicePrincipalId
272+
roleDefinitionId: cosmosContributorRoleDefinition.id
273+
scope: cosmosAccount.id
274+
}
275+
}
276+
253277
// ============================================================================
254278
// 5. DEPLOYER (USER) ROLE ASSIGNMENTS
255279
// Deploying user → AI Services, Search, Storage (Bicep-only)

0 commit comments

Comments
 (0)