Skip to content

Commit defacdc

Browse files
authored
Merge pull request #16 from paulyuk/main
Modernizing the Bicep for AVM (python)
2 parents d962f9d + 86d5664 commit defacdc

17 files changed

+481
-454
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!--
22
---
33
name: Azure Functions Python HTTP Trigger using Azure Developer CLI
4-
description: This repository contains an Azure Functions HTTP trigger quickstart written in Python and deployed to Azure Functions Flex Consumption using the Azure Developer CLI (azd). The sample uses managed identity and a virtual network to make sure deployment is secure by default. You can opt out of a VNet being used in the sample by setting SKIP_VNET to true in the parameters.
4+
description: This repository contains an Azure Functions HTTP trigger quickstart written in Python and deployed to Azure Functions Flex Consumption using the Azure Developer CLI (azd). The sample uses managed identity and a virtual network to make sure deployment is secure by default. You can opt out of a VNet being used in the sample by setting VNET_ENABLED to false in the parameters.
55
page_type: sample
66
languages:
77
- azdeveloper
@@ -162,10 +162,16 @@ Run this command to provision the function app, with any required Azure resource
162162
azd up
163163
```
164164
165-
Alternatively, you can opt-out of a VNet being used in the sample. To do so, use `azd env` to configure `SKIP_VNET` to `true` before running `azd up`:
165+
By default, this sample deploys with a virtual network (VNet) for enhanced security, ensuring that the function app and related resources are isolated within a private network.
166+
The `VNET_ENABLED` parameter controls whether a VNet is used during deployment:
167+
- When `VNET_ENABLED` is `true` (default), the function app is deployed with a VNet for secure communication and resource isolation.
168+
- When `VNET_ENABLED` is `false`, the function app is deployed without a VNet, allowing public access to resources.
166169
170+
This parameter replaces the previous `SKIP_VNET` parameter. If you were using `SKIP_VNET` in earlier versions, set `VNET_ENABLED` to `false` to achieve the same behavior.
171+
172+
To disable the VNet for this sample, set `VNET_ENABLED` to `false` before running `azd up`:
167173
```bash
168-
azd env set SKIP_VNET true
174+
azd env set VNET_ENABLED false
169175
azd up
170176
```
171177

azure.yaml

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

33
name: functions-quickstart-python-azd
44
metadata:
5-
template: functions-quickstart-python-azd@1.0.0
5+
template: functions-quickstart-python-azd@1.0.1
66
services:
77
api:
88
project: .

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)