From 0238a6722c029f35d6c8f2996d2f6f43316d1166 Mon Sep 17 00:00:00 2001 From: hundredacres Date: Thu, 10 Oct 2024 23:57:40 -0700 Subject: [PATCH] fix: Add support for forced tunneling (#3373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds param to enable forcedTunneling, which adds a managementIPAddress. Fixes #3368 Closes #3368 ## Pipeline Reference | Pipeline | | -------- | [![avm.res.network.azure-firewall](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=fix%2Fissues%2F3368)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/network/azure-firewall/README.md | 128 +++++++++++++++++- avm/res/network/azure-firewall/main.bicep | 11 +- avm/res/network/azure-firewall/main.json | 29 ++-- .../tests/e2e/tunneling/dependencies.bicep | 59 ++++++++ .../tests/e2e/tunneling/main.test.bicep | 70 ++++++++++ 5 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep create mode 100644 avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index 5d8d346c88..282958f330 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -18,7 +18,7 @@ This module deploys an Azure Firewall. | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Network/azureFirewalls` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/azureFirewalls) | +| `Microsoft.Network/azureFirewalls` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/azureFirewalls) | | `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | ## Usage examples @@ -37,7 +37,8 @@ The following section provides usage examples for the module, which were used to - [Hub-min](#example-6-hub-min) - [Using large parameter set](#example-7-using-large-parameter-set) - [Public-IP-Prefix](#example-8-public-ip-prefix) -- [WAF-aligned](#example-9-waf-aligned) +- [Forced tunneling](#example-9-forced-tunneling) +- [WAF-aligned](#example-10-waf-aligned) ### Example 1: _Add-PIP_ @@ -1295,7 +1296,117 @@ param zones = []

-### Example 9: _WAF-aligned_ +### Example 9: _Forced tunneling_ + +This instance deploys the module and sets up forced tunneling. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'naftunn001' + // Non-required parameters + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } + ] + azureSkuTier: 'Standard' + enableForcedTunneling: true + location: '' + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + } + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "naftunn001" + }, + // Non-required parameters + "additionalPublicIpConfigurations": { + "value": [ + { + "name": "ipConfig01", + "publicIPAddressResourceId": "" + } + ] + }, + "azureSkuTier": { + "value": "Standard" + }, + "enableForcedTunneling": { + "value": true + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "publicIPAllocationMethod": "Static" + } + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'naftunn001' +// Non-required parameters +param additionalPublicIpConfigurations = [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } +] +param azureSkuTier = 'Standard' +param enableForcedTunneling = true +param location = '' +param managementIPAddressObject = { + publicIPAllocationMethod: 'Static' +} +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 10: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1718,6 +1829,7 @@ param zones = [ | [`applicationRuleCollections`](#parameter-applicationrulecollections) | array | Collection of application rule collections used by Azure Firewall. | | [`azureSkuTier`](#parameter-azureskutier) | string | Tier of an Azure Firewall. | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableForcedTunneling`](#parameter-enableforcedtunneling) | bool | Enable/Disable forced tunneling. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`firewallPolicyId`](#parameter-firewallpolicyid) | string | Resource ID of the Firewall Policy that should be attached. | | [`location`](#parameter-location) | string | Location for all resources. | @@ -2111,6 +2223,14 @@ Resource ID of the diagnostic log analytics workspace. For security reasons, it - Required: No - Type: string +### Parameter: `enableForcedTunneling` + +Enable/Disable forced tunneling. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `enableTelemetry` Enable/Disable usage telemetry for module. @@ -2713,7 +2833,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/public-ip-address:0.5.1` | Remote reference | +| `br/public:avm/res/network/public-ip-address:0.6.0` | Remote reference | ## Data Collection diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep index dc6a94ce87..39fd9b8fc0 100644 --- a/avm/res/network/azure-firewall/main.bicep +++ b/avm/res/network/azure-firewall/main.bicep @@ -66,6 +66,9 @@ param zones array = [ 3 ] +@description('Optional. Enable/Disable forced tunneling.') +param enableForcedTunneling bool = false + @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -85,7 +88,7 @@ param tags object? param enableTelemetry bool = true var azureSkuName = empty(virtualNetworkResourceId) ? 'AZFW_Hub' : 'AZFW_VNet' -var requiresManagementIp = azureSkuTier == 'Basic' ? true : false +var requiresManagementIp = (azureSkuTier == 'Basic' || enableForcedTunneling) ? true : false var isCreateDefaultManagementIP = empty(managementIPResourceID) && requiresManagementIp // ---------------------------------------------------------------------------- @@ -193,7 +196,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { +module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.6.0' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { name: '${uniqueString(deployment().name, location)}-Firewall-PIP' params: { name: publicIPAddressObject.name @@ -224,7 +227,7 @@ module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if } // create a Management Public IP address if one is not provided and the flag is true -module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { +module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.6.0' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { name: '${uniqueString(deployment().name, location)}-Firewall-MIP' params: { name: contains(managementIPAddressObject, 'name') @@ -257,7 +260,7 @@ module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = } } -resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = { +resource azureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = { name: name location: location zones: length(zones) == 0 ? null : zones diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json index 75a9bfba6a..43d731614e 100644 --- a/avm/res/network/azure-firewall/main.json +++ b/avm/res/network/azure-firewall/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1087268001408720205" + "version": "0.30.3.12046", + "templateHash": "7724811109136350489" }, "name": "Azure Firewalls", "description": "This module deploys an Azure Firewall.", @@ -791,6 +791,13 @@ "description": "Optional. Zone numbers e.g. 1,2,3." } }, + "enableForcedTunneling": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable/Disable forced tunneling." + } + }, "diagnosticSettings": { "$ref": "#/definitions/diagnosticSettingType", "metadata": { @@ -850,7 +857,7 @@ } ], "azureSkuName": "[if(empty(parameters('virtualNetworkResourceId')), 'AZFW_Hub', 'AZFW_VNet')]", - "requiresManagementIp": "[if(equals(parameters('azureSkuTier'), 'Basic'), true(), false())]", + "requiresManagementIp": "[if(or(equals(parameters('azureSkuTier'), 'Basic'), parameters('enableForcedTunneling')), true(), false())]", "isCreateDefaultManagementIP": "[and(empty(parameters('managementIPResourceID')), variables('requiresManagementIp'))]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -883,7 +890,7 @@ }, "azureFirewall": { "type": "Microsoft.Network/azureFirewalls", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]", @@ -1017,7 +1024,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14450344965065009842" + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1466,7 +1473,7 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -1474,7 +1481,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1670,7 +1677,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14450344965065009842" + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -2119,7 +2126,7 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -2127,7 +2134,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2345,7 +2352,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('azureFirewall', '2023-04-01', 'full').location]" + "value": "[reference('azureFirewall', '2024-01-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep b/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep new file mode 100644 index 0000000000..8497ceafc0 --- /dev/null +++ b/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep @@ -0,0 +1,59 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id diff --git a/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep new file mode 100644 index 0000000000..8f70451dc2 --- /dev/null +++ b/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep @@ -0,0 +1,70 @@ +targetScope = 'subscription' + +metadata name = 'Forced tunneling' +metadata description = 'This instance deploys the module and sets up forced tunneling.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'naftunn' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: nestedDependencies.outputs.publicIPResourceId + } + ] + azureSkuTier: 'Standard' + enableForcedTunneling: true + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + } + } + } +]