Skip to content

Commit 476d10f

Browse files
infra: enable system-assigned identity, add all toolkit modules, sync private-dns-zone and app-service updates
- Enable system-assigned managed identity on all 3 container apps (backend, frontend, processor) in both avm and bicep flavors - Add all missing toolkit core modules (29 modules: ai-services, ai-search, app-service, container-instance, container-registry, function-app, kubernetes, cosmos-db-mongo, event-grid, event-hub, postgresql, sql-database, app-configuration, managed-identity, fabric-capacity, portal-dashboard, workbook, key-vault, etc.) - Sync private-dns-zone.bicep with latest toolkit (added A records param, updated deployment name) - Sync app-service.bicep with latest toolkit (added vnet routing, private endpoints params) - Remove dead parameter files (bicep/main.parameters.json, bicep/main.waf.parameters.json) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f1a38eb commit 476d10f

49 files changed

Lines changed: 3971 additions & 90 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

infra/avm/main.bicep

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ module ca_backend_api './modules/compute/container-app.bicep' = {
334334
location: solutionLocation
335335
tags: union(existingTags, tags, { TemplateName: 'Container Migration' })
336336
environmentResourceId: containerAppEnv.outputs.resourceId
337+
managedIdentities: { systemAssigned: true }
337338
ingressExternal: true
338339
ingressTargetPort: 80
339340
enableTelemetry: enableTelemetry
@@ -387,6 +388,7 @@ module ca_frontend './modules/compute/container-app.bicep' = {
387388
location: solutionLocation
388389
tags: union(existingTags, tags, { TemplateName: 'Container Migration' })
389390
environmentResourceId: containerAppEnv.outputs.resourceId
391+
managedIdentities: { systemAssigned: true }
390392
ingressExternal: true
391393
ingressTargetPort: 3000
392394
enableTelemetry: enableTelemetry
@@ -422,6 +424,7 @@ module ca_processor './modules/compute/container-app.bicep' = {
422424
location: solutionLocation
423425
tags: union(existingTags, tags, { TemplateName: 'Container Migration' })
424426
environmentResourceId: containerAppEnv.outputs.resourceId
427+
managedIdentities: { systemAssigned: true }
425428
ingressExternal: false
426429
ingressTargetPort: 8080
427430
ingressAllowInsecure: true

infra/avm/main.json

Lines changed: 16 additions & 1 deletion
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": "1299675852282484186"
9+
"templateHash": "12751579259960962504"
1010
}
1111
},
1212
"parameters": {
@@ -22725,6 +22725,11 @@
2272522725
"environmentResourceId": {
2272622726
"value": "[reference('containerAppEnv').outputs.resourceId.value]"
2272722727
},
22728+
"managedIdentities": {
22729+
"value": {
22730+
"systemAssigned": true
22731+
}
22732+
},
2272822733
"ingressExternal": {
2272922734
"value": true
2273022735
},
@@ -24646,6 +24651,11 @@
2464624651
"environmentResourceId": {
2464724652
"value": "[reference('containerAppEnv').outputs.resourceId.value]"
2464824653
},
24654+
"managedIdentities": {
24655+
"value": {
24656+
"systemAssigned": true
24657+
}
24658+
},
2464924659
"ingressExternal": {
2465024660
"value": true
2465124661
},
@@ -26493,6 +26503,11 @@
2649326503
"environmentResourceId": {
2649426504
"value": "[reference('containerAppEnv').outputs.resourceId.value]"
2649526505
},
26506+
"managedIdentities": {
26507+
"value": {
26508+
"systemAssigned": true
26509+
}
26510+
},
2649626511
"ingressExternal": {
2649726512
"value": false
2649826513
},
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// ============================================================================
2+
// Module: AI Search
3+
// Description: Deploys Azure AI Search with a two-step pattern:
4+
// Step 1: Plain Bicep resource for fast initial creation (name, location, SKU)
5+
// Step 2: AVM module update to enable managed identity & full configuration
6+
// This reduces deployment time by making the resource available immediately
7+
// while identity enablement proceeds separately.
8+
// AVM Module: avm/res/search/search-service:0.12.0
9+
// WAF: https://learn.microsoft.com/azure/well-architected/service-guides/azure-cognitive-search
10+
// ============================================================================
11+
12+
@description('Solution name suffix used to derive the resource name.')
13+
@minLength(3)
14+
param solutionName string
15+
16+
@description('Optional. Override name for the search service. Defaults to srch-{solutionName}.')
17+
param name string = 'srch-${solutionName}'
18+
19+
@description('Azure region for the resource.')
20+
param location string
21+
22+
@description('Tags to apply to the resource.')
23+
param tags object = {}
24+
25+
@description('SKU name for the search service.')
26+
@allowed(['free', 'basic', 'standard', 'standard2', 'standard3', 'storage_optimized_l1', 'storage_optimized_l2'])
27+
param skuName string = 'basic'
28+
29+
@description('Number of replicas.')
30+
param replicaCount int = 1
31+
32+
@description('Number of partitions.')
33+
param partitionCount int = 1
34+
35+
@description('Hosting mode.')
36+
@allowed(['Default', 'HighDensity'])
37+
param hostingMode string = 'Default'
38+
39+
@description('Semantic search tier.')
40+
@allowed(['disabled', 'free', 'standard'])
41+
param semanticSearch string = 'free'
42+
43+
@description('Whether to disable local authentication.')
44+
param disableLocalAuth bool = true
45+
46+
@description('Managed identity type for the search service.')
47+
param managedIdentityType string = 'SystemAssigned'
48+
49+
@description('Public network access setting.')
50+
param publicNetworkAccess string = 'Enabled'
51+
52+
// --- WAF: Telemetry ---
53+
@description('Optional. Enable/Disable usage telemetry for module.')
54+
param enableTelemetry bool = true
55+
56+
// --- WAF: Monitoring ---
57+
@description('Diagnostic settings for monitoring.')
58+
param diagnosticSettings array = []
59+
60+
// --- WAF: Private Networking ---
61+
@description('Private endpoint configurations.')
62+
param privateEndpoints array = []
63+
64+
// --- Role Assignments ---
65+
@description('Optional. Array of role assignments to create on the AI Search service.')
66+
param roleAssignments array = []
67+
68+
// ============================================================================
69+
// Step 1: Initial resource creation (plain Bicep — fast)
70+
// ============================================================================
71+
resource searchService 'Microsoft.Search/searchServices@2025-05-01' = {
72+
name: name
73+
location: location
74+
sku: {
75+
name: skuName
76+
}
77+
}
78+
79+
// ============================================================================
80+
// Step 2: AVM update — enables identity & full configuration
81+
// ============================================================================
82+
module searchServiceUpdate 'br/public:avm/res/search/search-service:0.12.0' = {
83+
name: take('avm.res.search.update.${name}', 64)
84+
params: {
85+
name: name
86+
location: location
87+
tags: tags
88+
enableTelemetry: enableTelemetry
89+
sku: skuName
90+
replicaCount: replicaCount
91+
partitionCount: partitionCount
92+
hostingMode: hostingMode
93+
semanticSearch: semanticSearch
94+
disableLocalAuth: disableLocalAuth
95+
publicNetworkAccess: publicNetworkAccess
96+
managedIdentities: {
97+
systemAssigned: managedIdentityType == 'SystemAssigned'
98+
}
99+
diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : []
100+
privateEndpoints: privateEndpoints
101+
roleAssignments: !empty(roleAssignments) ? roleAssignments : []
102+
}
103+
dependsOn: [
104+
searchService
105+
]
106+
}
107+
108+
// ============================================================================
109+
// Outputs
110+
// ============================================================================
111+
@description('Resource ID of the AI Search service.')
112+
output resourceId string = searchService.id
113+
114+
@description('Name of the AI Search service.')
115+
output name string = searchService.name
116+
117+
@description('Endpoint URL of the AI Search service.')
118+
output endpoint string = 'https://${searchService.name}.search.windows.net'
119+
120+
@description('System-assigned identity principal ID.')
121+
output identityPrincipalId string = searchServiceUpdate.outputs.?systemAssignedMIPrincipalId ?? ''
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// ============================================================================
2+
// Module: Azure AI Services (Generic)
3+
// Description: AVM wrapper for Cognitive Services — supports Content Safety,
4+
// Speech, Computer Vision, Document Intelligence, and others.
5+
// AVM Module: avm/res/cognitive-services/account:0.14.2
6+
// ============================================================================
7+
8+
@description('Solution name suffix used to derive the resource name.')
9+
param solutionName string
10+
11+
@description('Name prefix for the resource (e.g., cs, speech, cv, docintel).')
12+
param namePrefix string
13+
14+
@description('The kind of Cognitive Service to deploy.')
15+
@allowed([
16+
'ContentSafety'
17+
'SpeechServices'
18+
'ComputerVision'
19+
'FormRecognizer'
20+
'TextAnalytics'
21+
'TextTranslation'
22+
'Face'
23+
'OpenAI'
24+
'AIServices'
25+
])
26+
param kind string
27+
28+
@description('Optional. Override name for the resource. Defaults to {namePrefix}-{solutionName}.')
29+
param name string = '${namePrefix}-${solutionName}'
30+
31+
@description('Azure region for the resource.')
32+
param location string
33+
34+
@description('Tags to apply to the resource.')
35+
param tags object = {}
36+
37+
@description('Optional. Enable/Disable usage telemetry for module.')
38+
param enableTelemetry bool = false
39+
40+
@description('SKU for the Cognitive Services account.')
41+
@allowed(['F0', 'S0', 'S1'])
42+
param sku string = 'S0'
43+
44+
@description('Custom subdomain name for the account.')
45+
param customSubDomainName string = ''
46+
47+
@description('Disable local (key-based) authentication.')
48+
param disableLocalAuth bool = true
49+
50+
@description('Public network access setting.')
51+
@allowed(['Enabled', 'Disabled'])
52+
param publicNetworkAccess string = 'Enabled'
53+
54+
@description('Whether to enable private networking.')
55+
param enablePrivateNetworking bool = false
56+
57+
@description('Subnet resource ID for the private endpoint.')
58+
param privateEndpointSubnetId string = ''
59+
60+
@description('Private DNS zone resource IDs.')
61+
param privateDnsZoneResourceIds array = []
62+
63+
@description('Diagnostic settings for monitoring.')
64+
param diagnosticSettings array = []
65+
66+
@description('Optional. Role assignments for the resource.')
67+
param roleAssignments array = []
68+
69+
var effectiveSubDomain = !empty(customSubDomainName) ? customSubDomainName : name
70+
71+
var privateDnsZoneConfigs = [for (zoneId, i) in privateDnsZoneResourceIds: {
72+
name: 'dns-zone-${i}'
73+
privateDnsZoneResourceId: zoneId
74+
}]
75+
76+
// ============================================================================
77+
// AVM Module Deployment
78+
// ============================================================================
79+
module aiService 'br/public:avm/res/cognitive-services/account:0.14.2' = {
80+
name: take('avm.res.cognitive-services.${namePrefix}.${name}', 64)
81+
params: {
82+
name: name
83+
location: location
84+
tags: tags
85+
enableTelemetry: enableTelemetry
86+
kind: kind
87+
sku: sku
88+
customSubDomainName: effectiveSubDomain
89+
disableLocalAuth: disableLocalAuth
90+
managedIdentities: { systemAssigned: true }
91+
publicNetworkAccess: publicNetworkAccess
92+
diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : []
93+
roleAssignments: !empty(roleAssignments) ? roleAssignments : []
94+
privateEndpoints: enablePrivateNetworking ? [
95+
{
96+
name: 'pep-${name}'
97+
customNetworkInterfaceName: 'nic-${name}'
98+
subnetResourceId: privateEndpointSubnetId
99+
service: 'account'
100+
privateDnsZoneGroup: {
101+
privateDnsZoneGroupConfigs: privateDnsZoneConfigs
102+
}
103+
}
104+
] : []
105+
}
106+
}
107+
108+
// ============================================================================
109+
// Outputs
110+
// ============================================================================
111+
@description('Name of the AI Services account.')
112+
output name string = aiService.outputs.name
113+
114+
@description('Resource ID of the AI Services account.')
115+
output resourceId string = aiService.outputs.resourceId
116+
117+
@description('Endpoint of the AI Services account.')
118+
output endpoint string = aiService.outputs.endpoint
119+
120+
@description('System-assigned identity principal ID.')
121+
output identityPrincipalId string = aiService.outputs.?systemAssignedMIPrincipalId ?? ''
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// ============================================================================
2+
// Module: App Service Plan
3+
// Description: AVM wrapper for Azure App Service Plan
4+
// AVM Module: avm/res/web/serverfarm:0.7.0
5+
// ============================================================================
6+
7+
@description('Solution name suffix used to derive the resource name.')
8+
param solutionName string
9+
10+
@description('Name of the App Service Plan.')
11+
param name string = 'asp-${solutionName}'
12+
13+
@description('Azure region for the resource.')
14+
param location string
15+
16+
@description('Tags to apply to the resource.')
17+
param tags object = {}
18+
19+
@description('SKU name for the App Service Plan.')
20+
@allowed(['F1', 'D1', 'B1', 'B2', 'B3', 'S1', 'S2', 'S3', 'P1', 'P2', 'P3', 'P4', 'P0v3', 'P0v4', 'P1v3', 'P1v4', 'P2v3', 'P3v3'])
21+
param skuName string = 'B2'
22+
23+
@description('Whether the plan is Linux-based.')
24+
param reserved bool = true
25+
26+
@description('Kind of the App Service Plan.')
27+
param kind string = 'linux'
28+
29+
@description('Optional. Enable/Disable usage telemetry for module.')
30+
param enableTelemetry bool = true
31+
32+
@description('Number of instances (workers).')
33+
param skuCapacity int = 1
34+
35+
@description('Diagnostic settings for monitoring.')
36+
param diagnosticSettings array = []
37+
38+
@description('Enable zone redundancy. Requires Premium SKU (P1v3+).')
39+
param zoneRedundant bool = false
40+
41+
// ============================================================================
42+
// AVM Module Deployment
43+
// ============================================================================
44+
module appServicePlan 'br/public:avm/res/web/serverfarm:0.7.0' = {
45+
name: take('avm.res.web.serverfarm.${name}', 64)
46+
params: {
47+
name: name
48+
location: location
49+
tags: tags
50+
enableTelemetry: enableTelemetry
51+
skuName: skuName
52+
skuCapacity: skuCapacity
53+
reserved: reserved
54+
kind: kind
55+
diagnosticSettings: !empty(diagnosticSettings) ? diagnosticSettings : []
56+
zoneRedundant: zoneRedundant
57+
}
58+
}
59+
60+
// ============================================================================
61+
// Outputs
62+
// ============================================================================
63+
@description('Resource ID of the App Service Plan.')
64+
output resourceId string = appServicePlan.outputs.resourceId
65+
66+
@description('Name of the App Service Plan.')
67+
output name string = appServicePlan.outputs.name

0 commit comments

Comments
 (0)