-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathmain.bicep
More file actions
232 lines (217 loc) · 7.64 KB
/
main.bicep
File metadata and controls
232 lines (217 loc) · 7.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
targetScope = 'subscription'
@minLength(1)
@maxLength(64)
@description('Name of the the environment which is used to generate a short unique hash used in all resources.')
param environmentName string
@minLength(1)
@description('Primary location for all resources & Flex Consumption Function App')
@allowed([
'australiaeast'
'australiasoutheast'
'brazilsouth'
'canadacentral'
'centralindia'
'centralus'
'eastasia'
'eastus'
'eastus2'
'eastus2euap'
'francecentral'
'germanywestcentral'
'italynorth'
'japaneast'
'koreacentral'
'northcentralus'
'northeurope'
'norwayeast'
'southafricanorth'
'southcentralus'
'southeastasia'
'southindia'
'spaincentral'
'swedencentral'
'uaenorth'
'uksouth'
'ukwest'
'westcentralus'
'westeurope'
'westus'
'westus2'
'westus3'
])
@metadata({
azd: {
type: 'location'
}
})
param location string
param vnetEnabled bool
param apiServiceName string = ''
param apiUserAssignedIdentityName string = ''
param applicationInsightsName string = ''
param appServicePlanName string = ''
param logAnalyticsName string = ''
param resourceGroupName string = ''
param storageAccountName string = ''
param vNetName string = ''
@description('Id of the user identity to be used for testing and debugging. This is not required in production. Leave empty if not needed.')
param principalId string = ''
var abbrs = loadJsonContent('./abbreviations.json')
var resourceToken = toLower(uniqueString(subscription().id, environmentName, location))
var tags = { 'azd-env-name': environmentName }
var functionAppName = !empty(apiServiceName) ? apiServiceName : '${abbrs.webSitesFunctions}api-${resourceToken}'
var deploymentStorageContainerName = 'app-package-${take(functionAppName, 32)}-${take(toLower(uniqueString(functionAppName, resourceToken)), 7)}'
// Organize resources in a resource group
resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}'
location: location
tags: tags
}
// User assigned managed identity to be used by the function app to reach storage and other dependencies
// Assign specific roles to this identity in the RBAC module
module apiUserAssignedIdentity 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.1' = {
name: 'apiUserAssignedIdentity'
scope: rg
params: {
location: location
tags: tags
name: !empty(apiUserAssignedIdentityName) ? apiUserAssignedIdentityName : '${abbrs.managedIdentityUserAssignedIdentities}api-${resourceToken}'
}
}
// Create an App Service Plan to group applications under the same payment plan and SKU
module appServicePlan 'br/public:avm/res/web/serverfarm:0.1.1' = {
name: 'appserviceplan'
scope: rg
params: {
name: !empty(appServicePlanName) ? appServicePlanName : '${abbrs.webServerFarms}${resourceToken}'
sku: {
name: 'FC1'
tier: 'FlexConsumption'
}
reserved: true
location: location
tags: tags
}
}
module api './app/api.bicep' = {
name: 'api'
scope: rg
params: {
name: functionAppName
location: location
tags: tags
applicationInsightsName: monitoring.outputs.name
appServicePlanId: appServicePlan.outputs.resourceId
runtimeName: 'python'
runtimeVersion: '3.12'
storageAccountName: storage.outputs.name
enableBlob: storageEndpointConfig.enableBlob
enableQueue: storageEndpointConfig.enableQueue
enableTable: storageEndpointConfig.enableTable
deploymentStorageContainerName: deploymentStorageContainerName
identityId: apiUserAssignedIdentity.outputs.resourceId
identityClientId: apiUserAssignedIdentity.outputs.clientId
appSettings: {
}
virtualNetworkSubnetId: vnetEnabled ? serviceVirtualNetwork.outputs.appSubnetID : ''
}
}
// Backing storage for Azure functions backend API
module storage 'br/public:avm/res/storage/storage-account:0.8.3' = {
name: 'storage'
scope: rg
params: {
name: !empty(storageAccountName) ? storageAccountName : '${abbrs.storageStorageAccounts}${resourceToken}'
allowBlobPublicAccess: false
allowSharedKeyAccess: false // Disable local authentication methods as per policy
dnsEndpointType: 'Standard'
publicNetworkAccess: vnetEnabled ? 'Disabled' : 'Enabled'
networkAcls: vnetEnabled ? {
defaultAction: 'Deny'
bypass: 'None'
} : {
defaultAction: 'Allow'
bypass: 'AzureServices'
}
blobServices: {
containers: [{name: deploymentStorageContainerName}]
}
minimumTlsVersion: 'TLS1_2' // Enforcing TLS 1.2 for better security
location: location
tags: tags
}
}
// Define the configuration object locally to pass to the modules
var storageEndpointConfig = {
enableBlob: true // Required for AzureWebJobsStorage, .zip deployment, Event Hubs trigger and Timer trigger checkpointing
enableQueue: false // Required for Durable Functions and MCP trigger
enableTable: false // Required for Durable Functions and OpenAI triggers and bindings
enableFiles: false // Not required, used in legacy scenarios
allowUserIdentityPrincipal: true // Allow interactive user identity to access for testing and debugging
}
// Consolidated Role Assignments
module rbac 'app/rbac.bicep' = {
name: 'rbacAssignments'
scope: rg
params: {
storageAccountName: storage.outputs.name
appInsightsName: monitoring.outputs.name
managedIdentityPrincipalId: apiUserAssignedIdentity.outputs.principalId
userIdentityPrincipalId: principalId
enableBlob: storageEndpointConfig.enableBlob
enableQueue: storageEndpointConfig.enableQueue
enableTable: storageEndpointConfig.enableTable
allowUserIdentityPrincipal: storageEndpointConfig.allowUserIdentityPrincipal
}
}
// Virtual Network & private endpoint to blob storage
module serviceVirtualNetwork 'app/vnet.bicep' = if (vnetEnabled) {
name: 'serviceVirtualNetwork'
scope: rg
params: {
location: location
tags: tags
vNetName: !empty(vNetName) ? vNetName : '${abbrs.networkVirtualNetworks}${resourceToken}'
}
}
module storagePrivateEndpoint 'app/storage-PrivateEndpoint.bicep' = if (vnetEnabled) {
name: 'servicePrivateEndpoint'
scope: rg
params: {
location: location
tags: tags
virtualNetworkName: !empty(vNetName) ? vNetName : '${abbrs.networkVirtualNetworks}${resourceToken}'
subnetName: vnetEnabled ? serviceVirtualNetwork.outputs.peSubnetName : '' // Keep conditional check for safety, though module won't run if !vnetEnabled
resourceName: storage.outputs.name
enableBlob: storageEndpointConfig.enableBlob
enableQueue: storageEndpointConfig.enableQueue
enableTable: storageEndpointConfig.enableTable
}
}
// Monitor application with Azure Monitor - Log Analytics and Application Insights
module logAnalytics 'br/public:avm/res/operational-insights/workspace:0.7.0' = {
name: '${uniqueString(deployment().name, location)}-loganalytics'
scope: rg
params: {
name: !empty(logAnalyticsName) ? logAnalyticsName : '${abbrs.operationalInsightsWorkspaces}${resourceToken}'
location: location
tags: tags
dataRetention: 30
}
}
module monitoring 'br/public:avm/res/insights/component:0.4.1' = {
name: '${uniqueString(deployment().name, location)}-appinsights'
scope: rg
params: {
name: !empty(applicationInsightsName) ? applicationInsightsName : '${abbrs.insightsComponents}${resourceToken}'
location: location
tags: tags
workspaceResourceId: logAnalytics.outputs.resourceId
disableLocalAuth: true
}
}
// App outputs
output AZURE_LOCATION string = location
output AZURE_TENANT_ID string = tenant().tenantId
output SERVICE_API_NAME string = api.outputs.SERVICE_API_NAME
output AZURE_FUNCTION_NAME string = api.outputs.SERVICE_API_NAME