Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions Bicep/getavailability.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@ param functionAppName string
@description('Name of the Application Insights instance for Function App monitoring.')
param applicationInsightsName string

@description('Create private endpoints for the Storage Account and Function App. When false, both resources remain publicly reachable.')
param usePrivateEndpoints bool = true

@description('Subnet resource ID for Function App VNet integration. Must be delegated to Microsoft.App/environments.')
param fnSubnetId string

@description('Subnet resource ID for Private Endpoints.')
param peSubnetId string
@description('Subnet resource ID for Private Endpoints. Required only when usePrivateEndpoints is true.')
param peSubnetId string = ''

@description('Subscription ID containing existing Private DNS Zones.')
param dnsZonesSubscriptionId string
@description('Subscription ID containing existing Private DNS Zones. Required only when usePrivateEndpoints is true.')
param dnsZonesSubscriptionId string = ''

@description('Resource group name containing existing Private DNS Zones.')
param dnsZonesResourceGroupName string
@description('Resource group name containing existing Private DNS Zones. Required only when usePrivateEndpoints is true.')
param dnsZonesResourceGroupName string = ''

@description('Comma-separated list of Azure subscription names or IDs to monitor (written to GETAVAIL_SUBSCRIPTIONS app setting).')
param getavailSubscriptions string
Expand All @@ -78,14 +81,18 @@ var roleDefinitions = {
storageBlobDataOwner: 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b'
}

var storagePublicNetworkAccess = usePrivateEndpoints ? 'Disabled' : 'Enabled'
var storageDefaultAction = usePrivateEndpoints ? 'Deny' : 'Allow'
var functionAppPublicNetworkAccess = usePrivateEndpoints ? 'Disabled' : 'Enabled'

// ── Existing Private DNS Zones ───────────────────────────────────────────────

resource blobDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = {
resource blobDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = if (usePrivateEndpoints) {
name: 'privatelink.blob.${environment().suffixes.storage}'
scope: resourceGroup(dnsZonesSubscriptionId, dnsZonesResourceGroupName)
}

resource webAppDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = {
resource webAppDnsZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = if (usePrivateEndpoints) {
name: 'privatelink.azurewebsites.net'
scope: resourceGroup(dnsZonesSubscriptionId, dnsZonesResourceGroupName)
}
Expand Down Expand Up @@ -281,9 +288,9 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2025-01-01' = {
supportsHttpsTrafficOnly: true
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Deny'
defaultAction: storageDefaultAction
}
publicNetworkAccess: 'Disabled'
publicNetworkAccess: storagePublicNetworkAccess
encryption: {
services: {
blob: {
Expand All @@ -294,17 +301,23 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2025-01-01' = {
}
resource blobServices 'blobServices' = {
name: 'default'
properties: {}
properties: {
deleteRetentionPolicy: {
enabled: false
allowPermanentDelete: false
}
}
}
tags: commonTags
}

// ── Private Endpoint: Storage Account (blob) ─────────────────────────────────

resource storageAccountBlobPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-10-01' = {
resource storageAccountBlobPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-10-01' = if (usePrivateEndpoints) {
name: 'pe-blob-${storageAccountName}'
location: location
properties: {
properties: any({
ipVersionType: 'IPv4'
subnet: {
id: peSubnetId
}
Expand All @@ -320,7 +333,7 @@ resource storageAccountBlobPrivateEndpoint 'Microsoft.Network/privateEndpoints@2
}
]
customNetworkInterfaceName: 'nic-pe-${storageAccountName}'
}
})
tags: commonTags

