Skip to content

Commit 1189edd

Browse files
authored
Merge pull request #13 from paulyuk/avm
Modernizing Bicep to AVM (python, mcp)
2 parents 3fafc5b + 1bfc97c commit 1189edd

16 files changed

Lines changed: 448 additions & 502 deletions

azure.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
name: remote-mcp-functions-python
44
metadata:
5-
template: remote-mcp-functions-python@1.0.0
5+
template: remote-mcp-functions-python@1.0.1
66
services:
77
api:
88
project: ./src/

infra/app/api.bicep

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
param name string
2+
@description('Primary location for all resources & Flex Consumption Function App')
23
param location string = resourceGroup().location
34
param tags object = {}
45
param applicationInsightsName string = ''
@@ -14,33 +15,95 @@ param instanceMemoryMB int = 2048
1415
param maximumInstanceCount int = 100
1516
param identityId string = ''
1617
param identityClientId string = ''
18+
param enableBlob bool = true
19+
param enableQueue bool = false
20+
param enableTable bool = false
21+
param enableFile bool = false
22+
23+
@allowed(['SystemAssigned', 'UserAssigned'])
24+
param identityType string = 'UserAssigned'
1725

1826
var applicationInsightsIdentity = 'ClientId=${identityClientId};Authorization=AAD'
27+
var kind = 'functionapp,linux'
28+
29+
// Create base application settings
30+
var baseAppSettings = {
31+
// Only include required credential settings unconditionally
32+
AzureWebJobsStorage__credential: 'managedidentity'
33+
AzureWebJobsStorage__clientId: identityClientId
34+
35+
// Application Insights settings are always included
36+
APPLICATIONINSIGHTS_AUTHENTICATION_STRING: applicationInsightsIdentity
37+
APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString
38+
}
39+
40+
// Dynamically build storage endpoint settings based on feature flags
41+
var blobSettings = enableBlob ? { AzureWebJobsStorage__blobServiceUri: stg.properties.primaryEndpoints.blob } : {}
42+
var queueSettings = enableQueue ? { AzureWebJobsStorage__queueServiceUri: stg.properties.primaryEndpoints.queue } : {}
43+
var tableSettings = enableTable ? { AzureWebJobsStorage__tableServiceUri: stg.properties.primaryEndpoints.table } : {}
44+
var fileSettings = enableFile ? { AzureWebJobsStorage__fileServiceUri: stg.properties.primaryEndpoints.file } : {}
45+
46+
// Merge all app settings
47+
var allAppSettings = union(
48+
appSettings,
49+
blobSettings,
50+
queueSettings,
51+
tableSettings,
52+
fileSettings,
53+
baseAppSettings
54+
)
55+
56+
resource stg 'Microsoft.Storage/storageAccounts@2022-09-01' existing = {
57+
name: storageAccountName
58+
}
59+
60+
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) {
61+
name: applicationInsightsName
62+
}
1963

