diff --git a/src/bicep/core/hub-network.bicep b/src/bicep/core/hub-network.bicep index 71fa81a12..076be73d4 100644 --- a/src/bicep/core/hub-network.bicep +++ b/src/bicep/core/hub-network.bicep @@ -9,7 +9,6 @@ param tags object = {} param logStorageAccountName string param logStorageSkuName string -param logAnalyticsWorkspaceName string param logAnalyticsWorkspaceResourceId string param virtualNetworkName string @@ -71,11 +70,6 @@ param firewallManagementPublicIPAddressAvailabilityZones array param publicIPAddressDiagnosticsLogs array param publicIPAddressDiagnosticsMetrics array -param supportedClouds array = [ - 'AzureCloud' - 'AzureUSGovernment' -] - module logStorage '../modules/storage-account.bicep' = { name: 'logStorage' params: { @@ -238,21 +232,6 @@ module firewall '../modules/firewall.bicep' = { } } -module azureMonitorPrivateLink '../modules/private-link.bicep' = if ( contains(supportedClouds, environment().name) ){ - name: 'azure-monitor-private-link' - params: { - logAnalyticsWorkspaceName: logAnalyticsWorkspaceName - logAnalyticsWorkspaceResourceId: logAnalyticsWorkspaceResourceId - privateEndpointSubnetName: subnetName - privateEndpointVnetName: virtualNetwork.outputs.name - location: location - tags: tags - } - dependsOn: [ - subnet - ] -} - output virtualNetworkName string = virtualNetwork.outputs.name output virtualNetworkResourceId string = virtualNetwork.outputs.id output subnetName string = subnet.name diff --git a/src/bicep/core/spoke-network.bicep b/src/bicep/core/spoke-network.bicep index 385be9563..157e0defc 100644 --- a/src/bicep/core/spoke-network.bicep +++ b/src/bicep/core/spoke-network.bicep @@ -34,6 +34,8 @@ param routeTableRouteAddressPrefix string = '0.0.0.0/0' param routeTableRouteNextHopIpAddress string = firewallPrivateIPAddress param routeTableRouteNextHopType string = 'VirtualAppliance' +param subnetPrivateEndpointNetworkPolicies string + module logStorage '../modules/storage-account.bicep' = { name: 'logStorage' params: { @@ -95,7 +97,8 @@ module virtualNetwork '../modules/virtual-network.bicep' = { routeTable: { id: routeTable.outputs.id } - serviceEndpoints: subnetServiceEndpoints + serviceEndpoints: subnetServiceEndpoints + privateEndpointNetworkPolicies: subnetPrivateEndpointNetworkPolicies } } ] diff --git a/src/bicep/mlz.bicep b/src/bicep/mlz.bicep index c8f87605d..959f19e1e 100644 --- a/src/bicep/mlz.bicep +++ b/src/bicep/mlz.bicep @@ -42,6 +42,12 @@ param sharedServicesSubscriptionId string = subscription().subscriptionId @description('The region to deploy resources into. It defaults to the deployment location.') param location string = deployment().location +@description('Supported Azure Clouds array. It defaults to the Public cloud and the Azure US Government cloud.') +param supportedClouds array = [ + 'AzureCloud' + 'AzureUSGovernment' +] + // RESOURCE NAMING PARAMETERS @description('A suffix to use for naming deployments uniquely. It defaults to the Bicep resolution of the "utcNow()" function.') @@ -661,6 +667,7 @@ var spokes = [ subnetName: identitySubnetName subnetAddressPrefix: identitySubnetAddressPrefix subnetServiceEndpoints: identitySubnetServiceEndpoints + subnetPrivateEndpointNetworkPolicies: 'Enabled' } { name: operationsName @@ -678,6 +685,7 @@ var spokes = [ subnetName: operationsSubnetName subnetAddressPrefix: operationsSubnetAddressPrefix subnetServiceEndpoints: operationsSubnetServiceEndpoints + subnetPrivateEndpointNetworkPolicies: 'Disabled' } { name: sharedServicesName @@ -695,6 +703,7 @@ var spokes = [ subnetName: sharedServicesSubnetName subnetAddressPrefix: sharedServicesSubnetAddressPrefix subnetServiceEndpoints: sharedServicesSubnetServiceEndpoints + subnetPrivateEndpointNetworkPolicies: 'Enabled' } ] @@ -768,8 +777,6 @@ module hubNetwork './core/hub-network.bicep' = { logStorageAccountName: hubLogStorageAccountName logStorageSkuName: logStorageSkuName - - logAnalyticsWorkspaceName: logAnalyticsWorkspace.outputs.name logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.outputs.id virtualNetworkName: hubVirtualNetworkName @@ -843,6 +850,8 @@ module spokeNetworks './core/spoke-network.bicep' = [for spoke in spokes: { subnetName: spoke.subnetName subnetAddressPrefix: spoke.subnetAddressPrefix subnetServiceEndpoints: spoke.subnetServiceEndpoints + + subnetPrivateEndpointNetworkPolicies: spoke.subnetPrivateEndpointNetworkPolicies } }] @@ -899,6 +908,20 @@ module spokePolicyAssignments './modules/policy-assignment.bicep' = [for spoke i } }] +// PRIVATE DNS + +module azurePrivateDns './modules/private-dns.bicep' = { + name: 'azure-private-dns' + scope: resourceGroup(hubSubscriptionId, hubResourceGroupName) + params: { + vnetName: hubNetwork.outputs.virtualNetworkName + tags: tags + } + dependsOn: [ + hubNetwork + ] +} + // CENTRAL LOGGING module hubSubscriptionActivityLogging './modules/central-logging.bicep' = { @@ -913,6 +936,29 @@ module hubSubscriptionActivityLogging './modules/central-logging.bicep' = { ] } +module azureMonitorPrivateLink './modules/private-link.bicep' = if ( contains(supportedClouds, environment().name) ){ + name: 'azure-monitor-private-link' + scope: resourceGroup(operationsSubscriptionId, operationsResourceGroupName) + params: { + logAnalyticsWorkspaceName: logAnalyticsWorkspace.outputs.name + logAnalyticsWorkspaceResourceId: logAnalyticsWorkspace.outputs.id + privateEndpointSubnetName: operationsSubnetName + privateEndpointVnetName: operationsVirtualNetworkName + monitorPrivateDnsZoneId: azurePrivateDns.outputs.monitorPrivateDnsZoneId + omsPrivateDnsZoneId: azurePrivateDns.outputs.omsPrivateDnsZoneId + odsPrivateDnsZoneId: azurePrivateDns.outputs.odsPrivateDnsZoneId + agentsvcPrivateDnsZoneId: azurePrivateDns.outputs.agentsvcPrivateDnsZoneId + storagePrivateDnsZoneId: azurePrivateDns.outputs.storagePrivateDnsZoneId + location: location + tags: tags + } + dependsOn: [ + logAnalyticsWorkspace + spokeNetworks + azurePrivateDns + ] +} + module spokeSubscriptionActivityLogging './modules/central-logging.bicep' = [for spoke in spokes: if (spoke.subscriptionId != hubSubscriptionId) { name: 'activity-logs-${spoke.name}-${deploymentNameSuffix}' scope: subscription(spoke.subscriptionId) @@ -1012,6 +1058,9 @@ module remoteAccess './core/remote-access.bicep' = if (deployRemoteAccess) { logAnalyticsWorkspaceId: logAnalyticsWorkspace.outputs.id } + dependsOn: [ + azureMonitorPrivateLink + ] } /* diff --git a/src/bicep/modules/private-dns.bicep b/src/bicep/modules/private-dns.bicep new file mode 100644 index 000000000..f482d03a7 --- /dev/null +++ b/src/bicep/modules/private-dns.bicep @@ -0,0 +1,132 @@ +/* +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. +*/ + +@description('The name of the virtual network the private dns zones will be connected to') +param vnetName string + +@description('The name of the the resource group where the virtual network exists') +param vnetResourceGroup string = resourceGroup().name + +@description('The subscription id of the subscription the virtual network exists in') +param vnetSubscriptionId string = subscription().subscriptionId + +@description('The tags that will be associated to the resources') +param tags object + +var privateDnsZones_privatelink_monitor_azure_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.monitor.azure.com' : 'privatelink.monitor.azure.us' ) +var privateDnsZones_privatelink_ods_opinsights_azure_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.ods.opinsights.azure.com' : 'privatelink.ods.opinsights.azure.us' ) +var privateDnsZones_privatelink_oms_opinsights_azure_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.oms.opinsights.azure.com' : 'privatelink.oms.opinsights.azure.us' ) +var privateDnsZones_privatelink_blob_core_cloudapi_net_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.blob.${environment().suffixes.storage}' : 'privatelink.blob.core.usgovcloudapi.net' ) +var privateDnsZones_privatelink_agentsvc_azure_automation_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.agentsvc.azure-automation.net' : 'privatelink.agentsvc.azure-automation.us' ) + +resource privatelink_monitor_azure_com 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: privateDnsZones_privatelink_monitor_azure_name + location: 'global' + tags: tags +} + +resource privatelink_oms_opinsights_azure_com 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: privateDnsZones_privatelink_oms_opinsights_azure_name + location: 'global' + tags: tags +} + +resource privatelink_ods_opinsights_azure_com 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: privateDnsZones_privatelink_ods_opinsights_azure_name + location: 'global' + tags: tags +} + +resource privatelink_agentsvc_azure_automation_net 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: privateDnsZones_privatelink_agentsvc_azure_automation_name + location: 'global' + tags: tags +} + +resource privatelink_blob_core_cloudapi_net 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: privateDnsZones_privatelink_blob_core_cloudapi_net_name + location: 'global' + tags: tags +} + +resource privatelink_monitor_azure_com_privatelink_monitor_azure_com_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { + name: '${privateDnsZones_privatelink_monitor_azure_name}/${privateDnsZones_privatelink_monitor_azure_name}-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', vnetName ) + } + } + dependsOn: [ + privatelink_monitor_azure_com + ] +} + +resource privatelink_oms_opinsights_azure_com_privatelink_oms_opinsights_azure_com_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { + name: '${privateDnsZones_privatelink_oms_opinsights_azure_name}/${privateDnsZones_privatelink_oms_opinsights_azure_name}-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', vnetName ) + } + } + dependsOn: [ + privatelink_oms_opinsights_azure_com + privatelink_monitor_azure_com_privatelink_monitor_azure_com_link + ] +} + +resource privatelink_ods_opinsights_azure_com_privatelink_ods_opinsights_azure_com_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { + name: '${privateDnsZones_privatelink_ods_opinsights_azure_name}/${privateDnsZones_privatelink_ods_opinsights_azure_name}-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', vnetName ) + } + } + dependsOn: [ + privatelink_ods_opinsights_azure_com + privatelink_oms_opinsights_azure_com_privatelink_oms_opinsights_azure_com_link + ] +} + +resource privatelink_agentsvc_azure_automation_net_privatelink_agentsvc_azure_automation_net_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { + name: '${privateDnsZones_privatelink_agentsvc_azure_automation_name}/${privateDnsZones_privatelink_agentsvc_azure_automation_name}-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', vnetName ) + } + } + dependsOn: [ + privatelink_agentsvc_azure_automation_net + privatelink_ods_opinsights_azure_com_privatelink_ods_opinsights_azure_com_link + ] +} + +resource privateDnsZones_privatelink_blob_core_cloudapi_net_privateDnsZones_privatelink_blob_core_cloudapi_net_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { + name: '${privateDnsZones_privatelink_blob_core_cloudapi_net_name}/${privateDnsZones_privatelink_blob_core_cloudapi_net_name}-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', vnetName ) + } + } + dependsOn: [ + privatelink_blob_core_cloudapi_net + privatelink_agentsvc_azure_automation_net_privatelink_agentsvc_azure_automation_net_link + ] +} + +output monitorPrivateDnsZoneId string = privatelink_monitor_azure_com.id +output omsPrivateDnsZoneId string = privatelink_oms_opinsights_azure_com.id +output odsPrivateDnsZoneId string = privatelink_ods_opinsights_azure_com.id +output agentsvcPrivateDnsZoneId string = privatelink_agentsvc_azure_automation_net.id +output storagePrivateDnsZoneId string = privatelink_blob_core_cloudapi_net.id diff --git a/src/bicep/modules/private-link.bicep b/src/bicep/modules/private-link.bicep index cd8bc172c..46c559731 100644 --- a/src/bicep/modules/private-link.bicep +++ b/src/bicep/modules/private-link.bicep @@ -30,6 +30,21 @@ param vnetSubscriptionId string = subscription().subscriptionId @description('The location of this resource') param location string = resourceGroup().location +@description('Azure Monitor Private DNS Zone resource id') +param monitorPrivateDnsZoneId string + +@description('OMS Private DNS Zone resource id') +param omsPrivateDnsZoneId string + +@description('ODS Private DNS Zone resource id') +param odsPrivateDnsZoneId string + +@description('Agentsvc Private DNS Zone resource id') +param agentsvcPrivateDnsZoneId string + +@description('Azure Blob Storage Private DNS Zone resource id') +param storagePrivateDnsZoneId string + var privateLinkConnectionName = take('plconn${logAnalyticsWorkspaceName}${uniqueData}', 80) var privateLinkEndpointName = take('pl${logAnalyticsWorkspaceName}${uniqueData}', 80) var privateLinkScopeName = take('plscope${logAnalyticsWorkspaceName}${uniqueData}', 80) @@ -83,31 +98,31 @@ resource dnsZonePrivateLinkEndpoint 'Microsoft.Network/privateEndpoints/privateD { name: 'monitor' properties: { - privateDnsZoneId: privatelink_monitor_azure_com.id + privateDnsZoneId: monitorPrivateDnsZoneId } } { name: 'oms' properties: { - privateDnsZoneId: privatelink_oms_opinsights_azure_com.id + privateDnsZoneId: omsPrivateDnsZoneId } } { name: 'ods' properties: { - privateDnsZoneId: privatelink_ods_opinsights_azure_com.id + privateDnsZoneId: odsPrivateDnsZoneId } } { name: 'agentsvc' properties: { - privateDnsZoneId: privatelink_agentsvc_azure_automation_net.id + privateDnsZoneId: agentsvcPrivateDnsZoneId } } { name: 'storage' properties: { - privateDnsZoneId: privatelink_blob_core_cloudapi_net.id + privateDnsZoneId: storagePrivateDnsZoneId } } ] @@ -116,107 +131,3 @@ resource dnsZonePrivateLinkEndpoint 'Microsoft.Network/privateEndpoints/privateD subnetPrivateEndpoint ] } -var privateDnsZones_privatelink_monitor_azure_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.monitor.azure.com' : 'privatelink.monitor.azure.us' ) -var privateDnsZones_privatelink_ods_opinsights_azure_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.ods.opinsights.azure.com' : 'privatelink.ods.opinsights.azure.us' ) -var privateDnsZones_privatelink_oms_opinsights_azure_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.oms.opinsights.azure.com' : 'privatelink.oms.opinsights.azure.us' ) -var privateDnsZones_privatelink_blob_core_cloudapi_net_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.blob.${environment().suffixes.storage}' : 'privatelink.blob.core.usgovcloudapi.net' ) -var privateDnsZones_privatelink_agentsvc_azure_automation_name = ( environment().name =~ 'AzureCloud' ? 'privatelink.agentsvc.azure-automation.net' : 'privatelink.agentsvc.azure-automation.us' ) - -resource privatelink_monitor_azure_com 'Microsoft.Network/privateDnsZones@2018-09-01' = { - name: privateDnsZones_privatelink_monitor_azure_name - location: 'global' -} - -resource privatelink_oms_opinsights_azure_com 'Microsoft.Network/privateDnsZones@2018-09-01' = { - name: privateDnsZones_privatelink_oms_opinsights_azure_name - location: 'global' -} - -resource privatelink_ods_opinsights_azure_com 'Microsoft.Network/privateDnsZones@2018-09-01' = { - name: privateDnsZones_privatelink_ods_opinsights_azure_name - location: 'global' -} - -resource privatelink_agentsvc_azure_automation_net 'Microsoft.Network/privateDnsZones@2018-09-01' = { - name: privateDnsZones_privatelink_agentsvc_azure_automation_name - location: 'global' -} - -resource privatelink_blob_core_cloudapi_net 'Microsoft.Network/privateDnsZones@2018-09-01' = { - name: privateDnsZones_privatelink_blob_core_cloudapi_net_name - location: 'global' -} - -resource privatelink_monitor_azure_com_privatelink_monitor_azure_com_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { - name: '${privateDnsZones_privatelink_monitor_azure_name}/${privateDnsZones_privatelink_monitor_azure_name}-link' - location: 'global' - properties: { - registrationEnabled: false - virtualNetwork: { - id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', privateEndpointVnetName ) - } - } - dependsOn: [ - privatelink_monitor_azure_com - ] -} - -resource privatelink_oms_opinsights_azure_com_privatelink_oms_opinsights_azure_com_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { - name: '${privateDnsZones_privatelink_oms_opinsights_azure_name}/${privateDnsZones_privatelink_oms_opinsights_azure_name}-link' - location: 'global' - properties: { - registrationEnabled: false - virtualNetwork: { - id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', privateEndpointVnetName ) - } - } - dependsOn: [ - privatelink_oms_opinsights_azure_com - privatelink_monitor_azure_com_privatelink_monitor_azure_com_link - ] -} - -resource privatelink_ods_opinsights_azure_com_privatelink_ods_opinsights_azure_com_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { - name: '${privateDnsZones_privatelink_ods_opinsights_azure_name}/${privateDnsZones_privatelink_ods_opinsights_azure_name}-link' - location: 'global' - properties: { - registrationEnabled: false - virtualNetwork: { - id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', privateEndpointVnetName ) - } - } - dependsOn: [ - privatelink_ods_opinsights_azure_com - privatelink_oms_opinsights_azure_com_privatelink_oms_opinsights_azure_com_link - ] -} - -resource privatelink_agentsvc_azure_automation_net_privatelink_agentsvc_azure_automation_net_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { - name: '${privateDnsZones_privatelink_agentsvc_azure_automation_name}/${privateDnsZones_privatelink_agentsvc_azure_automation_name}-link' - location: 'global' - properties: { - registrationEnabled: false - virtualNetwork: { - id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', privateEndpointVnetName ) - } - } - dependsOn: [ - privatelink_agentsvc_azure_automation_net - privatelink_ods_opinsights_azure_com_privatelink_ods_opinsights_azure_com_link - ] -} - -resource privateDnsZones_privatelink_blob_core_cloudapi_net_privateDnsZones_privatelink_blob_core_cloudapi_net_link 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { - name: '${privateDnsZones_privatelink_blob_core_cloudapi_net_name}/${privateDnsZones_privatelink_blob_core_cloudapi_net_name}-link' - location: 'global' - properties: { - registrationEnabled: false - virtualNetwork: { - id: resourceId(vnetSubscriptionId, vnetResourceGroup, 'Microsoft.Network/virtualNetworks', privateEndpointVnetName ) - } - } - dependsOn: [ - privatelink_blob_core_cloudapi_net - privatelink_agentsvc_azure_automation_net_privatelink_agentsvc_azure_automation_net_link - ] -}