resource privateDnsZoneGroup 'privateDnsZoneGroups' = {
Expand All @@ -346,6 +359,8 @@ resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
kind: 'web'
properties: {
Application_Type: 'web'
Flow_Type: 'Bluefield'
Request_Source: 'rest'
WorkspaceResourceId: logAnalyticsWorkspace.id
DisableLocalAuth: true
}
Expand Down Expand Up @@ -384,7 +399,7 @@ resource functionApp 'Microsoft.Web/sites@2024-11-01' = {
serverFarmId: flexServicePlan.id
httpsOnly: true
virtualNetworkSubnetId: fnSubnetId
publicNetworkAccess: 'Disabled'
publicNetworkAccess: functionAppPublicNetworkAccess
siteConfig: {
minTlsVersion: '1.2'
cors: {
Expand Down Expand Up @@ -431,18 +446,21 @@ resource functionApp 'Microsoft.Web/sites@2024-11-01' = {
TIMER_SCHEDULE: timerSchedule
}
}
dependsOn: [
storageAccountBlobPrivateEndpoint // Create function only after storage PE is ready
]
dependsOn: usePrivateEndpoints
? [
storageAccountBlobPrivateEndpoint // Create function only after storage PE is ready
]
: []
tags: commonTags
}

// ── Private Endpoint: Function App (sites) ───────────────────────────────────

resource functionAppPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-10-01' = {
resource functionAppPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-10-01' = if (usePrivateEndpoints) {
name: 'pe-sites-${functionAppName}'
location: location
properties: {
properties: any({
ipVersionType: 'IPv4'
subnet: {
id: peSubnetId
}
Expand All @@ -458,7 +476,7 @@ resource functionAppPrivateEndpoint 'Microsoft.Network/privateEndpoints@2024-10-
}
]
customNetworkInterfaceName: 'nic-pe-${functionAppName}'
}
})
tags: commonTags

resource privateDnsZoneGroup 'privateDnsZoneGroups' = {
Expand Down
27 changes: 27 additions & 0 deletions Bicep/parameters.dev.bicepparam
Original file line number Diff line number Diff line change
@@ -1,14 +1,41 @@
using './getavailability.bicep'

// Log Analytics workspace that stores the custom availability tables.
param logAnalyticsWorkspaceName = 'log-getavail-itn-001'

// Data Collection Endpoint used by the Function App to ingest custom logs.
param dataCollectionEndpointName = 'dce-getavail-itn-001'

// Data Collection Rule that maps the ingestion streams into the two custom tables.
param dataCollectionRuleName = 'dcr-getavail-itn-001'

// Storage account used by the Flex Consumption Function App for deployment and runtime blobs.
param storageAccountName = 'flazstgetavailitn001'

// Function App name for the scheduled Get-Availability runner.
param functionAppName = 'fn-getavail-itn-001'

// Application Insights instance wired to the Function App.
param applicationInsightsName = 'appi-getavail-itn-001'

// Toggle for private endpoints on the Storage Account and Function App.
// Keep true for the current private networking model; set false to allow public access instead.
param usePrivateEndpoints = true

// Subnet reserved for private endpoints. Used only when usePrivateEndpoints = true.
param peSubnetId = '/subscriptions/9068a229-f092-400e-8093-87e8e7d26ae1/resourceGroups/rg-alz-net-workloads-itn-001/providers/Microsoft.Network/virtualNetworks/vnet-alz-workloads-itn-001/subnets/snet-alz-pe-workloads-itn-001'

// Subnet delegated to Microsoft.App/environments for Function App VNet integration.
param fnSubnetId = '/subscriptions/9068a229-f092-400e-8093-87e8e7d26ae1/resourceGroups/rg-alz-net-workloads-itn-001/providers/Microsoft.Network/virtualNetworks/vnet-alz-workloads-itn-001/subnets/snet-alz-fn-workloads-itn-001'

// Subscription containing the shared private DNS zones. Used only when usePrivateEndpoints = true.
param dnsZonesSubscriptionId = 'c4e6c176-bf9c-4e8c-87b2-ebdceea7085f'

// Resource group containing the shared private DNS zones. Used only when usePrivateEndpoints = true.
param dnsZonesResourceGroupName = 'rg-alz-dns-hub-itn-001'

// Comma-separated subscription names monitored by the Function App.
param getavailSubscriptions = 'Flaz-Connectivity,Flaz-Management,Flaz-Identity,Flaz-Workloads'

// Existing Log Analytics workspace used as the source for Activity Log and Resource Health KQL queries.
param sourceWorkspaceId = 'f25755bb-9b46-4aac-bfae-6a10c4c18440'
Loading
Loading