20-
module api '../core/host/functions-flexconsumption.bicep' = {
21-
name: '${serviceName}-functions-module'
64+
// Create a Flex Consumption Function App to host the API
65+
module api 'br/public:avm/res/web/site:0.15.1' = {
66+
name: '${serviceName}-flex-consumption'
2267
params: {
68+
kind: kind
2369
name: name
2470
location: location
2571
tags: union(tags, { 'azd-service-name': serviceName })
26-
identityType: 'UserAssigned'
27-
identityId: identityId
28-
appSettings: union(appSettings,
29-
{
30-
AzureWebJobsStorage__clientId : identityClientId
31-
APPLICATIONINSIGHTS_AUTHENTICATION_STRING: applicationInsightsIdentity
32-
})
33-
applicationInsightsName: applicationInsightsName
34-
appServicePlanId: appServicePlanId
35-
runtimeName: runtimeName
36-
runtimeVersion: runtimeVersion
37-
storageAccountName: storageAccountName
38-
deploymentStorageContainerName: deploymentStorageContainerName
39-
virtualNetworkSubnetId: virtualNetworkSubnetId
40-
instanceMemoryMB: instanceMemoryMB
41-
maximumInstanceCount: maximumInstanceCount
72+
serverFarmResourceId: appServicePlanId
73+
managedIdentities: {
74+
systemAssigned: identityType == 'SystemAssigned'
75+
userAssignedResourceIds: [
76+
'${identityId}'
77+
]
78+
}
79+
functionAppConfig: {
80+
deployment: {
81+
storage: {
82+
type: 'blobContainer'
83+
value: '${stg.properties.primaryEndpoints.blob}${deploymentStorageContainerName}'
84+
authentication: {
85+
type: identityType == 'SystemAssigned' ? 'SystemAssignedIdentity' : 'UserAssignedIdentity'
86+
userAssignedIdentityResourceId: identityType == 'UserAssigned' ? identityId : ''
87+
}
88+
}
89+
}
90+
scaleAndConcurrency: {
91+
instanceMemoryMB: instanceMemoryMB
92+
maximumInstanceCount: maximumInstanceCount
93+
}
94+
runtime: {
95+
name: runtimeName
96+
version: runtimeVersion
97+
}
98+
}
99+
siteConfig: {
100+
alwaysOn: false
101+
}
102+
virtualNetworkSubnetId: !empty(virtualNetworkSubnetId) ? virtualNetworkSubnetId : null
103+
appSettingsKeyValuePairs: allAppSettings
42104
}
43105
}
44106

45107
output SERVICE_API_NAME string = api.outputs.name
46-
output SERVICE_API_IDENTITY_PRINCIPAL_ID string = api.outputs.identityPrincipalId
108+
// Ensure output is always string, handle potential null from module output if SystemAssigned is not used
109+
output SERVICE_API_IDENTITY_PRINCIPAL_ID string = identityType == 'SystemAssigned' ? api.outputs.?systemAssignedMIPrincipalId ?? '' : ''

infra/app/rbac.bicep

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
param storageAccountName string
2+
param appInsightsName string
3+
param managedIdentityPrincipalId string // Principal ID for the Managed Identity
4+
param userIdentityPrincipalId string = '' // Principal ID for the User Identity
5+
param allowUserIdentityPrincipal bool = false // Flag to enable user identity role assignments
6+
param enableBlob bool = true
7+
param enableQueue bool = false
8+
param enableTable bool = false
9+
10+
// Define Role Definition IDs internally
11+
var storageRoleDefinitionId = 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b' //Storage Blob Data Owner role
12+
var queueRoleDefinitionId = '974c5e8b-45b9-4653-ba55-5f855dd0fb88' // Storage Queue Data Contributor role
13+
var tableRoleDefinitionId = '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3' // Storage Table Data Contributor role
14+
var monitoringRoleDefinitionId = '3913510d-42f4-4e42-8a64-420c390055eb' // Monitoring Metrics Publisher role ID
15+
16+
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' existing = {
17+
name: storageAccountName
18+
}
19+
20+
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = {
21+
name: appInsightsName
22+
}
23+
24+
// Role assignment for Storage Account (Blob) - Managed Identity
25+
resource storageRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableBlob) {
26+
name: guid(storageAccount.id, managedIdentityPrincipalId, storageRoleDefinitionId) // Use managed identity ID
27+
scope: storageAccount
28+
properties: {
29+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageRoleDefinitionId)
30+
principalId: managedIdentityPrincipalId // Use managed identity ID
31+
principalType: 'ServicePrincipal' // Managed Identity is a Service Principal
32+
}
33+
}
34+
35+
// Role assignment for Storage Account (Blob) - User Identity
36+
resource storageRoleAssignment_User 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableBlob && allowUserIdentityPrincipal && !empty(userIdentityPrincipalId)) {
37+
name: guid(storageAccount.id, userIdentityPrincipalId, storageRoleDefinitionId)
38+
scope: storageAccount
39+
properties: {
40+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', storageRoleDefinitionId)
41+
principalId: userIdentityPrincipalId // Use user identity ID
42+
principalType: 'User' // User Identity is a User Principal
43+
}
44+
}
45+
46+
// Role assignment for Storage Account (Queue) - Managed Identity
47+
resource queueRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableQueue) {
48+
name: guid(storageAccount.id, managedIdentityPrincipalId, queueRoleDefinitionId) // Use managed identity ID
49+
scope: storageAccount
50+
properties: {
51+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', queueRoleDefinitionId)
52+
principalId: managedIdentityPrincipalId // Use managed identity ID
53+
principalType: 'ServicePrincipal' // Managed Identity is a Service Principal
54+
}
55+
}
56+
57+
// Role assignment for Storage Account (Queue) - User Identity
58+
resource queueRoleAssignment_User 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableQueue && allowUserIdentityPrincipal && !empty(userIdentityPrincipalId)) {
59+
name: guid(storageAccount.id, userIdentityPrincipalId, queueRoleDefinitionId)
60+
scope: storageAccount
61+
properties: {
62+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', queueRoleDefinitionId)
63+
principalId: userIdentityPrincipalId // Use user identity ID
64+
principalType: 'User' // User Identity is a User Principal
65+
}
66+
}
67+
68+
// Role assignment for Storage Account (Table) - Managed Identity
69+
resource tableRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableTable) {
70+
name: guid(storageAccount.id, managedIdentityPrincipalId, tableRoleDefinitionId) // Use managed identity ID
71+
scope: storageAccount
72+
properties: {
73+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', tableRoleDefinitionId)
74+
principalId: managedIdentityPrincipalId // Use managed identity ID
75+
principalType: 'ServicePrincipal' // Managed Identity is a Service Principal
76+
}
77+
}
78+
79+
// Role assignment for Storage Account (Table) - User Identity
80+
resource tableRoleAssignment_User 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (enableTable && allowUserIdentityPrincipal && !empty(userIdentityPrincipalId)) {
81+
name: guid(storageAccount.id, userIdentityPrincipalId, tableRoleDefinitionId)
82+
scope: storageAccount
83+
properties: {
84+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', tableRoleDefinitionId)
85+
principalId: userIdentityPrincipalId // Use user identity ID
86+
principalType: 'User' // User Identity is a User Principal
87+
}
88+
}
89+
90+
// Role assignment for Application Insights - Managed Identity
91+
resource appInsightsRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
92+
name: guid(applicationInsights.id, managedIdentityPrincipalId, monitoringRoleDefinitionId) // Use managed identity ID
93+
scope: applicationInsights
94+
properties: {
95+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', monitoringRoleDefinitionId)
96+
principalId: managedIdentityPrincipalId // Use managed identity ID
97+
principalType: 'ServicePrincipal' // Managed Identity is a Service Principal
98+
}
99+
}
100+
101+
// Role assignment for Application Insights - User Identity
102+
resource appInsightsRoleAssignment_User 'Microsoft.Authorization/roleAssignments@2022-04-01' = if (allowUserIdentityPrincipal && !empty(userIdentityPrincipalId)) {
103+
name: guid(applicationInsights.id, userIdentityPrincipalId, monitoringRoleDefinitionId)
104+
scope: applicationInsights
105+
properties: {
106+
roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', monitoringRoleDefinitionId)
107+
principalId: userIdentityPrincipalId // Use user identity ID
108+
principalType: 'User' // User Identity is a User Principal
109+
}
110+
}

infra/app/storage-Access.bicep

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)