diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fe73dd9177..03c5cb5c17 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -87,9 +87,9 @@
/avm/res/network/dns-zone/ @Azure/avm-res-network-dnszone-module-owners-bicep @Azure/avm-core-team-technical-bicep
/avm/res/network/express-route-circuit/ @Azure/avm-res-network-expressroutecircuit-module-owners-bicep @Azure/avm-core-team-technical-bicep
/avm/res/network/express-route-gateway/ @Azure/avm-res-network-expressroutegateway-module-owners-bicep @Azure/avm-core-team-technical-bicep
-#/avm/res/network/firewall-policy/ @Azure/avm-res-network-firewallpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep
+/avm/res/network/firewall-policy/ @Azure/avm-res-network-firewallpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep
/avm/res/network/front-door/ @Azure/avm-res-network-frontdoor-module-owners-bicep @Azure/avm-core-team-technical-bicep
-#/avm/res/network/front-door-web-application-firewall-policy/ @Azure/avm-res-network-frontdoorwebapplicationfirewallpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep
+/avm/res/network/front-door-web-application-firewall-policy/ @Azure/avm-res-network-frontdoorwebapplicationfirewallpolicy-module-owners-bicep @Azure/avm-core-team-technical-bicep
#/avm/res/network/ip-group/ @Azure/avm-res-network-ipgroup-module-owners-bicep @Azure/avm-core-team-technical-bicep
/avm/res/network/load-balancer/ @Azure/avm-res-network-loadbalancer-module-owners-bicep @Azure/avm-core-team-technical-bicep
#/avm/res/network/local-network-gateway/ @Azure/avm-res-network-localnetworkgateway-module-owners-bicep @Azure/avm-core-team-technical-bicep
diff --git a/.github/workflows/avm.platform.toggle-avm-workflows.yml b/.github/workflows/avm.platform.toggle-avm-workflows.yml
index 2fec7d3020..04381bea14 100644
--- a/.github/workflows/avm.platform.toggle-avm-workflows.yml
+++ b/.github/workflows/avm.platform.toggle-avm-workflows.yml
@@ -37,7 +37,7 @@ jobs:
shell: pwsh
run: |
# Load used functions
- . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Switch-WorkflowSate.ps1')
+ . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Switch-WorkflowState.ps1')
$functionInput = @{
RepositoryOwner = '${{ github.repository_owner }}'
@@ -51,4 +51,4 @@ jobs:
Write-Verbose ($functionInput | ConvertTo-Json | Out-String) -Verbose
# Get the modified child resources
- Switch-WorkflowSate @functionInput -Verbose
+ Switch-WorkflowState @functionInput -Verbose
diff --git a/.github/workflows/avm.res.network.firewall-policy.yml b/.github/workflows/avm.res.network.firewall-policy.yml
new file mode 100644
index 0000000000..5279706f7b
--- /dev/null
+++ b/.github/workflows/avm.res.network.firewall-policy.yml
@@ -0,0 +1,83 @@
+name: "avm.res.network.firewall-policy"
+
+on:
+ schedule:
+ - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month)
+ workflow_dispatch:
+ inputs:
+ staticValidation:
+ type: boolean
+ description: "Execute static validation"
+ required: false
+ default: true
+ deploymentValidation:
+ type: boolean
+ description: "Execute deployment validation"
+ required: false
+ default: true
+ removeDeployment:
+ type: boolean
+ description: "Remove deployed module"
+ required: false
+ default: true
+
+ push:
+ branches:
+ - main
+ paths:
+ - ".github/actions/templates/avm-**"
+ - ".github/workflows/avm.template.module.yml"
+ - ".github/workflows/avm.res.network.firewall-policy.yml"
+ - "avm/res/network/firewall-policy/**"
+ - "avm/utilities/pipelines/**"
+ - "!*/**/README.md"
+
+env:
+ modulePath: "avm/res/network/firewall-policy"
+ workflowPath: ".github/workflows/avm.res.network.firewall-policy.yml"
+
+concurrency:
+ group: ${{ github.workflow }}
+
+jobs:
+ ###########################
+ # Initialize pipeline #
+ ###########################
+ job_initialize_pipeline:
+ runs-on: ubuntu-latest
+ name: "Initialize pipeline"
+ steps:
+ - name: "Checkout"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: "Set input parameters to output variables"
+ id: get-workflow-param
+ uses: ./.github/actions/templates/avm-getWorkflowInput
+ with:
+ workflowPath: "${{ env.workflowPath}}"
+ - name: "Get module test file paths"
+ id: get-module-test-file-paths
+ uses: ./.github/actions/templates/avm-getModuleTestFiles
+ with:
+ modulePath: "${{ env.modulePath }}"
+ outputs:
+ workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }}
+ moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }}
+ psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }}
+ modulePath: "${{ env.modulePath }}"
+
+ ##############################
+ # Call reusable workflow #
+ ##############################
+ call-workflow-passing-data:
+ name: "Run"
+ needs:
+ - job_initialize_pipeline
+ uses: ./.github/workflows/avm.template.module.yml
+ with:
+ workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}"
+ moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}"
+ psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}"
+ modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}"
+ secrets: inherit
diff --git a/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml b/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml
new file mode 100644
index 0000000000..b060d5bbd2
--- /dev/null
+++ b/.github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml
@@ -0,0 +1,83 @@
+name: "avm.res.network.front-door-web-application-firewall-policy"
+
+on:
+ schedule:
+ - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month)
+ workflow_dispatch:
+ inputs:
+ staticValidation:
+ type: boolean
+ description: "Execute static validation"
+ required: false
+ default: true
+ deploymentValidation:
+ type: boolean
+ description: "Execute deployment validation"
+ required: false
+ default: true
+ removeDeployment:
+ type: boolean
+ description: "Remove deployed module"
+ required: false
+ default: true
+
+ push:
+ branches:
+ - main
+ paths:
+ - ".github/actions/templates/avm-**"
+ - ".github/workflows/avm.template.module.yml"
+ - ".github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml"
+ - "avm/res/network/front-door-web-application-firewall-policy/**"
+ - "avm/utilities/pipelines/**"
+ - "!*/**/README.md"
+
+env:
+ modulePath: "avm/res/network/front-door-web-application-firewall-policy"
+ workflowPath: ".github/workflows/avm.res.network.front-door-web-application-firewall-policy.yml"
+
+concurrency:
+ group: ${{ github.workflow }}
+
+jobs:
+ ###########################
+ # Initialize pipeline #
+ ###########################
+ job_initialize_pipeline:
+ runs-on: ubuntu-latest
+ name: "Initialize pipeline"
+ steps:
+ - name: "Checkout"
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: "Set input parameters to output variables"
+ id: get-workflow-param
+ uses: ./.github/actions/templates/avm-getWorkflowInput
+ with:
+ workflowPath: "${{ env.workflowPath}}"
+ - name: "Get module test file paths"
+ id: get-module-test-file-paths
+ uses: ./.github/actions/templates/avm-getModuleTestFiles
+ with:
+ modulePath: "${{ env.modulePath }}"
+ outputs:
+ workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }}
+ moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }}
+ psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }}
+ modulePath: "${{ env.modulePath }}"
+
+ ##############################
+ # Call reusable workflow #
+ ##############################
+ call-workflow-passing-data:
+ name: "Run"
+ needs:
+ - job_initialize_pipeline
+ uses: ./.github/workflows/avm.template.module.yml
+ with:
+ workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}"
+ moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}"
+ psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}"
+ modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}"
+ secrets: inherit
diff --git a/avm/res/compute/gallery/README.md b/avm/res/compute/gallery/README.md
index a10e567827..009958240e 100644
--- a/avm/res/compute/gallery/README.md
+++ b/avm/res/compute/gallery/README.md
@@ -105,6 +105,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
applications: [
{
name: 'cgmax-appd-001'
+ supportedOSType: 'Linux'
}
{
name: 'cgmax-appd-002'
@@ -119,18 +120,10 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
}
]
images: [
- {
- name: 'az-imgd-ws-001'
- }
{
hyperVGeneration: 'V1'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: 'az-imgd-ws-002'
+ name: 'az-imgd-ws-001'
offer: 'WindowsServer'
- osState: 'Generalized'
osType: 'Windows'
publisher: 'MicrosoftWindowsServer'
roleAssignments: [
@@ -144,12 +137,12 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
}
{
hyperVGeneration: 'V2'
- isHibernateSupported: 'true'
+ isHibernateSupported: true
maxRecommendedMemory: 16
maxRecommendedvCPUs: 8
minRecommendedMemory: 4
minRecommendedvCPUs: 2
- name: 'az-imgd-ws-003'
+ name: 'az-imgd-ws-002'
offer: 'WindowsServer'
osState: 'Generalized'
osType: 'Windows'
@@ -163,34 +156,13 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
]
sku: '2022-datacenter-azure-edition-hibernate'
}
- {
- hyperVGeneration: 'V2'
- isAcceleratedNetworkSupported: 'true'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: 'az-imgd-ws-004'
- offer: 'WindowsServer'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsServer'
- roleAssignments: [
- {
- principalId: ''
- principalType: 'ServicePrincipal'
- roleDefinitionIdOrName: 'Reader'
- }
- ]
- sku: '2022-datacenter-azure-edition-accnet'
- }
{
hyperVGeneration: 'V2'
maxRecommendedMemory: 16
maxRecommendedvCPUs: 4
minRecommendedMemory: 4
minRecommendedvCPUs: 2
- name: 'az-imgd-wdtl-002'
+ name: 'az-imgd-wdtl-001'
offer: 'WindowsDesktop'
osState: 'Generalized'
osType: 'Windows'
@@ -270,7 +242,8 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
"applications": {
"value": [
{
- "name": "cgmax-appd-001"
+ "name": "cgmax-appd-001",
+ "supportedOSType": "Linux"
},
{
"name": "cgmax-appd-002",
@@ -287,18 +260,10 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
},
"images": {
"value": [
- {
- "name": "az-imgd-ws-001"
- },
{
"hyperVGeneration": "V1",
- "maxRecommendedMemory": 16,
- "maxRecommendedvCPUs": 8,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 2,
- "name": "az-imgd-ws-002",
+ "name": "az-imgd-ws-001",
"offer": "WindowsServer",
- "osState": "Generalized",
"osType": "Windows",
"publisher": "MicrosoftWindowsServer",
"roleAssignments": [
@@ -312,12 +277,12 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
},
{
"hyperVGeneration": "V2",
- "isHibernateSupported": "true",
+ "isHibernateSupported": true,
"maxRecommendedMemory": 16,
"maxRecommendedvCPUs": 8,
"minRecommendedMemory": 4,
"minRecommendedvCPUs": 2,
- "name": "az-imgd-ws-003",
+ "name": "az-imgd-ws-002",
"offer": "WindowsServer",
"osState": "Generalized",
"osType": "Windows",
@@ -331,34 +296,13 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
],
"sku": "2022-datacenter-azure-edition-hibernate"
},
- {
- "hyperVGeneration": "V2",
- "isAcceleratedNetworkSupported": "true",
- "maxRecommendedMemory": 16,
- "maxRecommendedvCPUs": 8,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 2,
- "name": "az-imgd-ws-004",
- "offer": "WindowsServer",
- "osState": "Generalized",
- "osType": "Windows",
- "publisher": "MicrosoftWindowsServer",
- "roleAssignments": [
- {
- "principalId": "",
- "principalType": "ServicePrincipal",
- "roleDefinitionIdOrName": "Reader"
- }
- ],
- "sku": "2022-datacenter-azure-edition-accnet"
- },
{
"hyperVGeneration": "V2",
"maxRecommendedMemory": 16,
"maxRecommendedvCPUs": 4,
"minRecommendedMemory": 4,
"minRecommendedvCPUs": 2,
- "name": "az-imgd-wdtl-002",
+ "name": "az-imgd-wdtl-001",
"offer": "WindowsDesktop",
"osState": "Generalized",
"osType": "Windows",
@@ -449,90 +393,19 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
applications: [
{
name: 'cgwaf-appd-001'
- }
- {
- name: 'cgwaf-appd-002'
supportedOSType: 'Windows'
}
]
images: [
{
name: 'az-imgd-ws-001'
- }
- {
- hyperVGeneration: 'V1'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: 'az-imgd-ws-002'
offer: 'WindowsServer'
- osState: 'Generalized'
osType: 'Windows'
publisher: 'MicrosoftWindowsServer'
sku: '2022-datacenter-azure-edition'
}
- {
- hyperVGeneration: 'V2'
- isHibernateSupported: 'true'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: 'az-imgd-ws-003'
- offer: 'WindowsServer'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsServer'
- sku: '2022-datacenter-azure-edition-hibernate'
- }
- {
- hyperVGeneration: 'V2'
- isAcceleratedNetworkSupported: 'true'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: 'az-imgd-ws-004'
- offer: 'WindowsServer'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsServer'
- sku: '2022-datacenter-azure-edition-accnet'
- }
- {
- hyperVGeneration: 'V2'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 4
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: 'az-imgd-wdtl-002'
- offer: 'WindowsDesktop'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsDesktop'
- securityType: 'TrustedLaunch'
- sku: 'Win11-21H2'
- }
- {
- hyperVGeneration: 'V2'
- maxRecommendedMemory: 32
- maxRecommendedvCPUs: 4
- minRecommendedMemory: 4
- minRecommendedvCPUs: 1
- name: 'az-imgd-us-001'
- offer: '0001-com-ubuntu-server-focal'
- osState: 'Generalized'
- osType: 'Linux'
- publisher: 'canonical'
- sku: '20_04-lts-gen2'
- }
]
location: ''
- lock: {
- kind: 'CanNotDelete'
- name: 'myCustomLockName'
- }
tags: {
Environment: 'Non-Prod'
'hidden-title': 'This is visible in the resource name'
@@ -562,10 +435,7 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
"applications": {
"value": [
{
- "name": "cgwaf-appd-001"
- },
- {
- "name": "cgwaf-appd-002",
+ "name": "cgwaf-appd-001",
"supportedOSType": "Windows"
}
]
@@ -573,87 +443,17 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
"images": {
"value": [
{
- "name": "az-imgd-ws-001"
- },
- {
- "hyperVGeneration": "V1",
- "maxRecommendedMemory": 16,
- "maxRecommendedvCPUs": 8,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 2,
- "name": "az-imgd-ws-002",
+ "name": "az-imgd-ws-001",
"offer": "WindowsServer",
- "osState": "Generalized",
"osType": "Windows",
"publisher": "MicrosoftWindowsServer",
"sku": "2022-datacenter-azure-edition"
- },
- {
- "hyperVGeneration": "V2",
- "isHibernateSupported": "true",
- "maxRecommendedMemory": 16,
- "maxRecommendedvCPUs": 8,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 2,
- "name": "az-imgd-ws-003",
- "offer": "WindowsServer",
- "osState": "Generalized",
- "osType": "Windows",
- "publisher": "MicrosoftWindowsServer",
- "sku": "2022-datacenter-azure-edition-hibernate"
- },
- {
- "hyperVGeneration": "V2",
- "isAcceleratedNetworkSupported": "true",
- "maxRecommendedMemory": 16,
- "maxRecommendedvCPUs": 8,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 2,
- "name": "az-imgd-ws-004",
- "offer": "WindowsServer",
- "osState": "Generalized",
- "osType": "Windows",
- "publisher": "MicrosoftWindowsServer",
- "sku": "2022-datacenter-azure-edition-accnet"
- },
- {
- "hyperVGeneration": "V2",
- "maxRecommendedMemory": 16,
- "maxRecommendedvCPUs": 4,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 2,
- "name": "az-imgd-wdtl-002",
- "offer": "WindowsDesktop",
- "osState": "Generalized",
- "osType": "Windows",
- "publisher": "MicrosoftWindowsDesktop",
- "securityType": "TrustedLaunch",
- "sku": "Win11-21H2"
- },
- {
- "hyperVGeneration": "V2",
- "maxRecommendedMemory": 32,
- "maxRecommendedvCPUs": 4,
- "minRecommendedMemory": 4,
- "minRecommendedvCPUs": 1,
- "name": "az-imgd-us-001",
- "offer": "0001-com-ubuntu-server-focal",
- "osState": "Generalized",
- "osType": "Linux",
- "publisher": "canonical",
- "sku": "20_04-lts-gen2"
}
]
},
"location": {
"value": ""
},
- "lock": {
- "value": {
- "kind": "CanNotDelete",
- "name": "myCustomLockName"
- }
- },
"tags": {
"value": {
"Environment": "Non-Prod",
@@ -688,6 +488,8 @@ module gallery 'br/public:avm/res/compute/gallery:' = {
| [`location`](#parameter-location) | string | Location for all resources. |
| [`lock`](#parameter-lock) | object | The lock settings of the service. |
| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
+| [`sharingProfile`](#parameter-sharingprofile) | object | Profile for gallery sharing to subscription or tenant. |
+| [`softDeletePolicy`](#parameter-softdeletepolicy) | object | Soft deletion policy of the gallery. |
| [`tags`](#parameter-tags) | object | Tags for all resources. |
### Parameter: `name`
@@ -859,6 +661,20 @@ The principal type of the assigned principal ID.
]
```
+### Parameter: `sharingProfile`
+
+Profile for gallery sharing to subscription or tenant.
+
+- Required: No
+- Type: object
+
+### Parameter: `softDeletePolicy`
+
+Soft deletion policy of the gallery.
+
+- Required: No
+- Type: object
+
### Parameter: `tags`
Tags for all resources.
diff --git a/avm/res/compute/gallery/application/README.md b/avm/res/compute/gallery/application/README.md
index e7d95d6251..2c2bd6d4a1 100644
--- a/avm/res/compute/gallery/application/README.md
+++ b/avm/res/compute/gallery/application/README.md
@@ -25,6 +25,7 @@ This module deploys an Azure Compute Gallery Application.
| Parameter | Type | Description |
| :-- | :-- | :-- |
| [`name`](#parameter-name) | string | Name of the application definition. |
+| [`supportedOSType`](#parameter-supportedostype) | string | This property allows you to specify the supported type of the OS that application is built for. |
**Conditional parameters**
@@ -44,7 +45,6 @@ This module deploys an Azure Compute Gallery Application.
| [`privacyStatementUri`](#parameter-privacystatementuri) | string | The privacy statement uri. Has to be a valid URL. |
| [`releaseNoteUri`](#parameter-releasenoteuri) | string | The release note uri. Has to be a valid URL. |
| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
-| [`supportedOSType`](#parameter-supportedostype) | string | This property allows you to specify the supported type of the OS that application is built for. |
| [`tags`](#parameter-tags) | object | Tags for all resources. |
### Parameter: `name`
@@ -54,6 +54,20 @@ Name of the application definition.
- Required: Yes
- Type: string
+### Parameter: `supportedOSType`
+
+This property allows you to specify the supported type of the OS that application is built for.
+
+- Required: Yes
+- Type: string
+- Allowed:
+ ```Bicep
+ [
+ 'Linux'
+ 'Windows'
+ ]
+ ```
+
### Parameter: `galleryName`
The name of the parent Azure Compute Gallery. Required if the template is used in a standalone deployment.
@@ -200,21 +214,6 @@ The principal type of the assigned principal ID.
]
```
-### Parameter: `supportedOSType`
-
-This property allows you to specify the supported type of the OS that application is built for.
-
-- Required: No
-- Type: string
-- Default: `'Windows'`
-- Allowed:
- ```Bicep
- [
- 'Linux'
- 'Windows'
- ]
- ```
-
### Parameter: `tags`
Tags for all resources.
diff --git a/avm/res/compute/gallery/application/main.bicep b/avm/res/compute/gallery/application/main.bicep
index 7cfd3ff3a0..f0f1ed2a3f 100644
--- a/avm/res/compute/gallery/application/main.bicep
+++ b/avm/res/compute/gallery/application/main.bicep
@@ -24,12 +24,12 @@ param privacyStatementUri string?
@sys.description('Optional. The release note uri. Has to be a valid URL.')
param releaseNoteUri string?
-@sys.description('Optional. This property allows you to specify the supported type of the OS that application is built for.')
+@sys.description('Required. This property allows you to specify the supported type of the OS that application is built for.')
@allowed([
'Windows'
'Linux'
])
-param supportedOSType string = 'Windows'
+param supportedOSType string
@sys.description('Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z.')
param endOfLifeDate string?
@@ -63,11 +63,11 @@ resource application 'Microsoft.Compute/galleries/applications@2022-03-03' = {
tags: tags
properties: {
customActions: customActions
- description: description ?? ''
- endOfLifeDate: endOfLifeDate ?? ''
- eula: eula ?? ''
- privacyStatementUri: privacyStatementUri ?? ''
- releaseNoteUri: releaseNoteUri ?? ''
+ description: description
+ endOfLifeDate: endOfLifeDate
+ eula: eula
+ privacyStatementUri: privacyStatementUri
+ releaseNoteUri: releaseNoteUri
supportedOSType: supportedOSType
}
}
@@ -97,6 +97,7 @@ output name string = application.name
@sys.description('The location the resource was deployed into.')
output location string = application.location
+
// =============== //
// Definitions //
// =============== //
diff --git a/avm/res/compute/gallery/application/main.json b/avm/res/compute/gallery/application/main.json
index a181bbc347..30e9cc1921 100644
--- a/avm/res/compute/gallery/application/main.json
+++ b/avm/res/compute/gallery/application/main.json
@@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.24.24.22086",
- "templateHash": "7964925859326857094"
+ "templateHash": "9951919331605340265"
},
"name": "Compute Galleries Applications",
"description": "This module deploys an Azure Compute Gallery Application.",
@@ -131,13 +131,12 @@
},
"supportedOSType": {
"type": "string",
- "defaultValue": "Windows",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
- "description": "Optional. This property allows you to specify the supported type of the OS that application is built for."
+ "description": "Required. This property allows you to specify the supported type of the OS that application is built for."
}
},
"endOfLifeDate": {
@@ -193,11 +192,11 @@
"tags": "[parameters('tags')]",
"properties": {
"customActions": "[parameters('customActions')]",
- "description": "[coalesce(parameters('description'), '')]",
- "endOfLifeDate": "[coalesce(parameters('endOfLifeDate'), '')]",
- "eula": "[coalesce(parameters('eula'), '')]",
- "privacyStatementUri": "[coalesce(parameters('privacyStatementUri'), '')]",
- "releaseNoteUri": "[coalesce(parameters('releaseNoteUri'), '')]",
+ "description": "[parameters('description')]",
+ "endOfLifeDate": "[parameters('endOfLifeDate')]",
+ "eula": "[parameters('eula')]",
+ "privacyStatementUri": "[parameters('privacyStatementUri')]",
+ "releaseNoteUri": "[parameters('releaseNoteUri')]",
"supportedOSType": "[parameters('supportedOSType')]"
},
"dependsOn": [
diff --git a/avm/res/compute/gallery/image/README.md b/avm/res/compute/gallery/image/README.md
index 62d520493c..0c99e3a326 100644
--- a/avm/res/compute/gallery/image/README.md
+++ b/avm/res/compute/gallery/image/README.md
@@ -24,6 +24,10 @@ This module deploys an Azure Compute Gallery Image Definition.
| Parameter | Type | Description |
| :-- | :-- | :-- |
| [`name`](#parameter-name) | string | Name of the image definition. |
+| [`offer`](#parameter-offer) | string | The name of the gallery Image Definition offer. |
+| [`osType`](#parameter-ostype) | string | OS type of the image to be created. |
+| [`publisher`](#parameter-publisher) | string | The name of the gallery Image Definition publisher. |
+| [`sku`](#parameter-sku) | string | The name of the gallery Image Definition SKU. |
**Conditional parameters**
@@ -38,27 +42,29 @@ This module deploys an Azure Compute Gallery Image Definition.
| [`description`](#parameter-description) | string | The description of this gallery Image Definition resource. This property is updatable. |
| [`endOfLife`](#parameter-endoflife) | string | The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z. |
| [`eula`](#parameter-eula) | string | The Eula agreement for the gallery Image Definition. Has to be a valid URL. |
-| [`excludedDiskTypes`](#parameter-excludeddisktypes) | array | List of the excluded disk types. E.g. Standard_LRS. |
-| [`hyperVGeneration`](#parameter-hypervgeneration) | string | The hypervisor generation of the Virtual Machine.
- If this value is not specified, then it is determined by the securityType parameter.- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1. |
-| [`isAcceleratedNetworkSupported`](#parameter-isacceleratednetworksupported) | string | The image supports accelerated networking.Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types. |
-| [`isHibernateSupported`](#parameter-ishibernatesupported) | string | The image will support hibernation. |
+| [`excludedDiskTypes`](#parameter-excludeddisktypes) | array | List of the excluded disk types (e.g., Standard_LRS). |
+| [`hyperVGeneration`](#parameter-hypervgeneration) | string | The hypervisor generation of the Virtual Machine.
+- If this value is not specified, then it is determined by the securityType parameter.
+- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.
+ |
+| [`isAcceleratedNetworkSupported`](#parameter-isacceleratednetworksupported) | bool | Specify if the image supports accelerated networking.
+Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.
+This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.
+ |
+| [`isHibernateSupported`](#parameter-ishibernatesupported) | bool | Specifiy if the image supports hibernation. |
| [`location`](#parameter-location) | string | Location for all resources. |
| [`maxRecommendedMemory`](#parameter-maxrecommendedmemory) | int | The maximum amount of RAM in GB recommended for this image. |
| [`maxRecommendedvCPUs`](#parameter-maxrecommendedvcpus) | int | The maximum number of the CPU cores recommended for this image. |
| [`minRecommendedMemory`](#parameter-minrecommendedmemory) | int | The minimum amount of RAM in GB recommended for this image. |
| [`minRecommendedvCPUs`](#parameter-minrecommendedvcpus) | int | The minimum number of the CPU cores recommended for this image. |
-| [`offer`](#parameter-offer) | string | The name of the gallery Image Definition offer. |
| [`osState`](#parameter-osstate) | string | This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'. |
-| [`osType`](#parameter-ostype) | string | OS type of the image to be created. |
| [`planName`](#parameter-planname) | string | The plan ID. |
| [`planPublisherName`](#parameter-planpublishername) | string | The publisher ID. |
| [`privacyStatementUri`](#parameter-privacystatementuri) | string | The privacy statement uri. Has to be a valid URL. |
| [`productName`](#parameter-productname) | string | The product ID. |
-| [`publisher`](#parameter-publisher) | string | The name of the gallery Image Definition publisher. |
| [`releaseNoteUri`](#parameter-releasenoteuri) | string | The release note uri. Has to be a valid URL. |
| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
| [`securityType`](#parameter-securitytype) | string | The security type of the image. Requires a hyperVGeneration V2. |
-| [`sku`](#parameter-sku) | string | The name of the gallery Image Definition SKU. |
| [`tags`](#parameter-tags) | object | Tags for all resources. |
### Parameter: `name`
@@ -68,6 +74,41 @@ Name of the image definition.
- Required: Yes
- Type: string
+### Parameter: `offer`
+
+The name of the gallery Image Definition offer.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `osType`
+
+OS type of the image to be created.
+
+- Required: Yes
+- Type: string
+- Allowed:
+ ```Bicep
+ [
+ 'Linux'
+ 'Windows'
+ ]
+ ```
+
+### Parameter: `publisher`
+
+The name of the gallery Image Definition publisher.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `sku`
+
+The name of the gallery Image Definition SKU.
+
+- Required: Yes
+- Type: string
+
### Parameter: `galleryName`
The name of the parent Azure Shared Image Gallery. Required if the template is used in a standalone deployment.
@@ -88,6 +129,7 @@ The end of life date of the gallery Image Definition. This property can be used
- Required: No
- Type: string
+- Default: `''`
### Parameter: `eula`
@@ -98,22 +140,24 @@ The Eula agreement for the gallery Image Definition. Has to be a valid URL.
### Parameter: `excludedDiskTypes`
-List of the excluded disk types. E.g. Standard_LRS.
+List of the excluded disk types (e.g., Standard_LRS).
- Required: No
- Type: array
+- Default: `[]`
### Parameter: `hyperVGeneration`
-The hypervisor generation of the Virtual Machine.- If this value is not specified, then it is determined by the securityType parameter.- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.
+The hypervisor generation of the Virtual Machine.
+- If this value is not specified, then it is determined by the securityType parameter.
+- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.
+
- Required: No
- Type: string
-- Default: `''`
- Allowed:
```Bicep
[
- ''
'V1'
'V2'
]
@@ -121,33 +165,22 @@ The hypervisor generation of the Virtual Machine.- If this value is not spec
### Parameter: `isAcceleratedNetworkSupported`
-The image supports accelerated networking.Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.
+Specify if the image supports accelerated networking.
+Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.
+This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.
+
- Required: No
-- Type: string
-- Default: `'false'`
-- Allowed:
- ```Bicep
- [
- 'false'
- 'true'
- ]
- ```
+- Type: bool
+- Default: `False`
### Parameter: `isHibernateSupported`
-The image will support hibernation.
+Specifiy if the image supports hibernation.
- Required: No
-- Type: string
-- Default: `'false'`
-- Allowed:
- ```Bicep
- [
- 'false'
- 'true'
- ]
- ```
+- Type: bool
+- Default: `False`
### Parameter: `location`
@@ -189,14 +222,6 @@ The minimum number of the CPU cores recommended for this image.
- Type: int
- Default: `1`
-### Parameter: `offer`
-
-The name of the gallery Image Definition offer.
-
-- Required: No
-- Type: string
-- Default: `'0001-com-ubuntu-server-jammy'`
-
### Parameter: `osState`
This property allows the user to specify whether the virtual machines created under this image are 'Generalized' or 'Specialized'.
@@ -212,21 +237,6 @@ This property allows the user to specify whether the virtual machines created un
]
```
-### Parameter: `osType`
-
-OS type of the image to be created.
-
-- Required: No
-- Type: string
-- Default: `'Linux'`
-- Allowed:
- ```Bicep
- [
- 'Linux'
- 'Windows'
- ]
- ```
-
### Parameter: `planName`
The plan ID.
@@ -255,14 +265,6 @@ The product ID.
- Required: No
- Type: string
-### Parameter: `publisher`
-
-The name of the gallery Image Definition publisher.
-
-- Required: No
-- Type: string
-- Default: `'canonical'`
-
### Parameter: `releaseNoteUri`
The release note uri. Has to be a valid URL.
@@ -376,14 +378,6 @@ The security type of the image. Requires a hyperVGeneration V2.
]
```
-### Parameter: `sku`
-
-The name of the gallery Image Definition SKU.
-
-- Required: No
-- Type: string
-- Default: `'22_04-lts-gen2'`
-
### Parameter: `tags`
Tags for all resources.
diff --git a/avm/res/compute/gallery/image/main.bicep b/avm/res/compute/gallery/image/main.bicep
index 26b015f197..d82749672e 100644
--- a/avm/res/compute/gallery/image/main.bicep
+++ b/avm/res/compute/gallery/image/main.bicep
@@ -12,12 +12,12 @@ param location string = resourceGroup().location
@minLength(1)
param galleryName string
-@sys.description('Optional. OS type of the image to be created.')
+@sys.description('Required. OS type of the image to be created.')
@allowed([
'Windows'
'Linux'
])
-param osType string = 'Linux'
+param osType string
@sys.description('Optional. This property allows the user to specify whether the virtual machines created under this image are \'Generalized\' or \'Specialized\'.')
@allowed([
@@ -26,14 +26,14 @@ param osType string = 'Linux'
])
param osState string = 'Generalized'
-@sys.description('Optional. The name of the gallery Image Definition publisher.')
-param publisher string = 'canonical'
+@sys.description('Required. The name of the gallery Image Definition publisher.')
+param publisher string
-@sys.description('Optional. The name of the gallery Image Definition offer.')
-param offer string = '0001-com-ubuntu-server-jammy'
+@sys.description('Required. The name of the gallery Image Definition offer.')
+param offer string
-@sys.description('Optional. The name of the gallery Image Definition SKU.')
-param sku string = '22_04-lts-gen2'
+@sys.description('Required. The name of the gallery Image Definition SKU.')
+param sku string
@sys.description('Optional. The minimum number of the CPU cores recommended for this image.')
@minValue(1)
@@ -55,13 +55,15 @@ param minRecommendedMemory int = 4
@maxValue(4000)
param maxRecommendedMemory int = 16
-@sys.description('Optional. The hypervisor generation of the Virtual Machine.- If this value is not specified, then it is determined by the securityType parameter.- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.')
+@sys.description('''Optional. The hypervisor generation of the Virtual Machine.
+- If this value is not specified, then it is determined by the securityType parameter.
+- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.
+''')
@allowed([
- ''
'V1'
'V2'
])
-param hyperVGeneration string = ''
+param hyperVGeneration string?
@sys.description('Optional. The security type of the image. Requires a hyperVGeneration V2.')
@allowed([
@@ -72,19 +74,14 @@ param hyperVGeneration string = ''
])
param securityType string = 'Standard'
-@sys.description('Optional. The image will support hibernation.')
-@allowed([
- 'true'
- 'false'
-])
-param isHibernateSupported string = 'false'
+@sys.description('Optional. Specifiy if the image supports hibernation.')
+param isHibernateSupported bool = false
-@sys.description('Optional. The image supports accelerated networking.Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.')
-@allowed([
- 'true'
- 'false'
-])
-param isAcceleratedNetworkSupported string = 'false'
+@sys.description('''Optional. Specify if the image supports accelerated networking.
+Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.
+This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.
+''')
+param isAcceleratedNetworkSupported bool = false
@sys.description('Optional. The description of this gallery Image Definition resource. This property is updatable.')
param description string?
@@ -108,10 +105,10 @@ param planName string?
param planPublisherName string?
@sys.description('Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z.')
-param endOfLife string?
+param endOfLife string = ''
-@sys.description('Optional. List of the excluded disk types. E.g. Standard_LRS.')
-param excludedDiskTypes array?
+@sys.description('Optional. List of the excluded disk types (e.g., Standard_LRS).')
+param excludedDiskTypes array = []
@sys.description('Optional. Array of role assignments to create.')
param roleAssignments roleAssignmentType
@@ -155,42 +152,35 @@ resource image 'Microsoft.Compute/galleries/images@2022-03-03' = {
max: maxRecommendedMemory
}
}
- hyperVGeneration: !empty(hyperVGeneration) ? hyperVGeneration : (!empty(securityType) ? 'V2' : 'V1')
- features: !empty(securityType) && securityType != 'Standard' ? [
- {
- name: 'SecurityType'
- value: securityType
- }
- {
- name: 'IsAcceleratedNetworkSupported'
- value: isAcceleratedNetworkSupported
- }
- {
- name: 'IsHibernateSupported'
- value: isHibernateSupported
- }
- ] : [
- {
- name: 'IsAcceleratedNetworkSupported'
- value: isAcceleratedNetworkSupported
- }
- {
- name: 'IsHibernateSupported'
- value: isHibernateSupported
- }
- ]
- description: description ?? ''
- eula: eula ?? ''
- privacyStatementUri: privacyStatementUri ?? ''
- releaseNoteUri: releaseNoteUri ?? ''
+ hyperVGeneration: hyperVGeneration ?? (!empty(securityType) ? 'V2' : 'V1')
+ features: union([
+ {
+ name: 'IsAcceleratedNetworkSupported'
+ value: '${isAcceleratedNetworkSupported}'
+ }
+ {
+ name: 'IsHibernateSupported'
+ value: '${isHibernateSupported}'
+ }
+ ],
+ (securityType != 'Standard' ? [
+ {
+ name: 'SecurityType'
+ value: securityType
+ }
+ ] : []))
+ description: description
+ eula: eula
+ privacyStatementUri: privacyStatementUri
+ releaseNoteUri: releaseNoteUri
purchasePlan: {
product: productName
name: planName
publisher: planPublisherName
}
- endOfLifeDate: endOfLife ?? ''
+ endOfLifeDate: endOfLife
disallowed: {
- diskTypes: excludedDiskTypes ?? []
+ diskTypes: excludedDiskTypes
}
}
}
@@ -220,6 +210,7 @@ output name string = image.name
@sys.description('The location the resource was deployed into.')
output location string = image.location
+
// =============== //
// Definitions //
// =============== //
diff --git a/avm/res/compute/gallery/image/main.json b/avm/res/compute/gallery/image/main.json
index 42a1c36612..b9e48db9e8 100644
--- a/avm/res/compute/gallery/image/main.json
+++ b/avm/res/compute/gallery/image/main.json
@@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.24.24.22086",
- "templateHash": "8041246972502261835"
+ "templateHash": "11732013039305076688"
},
"name": "Compute Galleries Image Definitions",
"description": "This module deploys an Azure Compute Gallery Image Definition.",
@@ -103,13 +103,12 @@
},
"osType": {
"type": "string",
- "defaultValue": "Linux",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
- "description": "Optional. OS type of the image to be created."
+ "description": "Required. OS type of the image to be created."
}
},
"osState": {
@@ -125,23 +124,20 @@
},
"publisher": {
"type": "string",
- "defaultValue": "canonical",
"metadata": {
- "description": "Optional. The name of the gallery Image Definition publisher."
+ "description": "Required. The name of the gallery Image Definition publisher."
}
},
"offer": {
"type": "string",
- "defaultValue": "0001-com-ubuntu-server-jammy",
"metadata": {
- "description": "Optional. The name of the gallery Image Definition offer."
+ "description": "Required. The name of the gallery Image Definition offer."
}
},
"sku": {
"type": "string",
- "defaultValue": "22_04-lts-gen2",
"metadata": {
- "description": "Optional. The name of the gallery Image Definition SKU."
+ "description": "Required. The name of the gallery Image Definition SKU."
}
},
"minRecommendedvCPUs": {
@@ -182,14 +178,13 @@
},
"hyperVGeneration": {
"type": "string",
- "defaultValue": "",
+ "nullable": true,
"allowedValues": [
- "",
"V1",
"V2"
],
"metadata": {
- "description": "Optional. The hypervisor generation of the Virtual Machine.- If this value is not specified, then it is determined by the securityType parameter.- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1."
+ "description": "Optional. The hypervisor generation of the Virtual Machine.\n- If this value is not specified, then it is determined by the securityType parameter.\n- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.\n"
}
},
"securityType": {
@@ -206,25 +201,17 @@
}
},
"isHibernateSupported": {
- "type": "string",
- "defaultValue": "false",
- "allowedValues": [
- "true",
- "false"
- ],
+ "type": "bool",
+ "defaultValue": false,
"metadata": {
- "description": "Optional. The image will support hibernation."
+ "description": "Optional. Specifiy if the image supports hibernation."
}
},
"isAcceleratedNetworkSupported": {
- "type": "string",
- "defaultValue": "false",
- "allowedValues": [
- "true",
- "false"
- ],
+ "type": "bool",
+ "defaultValue": false,
"metadata": {
- "description": "Optional. The image supports accelerated networking.Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types."
+ "description": "Optional. Specify if the image supports accelerated networking.\nAccelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.\nThis high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.\n"
}
},
"description": {
@@ -278,16 +265,16 @@
},
"endOfLife": {
"type": "string",
- "nullable": true,
+ "defaultValue": "",
"metadata": {
"description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z."
}
},
"excludedDiskTypes": {
"type": "array",
- "nullable": true,
+ "defaultValue": [],
"metadata": {
- "description": "Optional. List of the excluded disk types. E.g. Standard_LRS."
+ "description": "Optional. List of the excluded disk types (e.g., Standard_LRS)."
}
},
"roleAssignments": {
@@ -345,20 +332,20 @@
"max": "[parameters('maxRecommendedMemory')]"
}
},
- "hyperVGeneration": "[if(not(empty(parameters('hyperVGeneration'))), parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]",
- "features": "[if(and(not(empty(parameters('securityType'))), not(equals(parameters('securityType'), 'Standard'))), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType')), createObject('name', 'IsAcceleratedNetworkSupported', 'value', parameters('isAcceleratedNetworkSupported')), createObject('name', 'IsHibernateSupported', 'value', parameters('isHibernateSupported'))), createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', parameters('isAcceleratedNetworkSupported')), createObject('name', 'IsHibernateSupported', 'value', parameters('isHibernateSupported'))))]",
- "description": "[coalesce(parameters('description'), '')]",
- "eula": "[coalesce(parameters('eula'), '')]",
- "privacyStatementUri": "[coalesce(parameters('privacyStatementUri'), '')]",
- "releaseNoteUri": "[coalesce(parameters('releaseNoteUri'), '')]",
+ "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]",
+ "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported'))), createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), if(not(equals(parameters('securityType'), 'Standard')), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType'))), createArray()))]",
+ "description": "[parameters('description')]",
+ "eula": "[parameters('eula')]",
+ "privacyStatementUri": "[parameters('privacyStatementUri')]",
+ "releaseNoteUri": "[parameters('releaseNoteUri')]",
"purchasePlan": {
"product": "[parameters('productName')]",
"name": "[parameters('planName')]",
"publisher": "[parameters('planPublisherName')]"
},
- "endOfLifeDate": "[coalesce(parameters('endOfLife'), '')]",
+ "endOfLifeDate": "[parameters('endOfLife')]",
"disallowed": {
- "diskTypes": "[coalesce(parameters('excludedDiskTypes'), createArray())]"
+ "diskTypes": "[parameters('excludedDiskTypes')]"
}
},
"dependsOn": [
diff --git a/avm/res/compute/gallery/main.bicep b/avm/res/compute/gallery/main.bicep
index ef252bf0b2..60f12f0655 100644
--- a/avm/res/compute/gallery/main.bicep
+++ b/avm/res/compute/gallery/main.bicep
@@ -30,6 +30,12 @@ param tags object?
@sys.description('Optional. Enable/Disable usage telemetry for module.')
param enableTelemetry bool = true
+@sys.description('Optional. Profile for gallery sharing to subscription or tenant.')
+param sharingProfile object?
+
+@sys.description('Optional. Soft deletion policy of the gallery.')
+param softDeletePolicy object?
+
var builtInRoleNames = {
'Compute Gallery Sharing Admin': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1ef6a3be-d0ac-425d-8c01-acb62866290b')
Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
@@ -62,8 +68,10 @@ resource gallery 'Microsoft.Compute/galleries@2022-03-03' = {
location: location
tags: tags
properties: {
- description: description ?? ''
- identifier: {}
+ description: description
+ // identifier: {} // Contains only read-only properties
+ sharingProfile: sharingProfile
+ softDeletePolicy: softDeletePolicy
}
}
@@ -90,14 +98,13 @@ resource gallery_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-0
scope: gallery
}]
-// Applications
module galleries_applications 'application/main.bicep' = [for (application, index) in (applications ?? []): {
name: '${uniqueString(deployment().name, location)}-Gallery-Application-${index}'
params: {
- name: application.name
location: location
+ name: application.name
galleryName: gallery.name
- supportedOSType: application.?supportedOSType
+ supportedOSType: application.supportedOSType
description: application.?description
eula: application.?eula
privacyStatementUri: application.?privacyStatementUri
@@ -109,26 +116,23 @@ module galleries_applications 'application/main.bicep' = [for (application, inde
}
}]
-// Images
module galleries_images 'image/main.bicep' = [for (image, index) in (images ?? []): {
name: '${uniqueString(deployment().name, location)}-Gallery-Image-${index}'
params: {
- name: image.name
location: location
+ name: image.name
galleryName: gallery.name
- osType: image.?osType
+ osType: image.osType
osState: image.?osState
- publisher: image.?publisher
- offer: image.?offer
- sku: image.?sku
+ publisher: image.publisher
+ offer: image.offer
+ sku: image.sku
minRecommendedvCPUs: image.?minRecommendedvCPUs
maxRecommendedvCPUs: image.?maxRecommendedvCPUs
minRecommendedMemory: image.?minRecommendedMemory
maxRecommendedMemory: image.?maxRecommendedMemory
- hyperVGeneration: image.?hyperVGeneration ?? 'V1'
+ hyperVGeneration: image.?hyperVGeneration
securityType: image.?securityType
- isAcceleratedNetworkSupported: image.?isAcceleratedNetworkSupported
- isHibernateSupported: image.?isHibernateSupported
description: image.?description
eula: image.?eula
privacyStatementUri: image.?privacyStatementUri
diff --git a/avm/res/compute/gallery/main.json b/avm/res/compute/gallery/main.json
index 6462a5c3af..a499939ac6 100644
--- a/avm/res/compute/gallery/main.json
+++ b/avm/res/compute/gallery/main.json
@@ -6,7 +6,7 @@
"_generator": {
"name": "bicep",
"version": "0.24.24.22086",
- "templateHash": "6088878443821644350"
+ "templateHash": "17536269376876527435"
},
"name": "Azure Compute Galleries",
"description": "This module deploys an Azure Compute Gallery (formerly known as Shared Image Gallery).",
@@ -166,6 +166,20 @@
"metadata": {
"description": "Optional. Enable/Disable usage telemetry for module."
}
+ },
+ "sharingProfile": {
+ "type": "object",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Profile for gallery sharing to subscription or tenant."
+ }
+ },
+ "softDeletePolicy": {
+ "type": "object",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Soft deletion policy of the gallery."
+ }
}
},
"variables": {
@@ -206,8 +220,9 @@
"location": "[parameters('location')]",
"tags": "[parameters('tags')]",
"properties": {
- "description": "[coalesce(parameters('description'), '')]",
- "identifier": {}
+ "description": "[parameters('description')]",
+ "sharingProfile": "[parameters('sharingProfile')]",
+ "softDeletePolicy": "[parameters('softDeletePolicy')]"
}
},
"gallery_lock": {
@@ -260,17 +275,17 @@
},
"mode": "Incremental",
"parameters": {
- "name": {
- "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].name]"
- },
"location": {
"value": "[parameters('location')]"
},
+ "name": {
+ "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].name]"
+ },
"galleryName": {
"value": "[parameters('name')]"
},
"supportedOSType": {
- "value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'supportedOSType')]"
+ "value": "[coalesce(parameters('applications'), createArray())[copyIndex()].supportedOSType]"
},
"description": {
"value": "[tryGet(coalesce(parameters('applications'), createArray())[copyIndex()], 'description')]"
@@ -305,7 +320,7 @@
"_generator": {
"name": "bicep",
"version": "0.24.24.22086",
- "templateHash": "7964925859326857094"
+ "templateHash": "9951919331605340265"
},
"name": "Compute Galleries Applications",
"description": "This module deploys an Azure Compute Gallery Application.",
@@ -430,13 +445,12 @@
},
"supportedOSType": {
"type": "string",
- "defaultValue": "Windows",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
- "description": "Optional. This property allows you to specify the supported type of the OS that application is built for."
+ "description": "Required. This property allows you to specify the supported type of the OS that application is built for."
}
},
"endOfLifeDate": {
@@ -492,11 +506,11 @@
"tags": "[parameters('tags')]",
"properties": {
"customActions": "[parameters('customActions')]",
- "description": "[coalesce(parameters('description'), '')]",
- "endOfLifeDate": "[coalesce(parameters('endOfLifeDate'), '')]",
- "eula": "[coalesce(parameters('eula'), '')]",
- "privacyStatementUri": "[coalesce(parameters('privacyStatementUri'), '')]",
- "releaseNoteUri": "[coalesce(parameters('releaseNoteUri'), '')]",
+ "description": "[parameters('description')]",
+ "endOfLifeDate": "[parameters('endOfLifeDate')]",
+ "eula": "[parameters('eula')]",
+ "privacyStatementUri": "[parameters('privacyStatementUri')]",
+ "releaseNoteUri": "[parameters('releaseNoteUri')]",
"supportedOSType": "[parameters('supportedOSType')]"
},
"dependsOn": [
@@ -576,29 +590,29 @@
},
"mode": "Incremental",
"parameters": {
- "name": {
- "value": "[coalesce(parameters('images'), createArray())[copyIndex()].name]"
- },
"location": {
"value": "[parameters('location')]"
},
+ "name": {
+ "value": "[coalesce(parameters('images'), createArray())[copyIndex()].name]"
+ },
"galleryName": {
"value": "[parameters('name')]"
},
"osType": {
- "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'osType')]"
+ "value": "[coalesce(parameters('images'), createArray())[copyIndex()].osType]"
},
"osState": {
"value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'osState')]"
},
"publisher": {
- "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'publisher')]"
+ "value": "[coalesce(parameters('images'), createArray())[copyIndex()].publisher]"
},
"offer": {
- "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'offer')]"
+ "value": "[coalesce(parameters('images'), createArray())[copyIndex()].offer]"
},
"sku": {
- "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'sku')]"
+ "value": "[coalesce(parameters('images'), createArray())[copyIndex()].sku]"
},
"minRecommendedvCPUs": {
"value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'minRecommendedvCPUs')]"
@@ -613,17 +627,11 @@
"value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'maxRecommendedMemory')]"
},
"hyperVGeneration": {
- "value": "[coalesce(tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'hyperVGeneration'), 'V1')]"
+ "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'hyperVGeneration')]"
},
"securityType": {
"value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'securityType')]"
},
- "isAcceleratedNetworkSupported": {
- "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isAcceleratedNetworkSupported')]"
- },
- "isHibernateSupported": {
- "value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'isHibernateSupported')]"
- },
"description": {
"value": "[tryGet(coalesce(parameters('images'), createArray())[copyIndex()], 'description')]"
},
@@ -666,7 +674,7 @@
"_generator": {
"name": "bicep",
"version": "0.24.24.22086",
- "templateHash": "8041246972502261835"
+ "templateHash": "11732013039305076688"
},
"name": "Compute Galleries Image Definitions",
"description": "This module deploys an Azure Compute Gallery Image Definition.",
@@ -763,13 +771,12 @@
},
"osType": {
"type": "string",
- "defaultValue": "Linux",
"allowedValues": [
"Windows",
"Linux"
],
"metadata": {
- "description": "Optional. OS type of the image to be created."
+ "description": "Required. OS type of the image to be created."
}
},
"osState": {
@@ -785,23 +792,20 @@
},
"publisher": {
"type": "string",
- "defaultValue": "canonical",
"metadata": {
- "description": "Optional. The name of the gallery Image Definition publisher."
+ "description": "Required. The name of the gallery Image Definition publisher."
}
},
"offer": {
"type": "string",
- "defaultValue": "0001-com-ubuntu-server-jammy",
"metadata": {
- "description": "Optional. The name of the gallery Image Definition offer."
+ "description": "Required. The name of the gallery Image Definition offer."
}
},
"sku": {
"type": "string",
- "defaultValue": "22_04-lts-gen2",
"metadata": {
- "description": "Optional. The name of the gallery Image Definition SKU."
+ "description": "Required. The name of the gallery Image Definition SKU."
}
},
"minRecommendedvCPUs": {
@@ -842,14 +846,13 @@
},
"hyperVGeneration": {
"type": "string",
- "defaultValue": "",
+ "nullable": true,
"allowedValues": [
- "",
"V1",
"V2"
],
"metadata": {
- "description": "Optional. The hypervisor generation of the Virtual Machine.- If this value is not specified, then it is determined by the securityType parameter.- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1."
+ "description": "Optional. The hypervisor generation of the Virtual Machine.\n- If this value is not specified, then it is determined by the securityType parameter.\n- If the securityType parameter is specified, then the value of hyperVGeneration will be V2, else V1.\n"
}
},
"securityType": {
@@ -866,25 +869,17 @@
}
},
"isHibernateSupported": {
- "type": "string",
- "defaultValue": "false",
- "allowedValues": [
- "true",
- "false"
- ],
+ "type": "bool",
+ "defaultValue": false,
"metadata": {
- "description": "Optional. The image will support hibernation."
+ "description": "Optional. Specifiy if the image supports hibernation."
}
},
"isAcceleratedNetworkSupported": {
- "type": "string",
- "defaultValue": "false",
- "allowedValues": [
- "true",
- "false"
- ],
+ "type": "bool",
+ "defaultValue": false,
"metadata": {
- "description": "Optional. The image supports accelerated networking.Accelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.This high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types."
+ "description": "Optional. Specify if the image supports accelerated networking.\nAccelerated networking enables single root I/O virtualization (SR-IOV) to a VM, greatly improving its networking performance.\nThis high-performance path bypasses the host from the data path, which reduces latency, jitter, and CPU utilization for the most demanding network workloads on supported VM types.\n"
}
},
"description": {
@@ -938,16 +933,16 @@
},
"endOfLife": {
"type": "string",
- "nullable": true,
+ "defaultValue": "",
"metadata": {
"description": "Optional. The end of life date of the gallery Image Definition. This property can be used for decommissioning purposes. This property is updatable. Allowed format: 2020-01-10T23:00:00.000Z."
}
},
"excludedDiskTypes": {
"type": "array",
- "nullable": true,
+ "defaultValue": [],
"metadata": {
- "description": "Optional. List of the excluded disk types. E.g. Standard_LRS."
+ "description": "Optional. List of the excluded disk types (e.g., Standard_LRS)."
}
},
"roleAssignments": {
@@ -1005,20 +1000,20 @@
"max": "[parameters('maxRecommendedMemory')]"
}
},
- "hyperVGeneration": "[if(not(empty(parameters('hyperVGeneration'))), parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]",
- "features": "[if(and(not(empty(parameters('securityType'))), not(equals(parameters('securityType'), 'Standard'))), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType')), createObject('name', 'IsAcceleratedNetworkSupported', 'value', parameters('isAcceleratedNetworkSupported')), createObject('name', 'IsHibernateSupported', 'value', parameters('isHibernateSupported'))), createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', parameters('isAcceleratedNetworkSupported')), createObject('name', 'IsHibernateSupported', 'value', parameters('isHibernateSupported'))))]",
- "description": "[coalesce(parameters('description'), '')]",
- "eula": "[coalesce(parameters('eula'), '')]",
- "privacyStatementUri": "[coalesce(parameters('privacyStatementUri'), '')]",
- "releaseNoteUri": "[coalesce(parameters('releaseNoteUri'), '')]",
+ "hyperVGeneration": "[coalesce(parameters('hyperVGeneration'), if(not(empty(parameters('securityType'))), 'V2', 'V1'))]",
+ "features": "[union(createArray(createObject('name', 'IsAcceleratedNetworkSupported', 'value', format('{0}', parameters('isAcceleratedNetworkSupported'))), createObject('name', 'IsHibernateSupported', 'value', format('{0}', parameters('isHibernateSupported')))), if(not(equals(parameters('securityType'), 'Standard')), createArray(createObject('name', 'SecurityType', 'value', parameters('securityType'))), createArray()))]",
+ "description": "[parameters('description')]",
+ "eula": "[parameters('eula')]",
+ "privacyStatementUri": "[parameters('privacyStatementUri')]",
+ "releaseNoteUri": "[parameters('releaseNoteUri')]",
"purchasePlan": {
"product": "[parameters('productName')]",
"name": "[parameters('planName')]",
"publisher": "[parameters('planPublisherName')]"
},
- "endOfLifeDate": "[coalesce(parameters('endOfLife'), '')]",
+ "endOfLifeDate": "[parameters('endOfLife')]",
"disallowed": {
- "diskTypes": "[coalesce(parameters('excludedDiskTypes'), createArray())]"
+ "diskTypes": "[parameters('excludedDiskTypes')]"
}
},
"dependsOn": [
diff --git a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep
index 89d7c2931a..f9de331bd7 100644
--- a/avm/res/compute/gallery/tests/e2e/max/main.test.bicep
+++ b/avm/res/compute/gallery/tests/e2e/max/main.test.bicep
@@ -35,8 +35,8 @@ module nestedDependencies 'dependencies.bicep' = {
scope: resourceGroup
name: '${uniqueString(deployment().name, location)}-nestedDependencies'
params: {
- managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
location: location
+ managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
}
}
@@ -49,8 +49,8 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
scope: resourceGroup
name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
params: {
- name: '${namePrefix}${serviceShort}001'
location: location
+ name: '${namePrefix}${serviceShort}001'
lock: {
kind: 'CanNotDelete'
name: 'myCustomLockName'
@@ -58,6 +58,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
applications: [
{
name: '${namePrefix}-${serviceShort}-appd-001'
+ supportedOSType: 'Linux'
}
{
name: '${namePrefix}-${serviceShort}-appd-002'
@@ -72,41 +73,13 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
}
]
images: [
- {
- name: '${namePrefix}-az-imgd-ws-001'
- }
{
hyperVGeneration: 'V1'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-ws-002'
+ name: '${namePrefix}-az-imgd-ws-001'
offer: 'WindowsServer'
- osState: 'Generalized'
osType: 'Windows'
publisher: 'MicrosoftWindowsServer'
- roleAssignments: [
- {
- roleDefinitionIdOrName: 'Reader'
- principalId: nestedDependencies.outputs.managedIdentityPrincipalId
- principalType: 'ServicePrincipal'
- }
- ]
sku: '2022-datacenter-azure-edition'
- }
- {
- hyperVGeneration: 'V2'
- isHibernateSupported: 'true'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-ws-003'
- offer: 'WindowsServer'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsServer'
roleAssignments: [
{
roleDefinitionIdOrName: 'Reader'
@@ -114,16 +87,15 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
principalType: 'ServicePrincipal'
}
]
- sku: '2022-datacenter-azure-edition-hibernate'
}
{
hyperVGeneration: 'V2'
- isAcceleratedNetworkSupported: 'true'
+ isHibernateSupported: true
maxRecommendedMemory: 16
maxRecommendedvCPUs: 8
minRecommendedMemory: 4
minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-ws-004'
+ name: '${namePrefix}-az-imgd-ws-002'
offer: 'WindowsServer'
osState: 'Generalized'
osType: 'Windows'
@@ -135,7 +107,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
principalType: 'ServicePrincipal'
}
]
- sku: '2022-datacenter-azure-edition-accnet'
+ sku: '2022-datacenter-azure-edition-hibernate'
}
{
hyperVGeneration: 'V2'
@@ -144,7 +116,7 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
maxRecommendedvCPUs: 4
minRecommendedMemory: 4
minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-wdtl-002'
+ name: '${namePrefix}-az-imgd-wdtl-001'
offer: 'WindowsDesktop'
osState: 'Generalized'
osType: 'Windows'
diff --git a/avm/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep
new file mode 100644
index 0000000000..a7f42aee7b
--- /dev/null
+++ b/avm/res/compute/gallery/tests/e2e/waf-aligned/dependencies.bicep
@@ -0,0 +1,13 @@
+@description('Optional. The location to deploy to.')
+param location string = resourceGroup().location
+
+@description('Required. The name of the Managed Identity to create.')
+param managedIdentityName string
+
+resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
+ name: managedIdentityName
+ location: location
+}
+
+@description('The principal ID of the created Managed Identity.')
+output managedIdentityPrincipalId string = managedIdentity.properties.principalId
diff --git a/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep b/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep
index 32cd165e60..2484672428 100644
--- a/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep
+++ b/avm/res/compute/gallery/tests/e2e/waf-aligned/main.test.bicep
@@ -40,93 +40,22 @@ module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem'
scope: resourceGroup
name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
params: {
- name: '${namePrefix}${serviceShort}001'
location: location
- lock: {
- kind: 'CanNotDelete'
- name: 'myCustomLockName'
- }
+ name: '${namePrefix}${serviceShort}001'
applications: [
{
name: '${namePrefix}-${serviceShort}-appd-001'
- }
- {
- name: '${namePrefix}-${serviceShort}-appd-002'
supportedOSType: 'Windows'
}
]
images: [
{
name: '${namePrefix}-az-imgd-ws-001'
- }
- {
- hyperVGeneration: 'V1'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-ws-002'
offer: 'WindowsServer'
- osState: 'Generalized'
osType: 'Windows'
publisher: 'MicrosoftWindowsServer'
sku: '2022-datacenter-azure-edition'
}
- {
- hyperVGeneration: 'V2'
- isHibernateSupported: 'true'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-ws-003'
- offer: 'WindowsServer'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsServer'
- sku: '2022-datacenter-azure-edition-hibernate'
- }
- {
- hyperVGeneration: 'V2'
- isAcceleratedNetworkSupported: 'true'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 8
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-ws-004'
- offer: 'WindowsServer'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsServer'
- sku: '2022-datacenter-azure-edition-accnet'
- }
- {
- hyperVGeneration: 'V2'
- securityType: 'TrustedLaunch'
- maxRecommendedMemory: 16
- maxRecommendedvCPUs: 4
- minRecommendedMemory: 4
- minRecommendedvCPUs: 2
- name: '${namePrefix}-az-imgd-wdtl-002'
- offer: 'WindowsDesktop'
- osState: 'Generalized'
- osType: 'Windows'
- publisher: 'MicrosoftWindowsDesktop'
- sku: 'Win11-21H2'
- }
- {
- hyperVGeneration: 'V2'
- maxRecommendedMemory: 32
- maxRecommendedvCPUs: 4
- minRecommendedMemory: 4
- minRecommendedvCPUs: 1
- name: '${namePrefix}-az-imgd-us-001'
- offer: '0001-com-ubuntu-server-focal'
- osState: 'Generalized'
- osType: 'Linux'
- publisher: 'canonical'
- sku: '20_04-lts-gen2'
- }
]
tags: {
'hidden-title': 'This is visible in the resource name'
diff --git a/avm/res/compute/gallery/version.json b/avm/res/compute/gallery/version.json
index 83083db694..1c035df49f 100644
--- a/avm/res/compute/gallery/version.json
+++ b/avm/res/compute/gallery/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
- "version": "0.1",
+ "version": "0.2",
"pathFilters": [
"./main.json"
]
diff --git a/avm/res/network/firewall-policy/ORPHANED.md b/avm/res/network/firewall-policy/ORPHANED.md
new file mode 100644
index 0000000000..ef8fa911d2
--- /dev/null
+++ b/avm/res/network/firewall-policy/ORPHANED.md
@@ -0,0 +1,4 @@
+⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️
+
+- Only security and bug fixes are being handled by the AVM core team at present.
+- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)!
\ No newline at end of file
diff --git a/avm/res/network/firewall-policy/README.md b/avm/res/network/firewall-policy/README.md
new file mode 100644
index 0000000000..0009160b35
--- /dev/null
+++ b/avm/res/network/firewall-policy/README.md
@@ -0,0 +1,685 @@
+# Firewall Policies `[Microsoft.Network/firewallPolicies]`
+
+> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️
+>
+> - Only security and bug fixes are being handled by the AVM core team at present.
+> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)!
+
+This module deploys a Firewall Policy.
+
+## Navigation
+
+- [Resource Types](#Resource-Types)
+- [Usage examples](#Usage-examples)
+- [Parameters](#Parameters)
+- [Outputs](#Outputs)
+- [Cross-referenced modules](#Cross-referenced-modules)
+- [Data Collection](#Data-Collection)
+
+## Resource Types
+
+| Resource Type | API Version |
+| :-- | :-- |
+| `Microsoft.Network/firewallPolicies` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/firewallPolicies) |
+| `Microsoft.Network/firewallPolicies/ruleCollectionGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/firewallPolicies/ruleCollectionGroups) |
+
+## Usage examples
+
+The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository.
+
+>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order.
+
+>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/firewall-policy:`.
+
+- [Using only defaults](#example-1-using-only-defaults)
+- [Using large parameter set](#example-2-using-large-parameter-set)
+- [WAF-aligned](#example-3-waf-aligned)
+
+### Example 1: _Using only defaults_
+
+This instance deploys the module with the minimum set of required parameters.
+
+
+
+
+via Bicep module
+
+```bicep
+module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {
+ name: '${uniqueString(deployment().name, location)}-test-nfpmin'
+ params: {
+ // Required parameters
+ name: 'nfpmin001'
+ // Non-required parameters
+ location: ''
+ }
+}
+```
+
+
+
+
+
+
+via JSON Parameter file
+
+```json
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ // Required parameters
+ "name": {
+ "value": "nfpmin001"
+ },
+ // Non-required parameters
+ "location": {
+ "value": ""
+ }
+ }
+}
+```
+
+
+
+
+### Example 2: _Using large parameter set_
+
+This instance deploys the module with most of its features enabled.
+
+
+
+
+via Bicep module
+
+```bicep
+module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {
+ name: '${uniqueString(deployment().name, location)}-test-nfpmax'
+ params: {
+ // Required parameters
+ name: 'nfpmax001'
+ // Non-required parameters
+ allowSqlRedirect: true
+ autoLearnPrivateRanges: 'Enabled'
+ location: ''
+ managedIdentities: {
+ userAssignedResourceIds: [
+ ''
+ ]
+ }
+ mode: 'Alert'
+ ruleCollectionGroups: [
+ {
+ name: 'rule-001'
+ priority: 5000
+ ruleCollections: [
+ {
+ action: {
+ type: 'Allow'
+ }
+ name: 'collection002'
+ priority: 5555
+ ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
+ rules: [
+ {
+ destinationAddresses: [
+ '*'
+ ]
+ destinationFqdns: []
+ destinationIpGroups: []
+ destinationPorts: [
+ '80'
+ ]
+ ipProtocols: [
+ 'TCP'
+ 'UDP'
+ ]
+ name: 'rule002'
+ ruleType: 'NetworkRule'
+ sourceAddresses: [
+ '*'
+ ]
+ sourceIpGroups: []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ tags: {
+ Environment: 'Non-Prod'
+ 'hidden-title': 'This is visible in the resource name'
+ Role: 'DeploymentValidation'
+ }
+ tier: 'Premium'
+ }
+}
+```
+
+
+
+
+
+
+via JSON Parameter file
+
+```json
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ // Required parameters
+ "name": {
+ "value": "nfpmax001"
+ },
+ // Non-required parameters
+ "allowSqlRedirect": {
+ "value": true
+ },
+ "autoLearnPrivateRanges": {
+ "value": "Enabled"
+ },
+ "location": {
+ "value": ""
+ },
+ "managedIdentities": {
+ "value": {
+ "userAssignedResourceIds": [
+ ""
+ ]
+ }
+ },
+ "mode": {
+ "value": "Alert"
+ },
+ "ruleCollectionGroups": {
+ "value": [
+ {
+ "name": "rule-001",
+ "priority": 5000,
+ "ruleCollections": [
+ {
+ "action": {
+ "type": "Allow"
+ },
+ "name": "collection002",
+ "priority": 5555,
+ "ruleCollectionType": "FirewallPolicyFilterRuleCollection",
+ "rules": [
+ {
+ "destinationAddresses": [
+ "*"
+ ],
+ "destinationFqdns": [],
+ "destinationIpGroups": [],
+ "destinationPorts": [
+ "80"
+ ],
+ "ipProtocols": [
+ "TCP",
+ "UDP"
+ ],
+ "name": "rule002",
+ "ruleType": "NetworkRule",
+ "sourceAddresses": [
+ "*"
+ ],
+ "sourceIpGroups": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "tags": {
+ "value": {
+ "Environment": "Non-Prod",
+ "hidden-title": "This is visible in the resource name",
+ "Role": "DeploymentValidation"
+ }
+ },
+ "tier": {
+ "value": "Premium"
+ }
+ }
+}
+```
+
+
+
+
+### Example 3: _WAF-aligned_
+
+This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.
+
+
+
+
+via Bicep module
+
+```bicep
+module firewallPolicy 'br/public:avm/res/network/firewall-policy:' = {
+ name: '${uniqueString(deployment().name, location)}-test-nfpwaf'
+ params: {
+ // Required parameters
+ name: 'nfpwaf001'
+ // Non-required parameters
+ allowSqlRedirect: true
+ autoLearnPrivateRanges: 'Enabled'
+ location: ''
+ ruleCollectionGroups: [
+ {
+ name: 'rule-001'
+ priority: 5000
+ ruleCollections: [
+ {
+ action: {
+ type: 'Allow'
+ }
+ name: 'collection002'
+ priority: 5555
+ ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
+ rules: [
+ {
+ destinationAddresses: [
+ '*'
+ ]
+ destinationFqdns: []
+ destinationIpGroups: []
+ destinationPorts: [
+ '80'
+ ]
+ ipProtocols: [
+ 'TCP'
+ 'UDP'
+ ]
+ name: 'rule002'
+ ruleType: 'NetworkRule'
+ sourceAddresses: [
+ '*'
+ ]
+ sourceIpGroups: []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ tags: {
+ Environment: 'Non-Prod'
+ 'hidden-title': 'This is visible in the resource name'
+ Role: 'DeploymentValidation'
+ }
+ threatIntelMode: 'Deny'
+ }
+}
+```
+
+
+
+
+
+
+via JSON Parameter file
+
+```json
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ // Required parameters
+ "name": {
+ "value": "nfpwaf001"
+ },
+ // Non-required parameters
+ "allowSqlRedirect": {
+ "value": true
+ },
+ "autoLearnPrivateRanges": {
+ "value": "Enabled"
+ },
+ "location": {
+ "value": ""
+ },
+ "ruleCollectionGroups": {
+ "value": [
+ {
+ "name": "rule-001",
+ "priority": 5000,
+ "ruleCollections": [
+ {
+ "action": {
+ "type": "Allow"
+ },
+ "name": "collection002",
+ "priority": 5555,
+ "ruleCollectionType": "FirewallPolicyFilterRuleCollection",
+ "rules": [
+ {
+ "destinationAddresses": [
+ "*"
+ ],
+ "destinationFqdns": [],
+ "destinationIpGroups": [],
+ "destinationPorts": [
+ "80"
+ ],
+ "ipProtocols": [
+ "TCP",
+ "UDP"
+ ],
+ "name": "rule002",
+ "ruleType": "NetworkRule",
+ "sourceAddresses": [
+ "*"
+ ],
+ "sourceIpGroups": []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "tags": {
+ "value": {
+ "Environment": "Non-Prod",
+ "hidden-title": "This is visible in the resource name",
+ "Role": "DeploymentValidation"
+ }
+ },
+ "threatIntelMode": {
+ "value": "Deny"
+ }
+ }
+}
+```
+
+
+
+
+
+## Parameters
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-name) | string | Name of the Firewall Policy. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`allowSqlRedirect`](#parameter-allowsqlredirect) | bool | A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999. |
+| [`autoLearnPrivateRanges`](#parameter-autolearnprivateranges) | string | The operation mode for automatically learning private ranges to not be SNAT. |
+| [`basePolicyResourceId`](#parameter-basepolicyresourceid) | string | Resource ID of the base policy. |
+| [`bypassTrafficSettings`](#parameter-bypasstrafficsettings) | array | List of rules for traffic to bypass. |
+| [`certificateName`](#parameter-certificatename) | string | Name of the CA certificate. |
+| [`defaultWorkspaceId`](#parameter-defaultworkspaceid) | string | Default Log Analytics Resource ID for Firewall Policy Insights. |
+| [`enableProxy`](#parameter-enableproxy) | bool | Enable DNS Proxy on Firewalls attached to the Firewall Policy. |
+| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. |
+| [`fqdns`](#parameter-fqdns) | array | List of FQDNs for the ThreatIntel Allowlist. |
+| [`insightsIsEnabled`](#parameter-insightsisenabled) | bool | A flag to indicate if the insights are enabled on the policy. |
+| [`ipAddresses`](#parameter-ipaddresses) | array | List of IP addresses for the ThreatIntel Allowlist. |
+| [`keyVaultSecretId`](#parameter-keyvaultsecretid) | string | Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault. |
+| [`location`](#parameter-location) | string | Location for all resources. |
+| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. |
+| [`mode`](#parameter-mode) | string | The configuring of intrusion detection. |
+| [`privateRanges`](#parameter-privateranges) | array | List of private IP addresses/IP address ranges to not be SNAT. |
+| [`retentionDays`](#parameter-retentiondays) | int | Number of days the insights should be enabled on the policy. |
+| [`ruleCollectionGroups`](#parameter-rulecollectiongroups) | array | Rule collection groups. |
+| [`servers`](#parameter-servers) | array | List of Custom DNS Servers. |
+| [`signatureOverrides`](#parameter-signatureoverrides) | array | List of specific signatures states. |
+| [`tags`](#parameter-tags) | object | Tags of the Firewall policy resource. |
+| [`threatIntelMode`](#parameter-threatintelmode) | string | The operation mode for Threat Intel. |
+| [`tier`](#parameter-tier) | string | Tier of Firewall Policy. |
+| [`workspaces`](#parameter-workspaces) | array | List of workspaces for Firewall Policy Insights. |
+
+### Parameter: `name`
+
+Name of the Firewall Policy.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `allowSqlRedirect`
+
+A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999.
+
+- Required: No
+- Type: bool
+- Default: `False`
+
+### Parameter: `autoLearnPrivateRanges`
+
+The operation mode for automatically learning private ranges to not be SNAT.
+
+- Required: No
+- Type: string
+- Default: `'Disabled'`
+- Allowed:
+ ```Bicep
+ [
+ 'Disabled'
+ 'Enabled'
+ ]
+ ```
+
+### Parameter: `basePolicyResourceId`
+
+Resource ID of the base policy.
+
+- Required: No
+- Type: string
+
+### Parameter: `bypassTrafficSettings`
+
+List of rules for traffic to bypass.
+
+- Required: No
+- Type: array
+
+### Parameter: `certificateName`
+
+Name of the CA certificate.
+
+- Required: No
+- Type: string
+
+### Parameter: `defaultWorkspaceId`
+
+Default Log Analytics Resource ID for Firewall Policy Insights.
+
+- Required: No
+- Type: string
+
+### Parameter: `enableProxy`
+
+Enable DNS Proxy on Firewalls attached to the Firewall Policy.
+
+- Required: No
+- Type: bool
+- Default: `False`
+
+### Parameter: `enableTelemetry`
+
+Enable/Disable usage telemetry for module.
+
+- Required: No
+- Type: bool
+- Default: `True`
+
+### Parameter: `fqdns`
+
+List of FQDNs for the ThreatIntel Allowlist.
+
+- Required: No
+- Type: array
+
+### Parameter: `insightsIsEnabled`
+
+A flag to indicate if the insights are enabled on the policy.
+
+- Required: No
+- Type: bool
+- Default: `False`
+
+### Parameter: `ipAddresses`
+
+List of IP addresses for the ThreatIntel Allowlist.
+
+- Required: No
+- Type: array
+
+### Parameter: `keyVaultSecretId`
+
+Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault.
+
+- Required: No
+- Type: string
+
+### Parameter: `location`
+
+Location for all resources.
+
+- Required: No
+- Type: string
+- Default: `[resourceGroup().location]`
+
+### Parameter: `managedIdentities`
+
+The managed identity definition for this resource.
+
+- Required: No
+- Type: object
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. |
+
+### Parameter: `managedIdentities.userAssignedResourceIds`
+
+The resource ID(s) to assign to the resource.
+
+- Required: Yes
+- Type: array
+
+### Parameter: `mode`
+
+The configuring of intrusion detection.
+
+- Required: No
+- Type: string
+- Default: `'Off'`
+- Allowed:
+ ```Bicep
+ [
+ 'Alert'
+ 'Deny'
+ 'Off'
+ ]
+ ```
+
+### Parameter: `privateRanges`
+
+List of private IP addresses/IP address ranges to not be SNAT.
+
+- Required: No
+- Type: array
+- Default: `[]`
+
+### Parameter: `retentionDays`
+
+Number of days the insights should be enabled on the policy.
+
+- Required: No
+- Type: int
+- Default: `365`
+
+### Parameter: `ruleCollectionGroups`
+
+Rule collection groups.
+
+- Required: No
+- Type: array
+
+### Parameter: `servers`
+
+List of Custom DNS Servers.
+
+- Required: No
+- Type: array
+
+### Parameter: `signatureOverrides`
+
+List of specific signatures states.
+
+- Required: No
+- Type: array
+
+### Parameter: `tags`
+
+Tags of the Firewall policy resource.
+
+- Required: No
+- Type: object
+
+### Parameter: `threatIntelMode`
+
+The operation mode for Threat Intel.
+
+- Required: No
+- Type: string
+- Default: `'Off'`
+- Allowed:
+ ```Bicep
+ [
+ 'Alert'
+ 'Deny'
+ 'Off'
+ ]
+ ```
+
+### Parameter: `tier`
+
+Tier of Firewall Policy.
+
+- Required: No
+- Type: string
+- Default: `'Standard'`
+- Allowed:
+ ```Bicep
+ [
+ 'Premium'
+ 'Standard'
+ ]
+ ```
+
+### Parameter: `workspaces`
+
+List of workspaces for Firewall Policy Insights.
+
+- Required: No
+- Type: array
+
+
+## Outputs
+
+| Output | Type | Description |
+| :-- | :-- | :-- |
+| `location` | string | The location the resource was deployed into. |
+| `name` | string | The name of the deployed firewall policy. |
+| `resourceGroupName` | string | The resource group of the deployed firewall policy. |
+| `resourceId` | string | The resource ID of the deployed firewall policy. |
+
+## Cross-referenced modules
+
+_None_
+
+## Data Collection
+
+The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
diff --git a/avm/res/network/firewall-policy/main.bicep b/avm/res/network/firewall-policy/main.bicep
new file mode 100644
index 0000000000..3c2bb65442
--- /dev/null
+++ b/avm/res/network/firewall-policy/main.bicep
@@ -0,0 +1,212 @@
+metadata name = 'Firewall Policies'
+metadata description = 'This module deploys a Firewall Policy.'
+metadata owner = 'Azure/module-maintainers'
+
+@description('Required. Name of the Firewall Policy.')
+param name string
+
+@description('Optional. Location for all resources.')
+param location string = resourceGroup().location
+
+@description('Optional. Tags of the Firewall policy resource.')
+param tags object?
+
+@description('Optional. The managed identity definition for this resource.')
+param managedIdentities managedIdentitiesType
+
+@description('Optional. Resource ID of the base policy.')
+param basePolicyResourceId string?
+
+@description('Optional. Enable DNS Proxy on Firewalls attached to the Firewall Policy.')
+param enableProxy bool = false
+
+@description('Optional. List of Custom DNS Servers.')
+param servers array?
+
+@description('Optional. A flag to indicate if the insights are enabled on the policy.')
+param insightsIsEnabled bool = false
+
+@description('Optional. Default Log Analytics Resource ID for Firewall Policy Insights.')
+param defaultWorkspaceId string?
+
+@description('Optional. List of workspaces for Firewall Policy Insights.')
+param workspaces array?
+
+@description('Optional. Number of days the insights should be enabled on the policy.')
+param retentionDays int = 365
+
+@description('Optional. List of rules for traffic to bypass.')
+param bypassTrafficSettings array?
+
+@description('Optional. List of specific signatures states.')
+param signatureOverrides array?
+
+@description('Optional. The configuring of intrusion detection.')
+@allowed([
+ 'Alert'
+ 'Deny'
+ 'Off'
+])
+param mode string = 'Off'
+
+@description('Optional. Tier of Firewall Policy.')
+@allowed([
+ 'Premium'
+ 'Standard'
+])
+param tier string = 'Standard'
+
+@description('Optional. List of private IP addresses/IP address ranges to not be SNAT.')
+param privateRanges array = []
+
+@allowed([
+ 'Disabled'
+ 'Enabled'
+])
+@description('Optional. The operation mode for automatically learning private ranges to not be SNAT.')
+param autoLearnPrivateRanges string = 'Disabled'
+
+@description('Optional. The operation mode for Threat Intel.')
+@allowed([
+ 'Alert'
+ 'Deny'
+ 'Off'
+])
+param threatIntelMode string = 'Off'
+
+@description('Optional. A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999.')
+param allowSqlRedirect bool = false
+
+@description('Optional. List of FQDNs for the ThreatIntel Allowlist.')
+param fqdns array?
+
+@description('Optional. List of IP addresses for the ThreatIntel Allowlist.')
+param ipAddresses array?
+
+@description('Optional. Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault.')
+#disable-next-line secure-secrets-in-params // Not a secret
+param keyVaultSecretId string?
+
+@description('Optional. Name of the CA certificate.')
+param certificateName string?
+
+@description('Optional. Enable/Disable usage telemetry for module.')
+param enableTelemetry bool = true
+
+@description('Optional. Rule collection groups.')
+param ruleCollectionGroups array?
+
+var formattedUserAssignedIdentities = reduce(map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), {}, (cur, next) => union(cur, next)) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} }
+
+var identity = !empty(managedIdentities) ? {
+ type: 'UserAssigned'
+ userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null
+} : null
+
+resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) {
+ name: '46d3xbcp.res.network-firewallpolicy.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}'
+ properties: {
+ mode: 'Incremental'
+ template: {
+ '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
+ contentVersion: '1.0.0.0'
+ resources: []
+ outputs: {
+ telemetry: {
+ type: 'String'
+ value: 'For more information, see https://aka.ms/avm/TelemetryInfo'
+ }
+ }
+ }
+ }
+}
+
+resource firewallPolicy 'Microsoft.Network/firewallPolicies@2023-04-01' = {
+ name: name
+ location: location
+ tags: tags
+ identity: identity
+ properties: {
+ basePolicy: !empty(basePolicyResourceId ?? '') ? {
+ id: basePolicyResourceId
+ } : null
+ dnsSettings: enableProxy ? {
+ enableProxy: enableProxy
+ servers: servers ?? []
+ } : null
+ insights: insightsIsEnabled ? {
+ isEnabled: insightsIsEnabled
+ logAnalyticsResources: {
+ defaultWorkspaceId: {
+ id: defaultWorkspaceId
+ }
+ workspaces: workspaces
+ }
+ retentionDays: retentionDays
+ } : null
+ intrusionDetection: (mode != 'Off') ? {
+ configuration: {
+ bypassTrafficSettings: bypassTrafficSettings
+ signatureOverrides: signatureOverrides
+ }
+ mode: mode
+ } : null
+ sku: {
+ tier: tier
+ }
+ snat: !empty(privateRanges) ? {
+ autoLearnPrivateRanges: autoLearnPrivateRanges
+ privateRanges: privateRanges
+ } : null
+ sql: {
+ allowSqlRedirect: allowSqlRedirect
+ }
+ threatIntelMode: threatIntelMode
+ threatIntelWhitelist: {
+ fqdns: fqdns ?? []
+ ipAddresses: ipAddresses ?? []
+ }
+ transportSecurity: (!empty(keyVaultSecretId ?? []) || !empty(certificateName ?? '')) ? {
+ certificateAuthority: {
+ keyVaultSecretId: keyVaultSecretId
+ name: certificateName
+ }
+ } : null
+ }
+}
+
+// When a FW policy uses a base policy and have more rule collection groups,
+// they need to be deployed sequentially, otherwise the deployment would fail
+// because of concurrent access to the base policy.
+// The next line forces ARM to deploy them one after the other, so no race concition on the base policy will happen.
+@batchSize(1)
+module firewallPolicy_ruleCollectionGroups 'rule-collection-group/main.bicep' = [for (ruleCollectionGroup, index) in (ruleCollectionGroups ?? []): {
+ name: '${uniqueString(deployment().name, location)}-firewallPolicy_ruleCollectionGroups-${index}'
+ params: {
+ firewallPolicyName: firewallPolicy.name
+ name: ruleCollectionGroup.name
+ priority: ruleCollectionGroup.priority
+ ruleCollections: ruleCollectionGroup.ruleCollections
+ }
+}]
+
+@description('The name of the deployed firewall policy.')
+output name string = firewallPolicy.name
+
+@description('The resource ID of the deployed firewall policy.')
+output resourceId string = firewallPolicy.id
+
+@description('The resource group of the deployed firewall policy.')
+output resourceGroupName string = resourceGroup().name
+
+@description('The location the resource was deployed into.')
+output location string = firewallPolicy.location
+
+// =============== //
+// Definitions //
+// =============== //
+
+type managedIdentitiesType = {
+ @description('Optional. The resource ID(s) to assign to the resource.')
+ userAssignedResourceIds: string[]
+}?
diff --git a/avm/res/network/firewall-policy/main.json b/avm/res/network/firewall-policy/main.json
new file mode 100644
index 0000000000..cc430c6b10
--- /dev/null
+++ b/avm/res/network/firewall-policy/main.json
@@ -0,0 +1,427 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "languageVersion": "2.0",
+ "contentVersion": "1.0.0.0",
+ "metadata": {
+ "_generator": {
+ "name": "bicep",
+ "version": "0.23.1.45101",
+ "templateHash": "576890491523219712"
+ },
+ "name": "Firewall Policies",
+ "description": "This module deploys a Firewall Policy.",
+ "owner": "Azure/module-maintainers"
+ },
+ "definitions": {
+ "managedIdentitiesType": {
+ "type": "object",
+ "properties": {
+ "userAssignedResourceIds": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "metadata": {
+ "description": "Optional. The resource ID(s) to assign to the resource."
+ }
+ }
+ },
+ "nullable": true
+ }
+ },
+ "parameters": {
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "Required. Name of the Firewall Policy."
+ }
+ },
+ "location": {
+ "type": "string",
+ "defaultValue": "[resourceGroup().location]",
+ "metadata": {
+ "description": "Optional. Location for all resources."
+ }
+ },
+ "tags": {
+ "type": "object",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Tags of the Firewall policy resource."
+ }
+ },
+ "managedIdentities": {
+ "$ref": "#/definitions/managedIdentitiesType",
+ "metadata": {
+ "description": "Optional. The managed identity definition for this resource."
+ }
+ },
+ "basePolicyResourceId": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Resource ID of the base policy."
+ }
+ },
+ "enableProxy": {
+ "type": "bool",
+ "defaultValue": false,
+ "metadata": {
+ "description": "Optional. Enable DNS Proxy on Firewalls attached to the Firewall Policy."
+ }
+ },
+ "servers": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. List of Custom DNS Servers."
+ }
+ },
+ "insightsIsEnabled": {
+ "type": "bool",
+ "defaultValue": false,
+ "metadata": {
+ "description": "Optional. A flag to indicate if the insights are enabled on the policy."
+ }
+ },
+ "defaultWorkspaceId": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Default Log Analytics Resource ID for Firewall Policy Insights."
+ }
+ },
+ "workspaces": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. List of workspaces for Firewall Policy Insights."
+ }
+ },
+ "retentionDays": {
+ "type": "int",
+ "defaultValue": 365,
+ "metadata": {
+ "description": "Optional. Number of days the insights should be enabled on the policy."
+ }
+ },
+ "bypassTrafficSettings": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. List of rules for traffic to bypass."
+ }
+ },
+ "signatureOverrides": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. List of specific signatures states."
+ }
+ },
+ "mode": {
+ "type": "string",
+ "defaultValue": "Off",
+ "allowedValues": [
+ "Alert",
+ "Deny",
+ "Off"
+ ],
+ "metadata": {
+ "description": "Optional. The configuring of intrusion detection."
+ }
+ },
+ "tier": {
+ "type": "string",
+ "defaultValue": "Standard",
+ "allowedValues": [
+ "Premium",
+ "Standard"
+ ],
+ "metadata": {
+ "description": "Optional. Tier of Firewall Policy."
+ }
+ },
+ "privateRanges": {
+ "type": "array",
+ "defaultValue": [],
+ "metadata": {
+ "description": "Optional. List of private IP addresses/IP address ranges to not be SNAT."
+ }
+ },
+ "autoLearnPrivateRanges": {
+ "type": "string",
+ "defaultValue": "Disabled",
+ "allowedValues": [
+ "Disabled",
+ "Enabled"
+ ],
+ "metadata": {
+ "description": "Optional. The operation mode for automatically learning private ranges to not be SNAT."
+ }
+ },
+ "threatIntelMode": {
+ "type": "string",
+ "defaultValue": "Off",
+ "allowedValues": [
+ "Alert",
+ "Deny",
+ "Off"
+ ],
+ "metadata": {
+ "description": "Optional. The operation mode for Threat Intel."
+ }
+ },
+ "allowSqlRedirect": {
+ "type": "bool",
+ "defaultValue": false,
+ "metadata": {
+ "description": "Optional. A flag to indicate if SQL Redirect traffic filtering is enabled. Turning on the flag requires no rule using port 11000-11999."
+ }
+ },
+ "fqdns": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. List of FQDNs for the ThreatIntel Allowlist."
+ }
+ },
+ "ipAddresses": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. List of IP addresses for the ThreatIntel Allowlist."
+ }
+ },
+ "keyVaultSecretId": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Secret ID of (base-64 encoded unencrypted PFX) Secret or Certificate object stored in KeyVault."
+ }
+ },
+ "certificateName": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Name of the CA certificate."
+ }
+ },
+ "enableTelemetry": {
+ "type": "bool",
+ "defaultValue": true,
+ "metadata": {
+ "description": "Optional. Enable/Disable usage telemetry for module."
+ }
+ },
+ "ruleCollectionGroups": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Rule collection groups."
+ }
+ }
+ },
+ "variables": {
+ "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]",
+ "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', 'UserAssigned', 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]"
+ },
+ "resources": {
+ "avmTelemetry": {
+ "condition": "[parameters('enableTelemetry')]",
+ "type": "Microsoft.Resources/deployments",
+ "apiVersion": "2023-07-01",
+ "name": "[format('46d3xbcp.res.network-firewallpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]",
+ "properties": {
+ "mode": "Incremental",
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "resources": [],
+ "outputs": {
+ "telemetry": {
+ "type": "String",
+ "value": "For more information, see https://aka.ms/avm/TelemetryInfo"
+ }
+ }
+ }
+ }
+ },
+ "firewallPolicy": {
+ "type": "Microsoft.Network/firewallPolicies",
+ "apiVersion": "2023-04-01",
+ "name": "[parameters('name')]",
+ "location": "[parameters('location')]",
+ "tags": "[parameters('tags')]",
+ "identity": "[variables('identity')]",
+ "properties": {
+ "basePolicy": "[if(not(empty(coalesce(parameters('basePolicyResourceId'), ''))), createObject('id', parameters('basePolicyResourceId')), null())]",
+ "dnsSettings": "[if(parameters('enableProxy'), createObject('enableProxy', parameters('enableProxy'), 'servers', coalesce(parameters('servers'), createArray())), null())]",
+ "insights": "[if(parameters('insightsIsEnabled'), createObject('isEnabled', parameters('insightsIsEnabled'), 'logAnalyticsResources', createObject('defaultWorkspaceId', createObject('id', parameters('defaultWorkspaceId')), 'workspaces', parameters('workspaces')), 'retentionDays', parameters('retentionDays')), null())]",
+ "intrusionDetection": "[if(not(equals(parameters('mode'), 'Off')), createObject('configuration', createObject('bypassTrafficSettings', parameters('bypassTrafficSettings'), 'signatureOverrides', parameters('signatureOverrides')), 'mode', parameters('mode')), null())]",
+ "sku": {
+ "tier": "[parameters('tier')]"
+ },
+ "snat": "[if(not(empty(parameters('privateRanges'))), createObject('autoLearnPrivateRanges', parameters('autoLearnPrivateRanges'), 'privateRanges', parameters('privateRanges')), null())]",
+ "sql": {
+ "allowSqlRedirect": "[parameters('allowSqlRedirect')]"
+ },
+ "threatIntelMode": "[parameters('threatIntelMode')]",
+ "threatIntelWhitelist": {
+ "fqdns": "[coalesce(parameters('fqdns'), createArray())]",
+ "ipAddresses": "[coalesce(parameters('ipAddresses'), createArray())]"
+ },
+ "transportSecurity": "[if(or(not(empty(coalesce(parameters('keyVaultSecretId'), createArray()))), not(empty(coalesce(parameters('certificateName'), '')))), createObject('certificateAuthority', createObject('keyVaultSecretId', parameters('keyVaultSecretId'), 'name', parameters('certificateName'))), null())]"
+ }
+ },
+ "firewallPolicy_ruleCollectionGroups": {
+ "copy": {
+ "name": "firewallPolicy_ruleCollectionGroups",
+ "count": "[length(coalesce(parameters('ruleCollectionGroups'), createArray()))]",
+ "mode": "serial",
+ "batchSize": 1
+ },
+ "type": "Microsoft.Resources/deployments",
+ "apiVersion": "2022-09-01",
+ "name": "[format('{0}-firewallPolicy_ruleCollectionGroups-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]",
+ "properties": {
+ "expressionEvaluationOptions": {
+ "scope": "inner"
+ },
+ "mode": "Incremental",
+ "parameters": {
+ "firewallPolicyName": {
+ "value": "[parameters('name')]"
+ },
+ "name": {
+ "value": "[coalesce(parameters('ruleCollectionGroups'), createArray())[copyIndex()].name]"
+ },
+ "priority": {
+ "value": "[coalesce(parameters('ruleCollectionGroups'), createArray())[copyIndex()].priority]"
+ },
+ "ruleCollections": {
+ "value": "[coalesce(parameters('ruleCollectionGroups'), createArray())[copyIndex()].ruleCollections]"
+ }
+ },
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "languageVersion": "2.0",
+ "contentVersion": "1.0.0.0",
+ "metadata": {
+ "_generator": {
+ "name": "bicep",
+ "version": "0.23.1.45101",
+ "templateHash": "7306629689940419640"
+ },
+ "name": "Firewall Policy Rule Collection Groups",
+ "description": "This module deploys a Firewall Policy Rule Collection Group.",
+ "owner": "Azure/module-maintainers"
+ },
+ "parameters": {
+ "firewallPolicyName": {
+ "type": "string",
+ "metadata": {
+ "description": "Conditional. The name of the parent Firewall Policy. Required if the template is used in a standalone deployment."
+ }
+ },
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "Required. The name of the rule collection group to deploy."
+ }
+ },
+ "priority": {
+ "type": "int",
+ "metadata": {
+ "description": "Required. Priority of the Firewall Policy Rule Collection Group resource."
+ }
+ },
+ "ruleCollections": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Group of Firewall Policy rule collections."
+ }
+ }
+ },
+ "resources": {
+ "firewallPolicy": {
+ "existing": true,
+ "type": "Microsoft.Network/firewallPolicies",
+ "apiVersion": "2023-04-01",
+ "name": "[parameters('firewallPolicyName')]"
+ },
+ "ruleCollectionGroup": {
+ "type": "Microsoft.Network/firewallPolicies/ruleCollectionGroups",
+ "apiVersion": "2023-04-01",
+ "name": "[format('{0}/{1}', parameters('firewallPolicyName'), parameters('name'))]",
+ "properties": {
+ "priority": "[parameters('priority')]",
+ "ruleCollections": "[coalesce(parameters('ruleCollections'), createArray())]"
+ },
+ "dependsOn": [
+ "firewallPolicy"
+ ]
+ }
+ },
+ "outputs": {
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "The name of the deployed rule collection group."
+ },
+ "value": "[parameters('name')]"
+ },
+ "resourceId": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource ID of the deployed rule collection group."
+ },
+ "value": "[resourceId('Microsoft.Network/firewallPolicies/ruleCollectionGroups', parameters('firewallPolicyName'), parameters('name'))]"
+ },
+ "resourceGroupName": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource group of the deployed rule collection group."
+ },
+ "value": "[resourceGroup().name]"
+ }
+ }
+ }
+ },
+ "dependsOn": [
+ "firewallPolicy"
+ ]
+ }
+ },
+ "outputs": {
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "The name of the deployed firewall policy."
+ },
+ "value": "[parameters('name')]"
+ },
+ "resourceId": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource ID of the deployed firewall policy."
+ },
+ "value": "[resourceId('Microsoft.Network/firewallPolicies', parameters('name'))]"
+ },
+ "resourceGroupName": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource group of the deployed firewall policy."
+ },
+ "value": "[resourceGroup().name]"
+ },
+ "location": {
+ "type": "string",
+ "metadata": {
+ "description": "The location the resource was deployed into."
+ },
+ "value": "[reference('firewallPolicy', '2023-04-01', 'full').location]"
+ }
+ }
+}
\ No newline at end of file
diff --git a/avm/res/network/firewall-policy/rule-collection-group/README.md b/avm/res/network/firewall-policy/rule-collection-group/README.md
new file mode 100644
index 0000000000..985fee5162
--- /dev/null
+++ b/avm/res/network/firewall-policy/rule-collection-group/README.md
@@ -0,0 +1,83 @@
+# Firewall Policy Rule Collection Groups `[Microsoft.Network/firewallPolicies/ruleCollectionGroups]`
+
+This module deploys a Firewall Policy Rule Collection Group.
+
+## Navigation
+
+- [Resource Types](#Resource-Types)
+- [Parameters](#Parameters)
+- [Outputs](#Outputs)
+- [Cross-referenced modules](#Cross-referenced-modules)
+- [Data Collection](#Data-Collection)
+
+## Resource Types
+
+| Resource Type | API Version |
+| :-- | :-- |
+| `Microsoft.Network/firewallPolicies/ruleCollectionGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/firewallPolicies/ruleCollectionGroups) |
+
+## Parameters
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-name) | string | The name of the rule collection group to deploy. |
+| [`priority`](#parameter-priority) | int | Priority of the Firewall Policy Rule Collection Group resource. |
+
+**Conditional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`firewallPolicyName`](#parameter-firewallpolicyname) | string | The name of the parent Firewall Policy. Required if the template is used in a standalone deployment. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`ruleCollections`](#parameter-rulecollections) | array | Group of Firewall Policy rule collections. |
+
+### Parameter: `name`
+
+The name of the rule collection group to deploy.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `priority`
+
+Priority of the Firewall Policy Rule Collection Group resource.
+
+- Required: Yes
+- Type: int
+
+### Parameter: `firewallPolicyName`
+
+The name of the parent Firewall Policy. Required if the template is used in a standalone deployment.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `ruleCollections`
+
+Group of Firewall Policy rule collections.
+
+- Required: No
+- Type: array
+
+
+## Outputs
+
+| Output | Type | Description |
+| :-- | :-- | :-- |
+| `name` | string | The name of the deployed rule collection group. |
+| `resourceGroupName` | string | The resource group of the deployed rule collection group. |
+| `resourceId` | string | The resource ID of the deployed rule collection group. |
+
+## Cross-referenced modules
+
+_None_
+
+## Data Collection
+
+The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
diff --git a/avm/res/network/firewall-policy/rule-collection-group/main.bicep b/avm/res/network/firewall-policy/rule-collection-group/main.bicep
new file mode 100644
index 0000000000..451f0a3337
--- /dev/null
+++ b/avm/res/network/firewall-policy/rule-collection-group/main.bicep
@@ -0,0 +1,37 @@
+metadata name = 'Firewall Policy Rule Collection Groups'
+metadata description = 'This module deploys a Firewall Policy Rule Collection Group.'
+metadata owner = 'Azure/module-maintainers'
+
+@description('Conditional. The name of the parent Firewall Policy. Required if the template is used in a standalone deployment.')
+param firewallPolicyName string
+
+@description('Required. The name of the rule collection group to deploy.')
+param name string
+
+@description('Required. Priority of the Firewall Policy Rule Collection Group resource.')
+param priority int
+
+@description('Optional. Group of Firewall Policy rule collections.')
+param ruleCollections array?
+
+resource firewallPolicy 'Microsoft.Network/firewallPolicies@2023-04-01' existing = {
+ name: firewallPolicyName
+}
+
+resource ruleCollectionGroup 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2023-04-01' = {
+ name: name
+ parent: firewallPolicy
+ properties: {
+ priority: priority
+ ruleCollections: ruleCollections ?? []
+ }
+}
+
+@description('The name of the deployed rule collection group.')
+output name string = ruleCollectionGroup.name
+
+@description('The resource ID of the deployed rule collection group.')
+output resourceId string = ruleCollectionGroup.id
+
+@description('The resource group of the deployed rule collection group.')
+output resourceGroupName string = resourceGroup().name
diff --git a/avm/res/network/firewall-policy/rule-collection-group/main.json b/avm/res/network/firewall-policy/rule-collection-group/main.json
new file mode 100644
index 0000000000..fa05688bd6
--- /dev/null
+++ b/avm/res/network/firewall-policy/rule-collection-group/main.json
@@ -0,0 +1,85 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "languageVersion": "2.0",
+ "contentVersion": "1.0.0.0",
+ "metadata": {
+ "_generator": {
+ "name": "bicep",
+ "version": "0.23.1.45101",
+ "templateHash": "7306629689940419640"
+ },
+ "name": "Firewall Policy Rule Collection Groups",
+ "description": "This module deploys a Firewall Policy Rule Collection Group.",
+ "owner": "Azure/module-maintainers"
+ },
+ "parameters": {
+ "firewallPolicyName": {
+ "type": "string",
+ "metadata": {
+ "description": "Conditional. The name of the parent Firewall Policy. Required if the template is used in a standalone deployment."
+ }
+ },
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "Required. The name of the rule collection group to deploy."
+ }
+ },
+ "priority": {
+ "type": "int",
+ "metadata": {
+ "description": "Required. Priority of the Firewall Policy Rule Collection Group resource."
+ }
+ },
+ "ruleCollections": {
+ "type": "array",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Group of Firewall Policy rule collections."
+ }
+ }
+ },
+ "resources": {
+ "firewallPolicy": {
+ "existing": true,
+ "type": "Microsoft.Network/firewallPolicies",
+ "apiVersion": "2023-04-01",
+ "name": "[parameters('firewallPolicyName')]"
+ },
+ "ruleCollectionGroup": {
+ "type": "Microsoft.Network/firewallPolicies/ruleCollectionGroups",
+ "apiVersion": "2023-04-01",
+ "name": "[format('{0}/{1}', parameters('firewallPolicyName'), parameters('name'))]",
+ "properties": {
+ "priority": "[parameters('priority')]",
+ "ruleCollections": "[coalesce(parameters('ruleCollections'), createArray())]"
+ },
+ "dependsOn": [
+ "firewallPolicy"
+ ]
+ }
+ },
+ "outputs": {
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "The name of the deployed rule collection group."
+ },
+ "value": "[parameters('name')]"
+ },
+ "resourceId": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource ID of the deployed rule collection group."
+ },
+ "value": "[resourceId('Microsoft.Network/firewallPolicies/ruleCollectionGroups', parameters('firewallPolicyName'), parameters('name'))]"
+ },
+ "resourceGroupName": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource group of the deployed rule collection group."
+ },
+ "value": "[resourceGroup().name]"
+ }
+ }
+}
\ No newline at end of file
diff --git a/avm/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep b/avm/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep
new file mode 100644
index 0000000000..b7f696192f
--- /dev/null
+++ b/avm/res/network/firewall-policy/tests/e2e/defaults/main.test.bicep
@@ -0,0 +1,46 @@
+targetScope = 'subscription'
+
+metadata name = 'Using only defaults'
+metadata description = 'This instance deploys the module with the minimum set of required parameters.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'dep-${namePrefix}-network.firewallpolicies-${serviceShort}-rg'
+
+@description('Optional. The location to deploy resources to.')
+param location 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 = 'nfpmin'
+
+@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: location
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
+ params: {
+ name: '${namePrefix}${serviceShort}001'
+ location: location
+ }
+}]
diff --git a/avm/res/network/firewall-policy/tests/e2e/max/dependencies.bicep b/avm/res/network/firewall-policy/tests/e2e/max/dependencies.bicep
new file mode 100644
index 0000000000..4fa0028b8a
--- /dev/null
+++ b/avm/res/network/firewall-policy/tests/e2e/max/dependencies.bicep
@@ -0,0 +1,13 @@
+@description('Required. The name of the managed identity to create.')
+param managedIdentityName string
+
+@description('Optional. The location to deploy resources to.')
+param location string = resourceGroup().location
+
+resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
+ name: managedIdentityName
+ location: location
+}
+
+@description('The resource ID of the created Managed Identity.')
+output managedIdentityResourceId string = managedIdentity.id
diff --git a/avm/res/network/firewall-policy/tests/e2e/max/main.test.bicep b/avm/res/network/firewall-policy/tests/e2e/max/main.test.bicep
new file mode 100644
index 0000000000..ea6f60886d
--- /dev/null
+++ b/avm/res/network/firewall-policy/tests/e2e/max/main.test.bicep
@@ -0,0 +1,107 @@
+targetScope = 'subscription'
+
+metadata name = 'Using large parameter set'
+metadata description = 'This instance deploys the module with most of its features enabled.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'dep-${namePrefix}-network.firewallpolicies-${serviceShort}-rg'
+
+@description('Optional. The location to deploy resources to.')
+param location 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 = 'nfpmax'
+
+@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: location
+}
+
+module nestedDependencies 'dependencies.bicep' = {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-nestedDependencies'
+ params: {
+ managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
+ location: location
+ }
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
+ params: {
+ name: '${namePrefix}${serviceShort}001'
+ location: location
+ tier: 'Premium'
+ mode: 'Alert'
+ ruleCollectionGroups: [
+ {
+ name: '${namePrefix}-rule-001'
+ priority: 5000
+ ruleCollections: [
+ {
+ action: {
+ type: 'Allow'
+ }
+ name: 'collection002'
+ priority: 5555
+ ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
+ rules: [
+ {
+ destinationAddresses: [
+ '*'
+ ]
+ destinationFqdns: []
+ destinationIpGroups: []
+ destinationPorts: [
+ '80'
+ ]
+ ipProtocols: [
+ 'TCP'
+ 'UDP'
+ ]
+ name: 'rule002'
+ ruleType: 'NetworkRule'
+ sourceAddresses: [
+ '*'
+ ]
+ sourceIpGroups: []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ managedIdentities: {
+ userAssignedResourceIds: [
+ nestedDependencies.outputs.managedIdentityResourceId
+ ]
+ }
+ tags: {
+ 'hidden-title': 'This is visible in the resource name'
+ Environment: 'Non-Prod'
+ Role: 'DeploymentValidation'
+ }
+ allowSqlRedirect: true
+ autoLearnPrivateRanges: 'Enabled'
+ }
+}]
diff --git a/avm/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep
new file mode 100644
index 0000000000..5804989b7c
--- /dev/null
+++ b/avm/res/network/firewall-policy/tests/e2e/waf-aligned/main.test.bicep
@@ -0,0 +1,92 @@
+targetScope = 'subscription'
+
+metadata name = 'WAF-aligned'
+metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'dep-${namePrefix}-network.firewallpolicies-${serviceShort}-rg'
+
+@description('Optional. The location to deploy resources to.')
+param location 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 = 'nfpwaf'
+
+@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: location
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
+ params: {
+ name: '${namePrefix}${serviceShort}001'
+ location: location
+ ruleCollectionGroups: [
+ {
+ name: '${namePrefix}-rule-001'
+ priority: 5000
+ ruleCollections: [
+ {
+ action: {
+ type: 'Allow'
+ }
+ name: 'collection002'
+ priority: 5555
+ ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
+ rules: [
+ {
+ destinationAddresses: [
+ '*'
+ ]
+ destinationFqdns: []
+ destinationIpGroups: []
+ destinationPorts: [
+ '80'
+ ]
+ ipProtocols: [
+ 'TCP'
+ 'UDP'
+ ]
+ name: 'rule002'
+ ruleType: 'NetworkRule'
+ sourceAddresses: [
+ '*'
+ ]
+ sourceIpGroups: []
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ tags: {
+ 'hidden-title': 'This is visible in the resource name'
+ Environment: 'Non-Prod'
+ Role: 'DeploymentValidation'
+ }
+ allowSqlRedirect: true
+ autoLearnPrivateRanges: 'Enabled'
+ threatIntelMode: 'Deny'
+ }
+}]
diff --git a/avm/res/network/firewall-policy/version.json b/avm/res/network/firewall-policy/version.json
new file mode 100644
index 0000000000..83083db694
--- /dev/null
+++ b/avm/res/network/firewall-policy/version.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
+ "version": "0.1",
+ "pathFilters": [
+ "./main.json"
+ ]
+}
\ No newline at end of file
diff --git a/avm/res/network/front-door-web-application-firewall-policy/ORPHANED.md b/avm/res/network/front-door-web-application-firewall-policy/ORPHANED.md
new file mode 100644
index 0000000000..ef8fa911d2
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/ORPHANED.md
@@ -0,0 +1,4 @@
+⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️
+
+- Only security and bug fixes are being handled by the AVM core team at present.
+- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)!
\ No newline at end of file
diff --git a/avm/res/network/front-door-web-application-firewall-policy/README.md b/avm/res/network/front-door-web-application-firewall-policy/README.md
new file mode 100644
index 0000000000..cf4c6a7864
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/README.md
@@ -0,0 +1,802 @@
+# Front Door Web Application Firewall (WAF) Policies `[Microsoft.Network/FrontDoorWebApplicationFirewallPolicies]`
+
+> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️
+>
+> - Only security and bug fixes are being handled by the AVM core team at present.
+> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)!
+
+This module deploys a Front Door Web Application Firewall (WAF) Policy.
+
+## Navigation
+
+- [Resource Types](#Resource-Types)
+- [Usage examples](#Usage-examples)
+- [Parameters](#Parameters)
+- [Outputs](#Outputs)
+- [Cross-referenced modules](#Cross-referenced-modules)
+- [Data Collection](#Data-Collection)
+
+## Resource Types
+
+| Resource Type | API Version |
+| :-- | :-- |
+| `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.Network/FrontDoorWebApplicationFirewallPolicies` | [2022-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2022-05-01/FrontDoorWebApplicationFirewallPolicies) |
+
+## Usage examples
+
+The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository.
+
+>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order.
+
+>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/front-door-web-application-firewall-policy:`.
+
+- [Using only defaults](#example-1-using-only-defaults)
+- [Using large parameter set](#example-2-using-large-parameter-set)
+- [WAF-aligned](#example-3-waf-aligned)
+
+### Example 1: _Using only defaults_
+
+This instance deploys the module with the minimum set of required parameters.
+
+
+
+
+via Bicep module
+
+```bicep
+module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:' = {
+ name: '${uniqueString(deployment().name, location)}-test-nagwafpmin'
+ params: {
+ // Required parameters
+ name: 'nagwafpmin001'
+ // Non-required parameters
+ location: ''
+ }
+}
+```
+
+
+
+
+
+
+via JSON Parameter file
+
+```json
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ // Required parameters
+ "name": {
+ "value": "nagwafpmin001"
+ },
+ // Non-required parameters
+ "location": {
+ "value": ""
+ }
+ }
+}
+```
+
+
+
+
+### Example 2: _Using large parameter set_
+
+This instance deploys the module with most of its features enabled.
+
+
+
+
+via Bicep module
+
+```bicep
+module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:' = {
+ name: '${uniqueString(deployment().name, location)}-test-nagwafpmax'
+ params: {
+ // Required parameters
+ name: 'nagwafpmax001'
+ // Non-required parameters
+ customRules: {
+ rules: [
+ {
+ action: 'Block'
+ enabledState: 'Enabled'
+ matchConditions: [
+ {
+ matchValue: [
+ 'CH'
+ ]
+ matchVariable: 'RemoteAddr'
+ negateCondition: false
+ operator: 'GeoMatch'
+ selector: ''
+ transforms: []
+ }
+ {
+ matchValue: [
+ 'windows'
+ ]
+ matchVariable: 'RequestHeader'
+ negateCondition: false
+ operator: 'Contains'
+ selector: 'UserAgent'
+ transforms: []
+ }
+ {
+ matchValue: [
+ '?>'
+ ''
+ lock: {
+ kind: 'CanNotDelete'
+ name: 'myCustomLockName'
+ }
+ managedRules: {
+ managedRuleSets: [
+ {
+ ruleSetType: 'Microsoft_BotManagerRuleSet'
+ ruleSetVersion: '1.0'
+ }
+ ]
+ }
+ policySettings: {
+ customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg=='
+ customBlockResponseStatusCode: 200
+ mode: 'Prevention'
+ redirectUrl: 'http://www.bing.com'
+ }
+ roleAssignments: [
+ {
+ principalId: ''
+ principalType: 'ServicePrincipal'
+ roleDefinitionIdOrName: 'Owner'
+ }
+ {
+ principalId: ''
+ principalType: 'ServicePrincipal'
+ roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
+ }
+ {
+ principalId: ''
+ principalType: 'ServicePrincipal'
+ roleDefinitionIdOrName: ''
+ }
+ ]
+ sku: 'Premium_AzureFrontDoor'
+ tags: {
+ Environment: 'Non-Prod'
+ 'hidden-title': 'This is visible in the resource name'
+ Role: 'DeploymentValidation'
+ }
+ }
+}
+```
+
+
+
+
+
+
+via JSON Parameter file
+
+```json
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ // Required parameters
+ "name": {
+ "value": "nagwafpmax001"
+ },
+ // Non-required parameters
+ "customRules": {
+ "value": {
+ "rules": [
+ {
+ "action": "Block",
+ "enabledState": "Enabled",
+ "matchConditions": [
+ {
+ "matchValue": [
+ "CH"
+ ],
+ "matchVariable": "RemoteAddr",
+ "negateCondition": false,
+ "operator": "GeoMatch",
+ "selector": "",
+ "transforms": []
+ },
+ {
+ "matchValue": [
+ "windows"
+ ],
+ "matchVariable": "RequestHeader",
+ "negateCondition": false,
+ "operator": "Contains",
+ "selector": "UserAgent",
+ "transforms": []
+ },
+ {
+ "matchValue": [
+ "?>",
+ ""
+ },
+ "lock": {
+ "value": {
+ "kind": "CanNotDelete",
+ "name": "myCustomLockName"
+ }
+ },
+ "managedRules": {
+ "value": {
+ "managedRuleSets": [
+ {
+ "ruleSetType": "Microsoft_BotManagerRuleSet",
+ "ruleSetVersion": "1.0"
+ }
+ ]
+ }
+ },
+ "policySettings": {
+ "value": {
+ "customBlockResponseBody": "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==",
+ "customBlockResponseStatusCode": 200,
+ "mode": "Prevention",
+ "redirectUrl": "http://www.bing.com"
+ }
+ },
+ "roleAssignments": {
+ "value": [
+ {
+ "principalId": "",
+ "principalType": "ServicePrincipal",
+ "roleDefinitionIdOrName": "Owner"
+ },
+ {
+ "principalId": "",
+ "principalType": "ServicePrincipal",
+ "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c"
+ },
+ {
+ "principalId": "",
+ "principalType": "ServicePrincipal",
+ "roleDefinitionIdOrName": ""
+ }
+ ]
+ },
+ "sku": {
+ "value": "Premium_AzureFrontDoor"
+ },
+ "tags": {
+ "value": {
+ "Environment": "Non-Prod",
+ "hidden-title": "This is visible in the resource name",
+ "Role": "DeploymentValidation"
+ }
+ }
+ }
+}
+```
+
+
+
+
+### Example 3: _WAF-aligned_
+
+This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.
+
+
+
+
+via Bicep module
+
+```bicep
+module frontDoorWebApplicationFirewallPolicy 'br/public:avm/res/network/front-door-web-application-firewall-policy:' = {
+ name: '${uniqueString(deployment().name, location)}-test-nagwafpwaf'
+ params: {
+ // Required parameters
+ name: 'nagwafpwaf001'
+ // Non-required parameters
+ customRules: {
+ rules: [
+ {
+ action: 'Block'
+ enabledState: 'Enabled'
+ matchConditions: [
+ {
+ matchValue: [
+ 'CH'
+ ]
+ matchVariable: 'RemoteAddr'
+ negateCondition: false
+ operator: 'GeoMatch'
+ selector: ''
+ transforms: []
+ }
+ {
+ matchValue: [
+ 'windows'
+ ]
+ matchVariable: 'RequestHeader'
+ negateCondition: false
+ operator: 'Contains'
+ selector: 'UserAgent'
+ transforms: []
+ }
+ {
+ matchValue: [
+ '?>'
+ ''
+ managedRules: {
+ managedRuleSets: [
+ {
+ ruleSetType: 'Microsoft_BotManagerRuleSet'
+ ruleSetVersion: '1.0'
+ }
+ ]
+ }
+ policySettings: {
+ customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg=='
+ customBlockResponseStatusCode: 200
+ mode: 'Prevention'
+ redirectUrl: 'http://www.bing.com'
+ }
+ sku: 'Premium_AzureFrontDoor'
+ tags: {
+ Environment: 'Non-Prod'
+ 'hidden-title': 'This is visible in the resource name'
+ Role: 'DeploymentValidation'
+ }
+ }
+}
+```
+
+
+
+
+
+
+via JSON Parameter file
+
+```json
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ // Required parameters
+ "name": {
+ "value": "nagwafpwaf001"
+ },
+ // Non-required parameters
+ "customRules": {
+ "value": {
+ "rules": [
+ {
+ "action": "Block",
+ "enabledState": "Enabled",
+ "matchConditions": [
+ {
+ "matchValue": [
+ "CH"
+ ],
+ "matchVariable": "RemoteAddr",
+ "negateCondition": false,
+ "operator": "GeoMatch",
+ "selector": "",
+ "transforms": []
+ },
+ {
+ "matchValue": [
+ "windows"
+ ],
+ "matchVariable": "RequestHeader",
+ "negateCondition": false,
+ "operator": "Contains",
+ "selector": "UserAgent",
+ "transforms": []
+ },
+ {
+ "matchValue": [
+ "?>",
+ ""
+ },
+ "managedRules": {
+ "value": {
+ "managedRuleSets": [
+ {
+ "ruleSetType": "Microsoft_BotManagerRuleSet",
+ "ruleSetVersion": "1.0"
+ }
+ ]
+ }
+ },
+ "policySettings": {
+ "value": {
+ "customBlockResponseBody": "PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg==",
+ "customBlockResponseStatusCode": 200,
+ "mode": "Prevention",
+ "redirectUrl": "http://www.bing.com"
+ }
+ },
+ "sku": {
+ "value": "Premium_AzureFrontDoor"
+ },
+ "tags": {
+ "value": {
+ "Environment": "Non-Prod",
+ "hidden-title": "This is visible in the resource name",
+ "Role": "DeploymentValidation"
+ }
+ }
+ }
+}
+```
+
+
+
+
+
+## Parameters
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`name`](#parameter-name) | string | Name of the Front Door WAF policy. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`customRules`](#parameter-customrules) | object | The custom rules inside the policy. |
+| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. |
+| [`location`](#parameter-location) | string | Location for all resources. |
+| [`lock`](#parameter-lock) | object | The lock settings of the service. |
+| [`managedRules`](#parameter-managedrules) | object | Describes the managedRules structure. |
+| [`policySettings`](#parameter-policysettings) | object | The PolicySettings for policy. |
+| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
+| [`sku`](#parameter-sku) | string | The pricing tier of the WAF profile. |
+| [`tags`](#parameter-tags) | object | Resource tags. |
+
+### Parameter: `name`
+
+Name of the Front Door WAF policy.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `customRules`
+
+The custom rules inside the policy.
+
+- Required: No
+- Type: object
+- Default:
+ ```Bicep
+ {
+ rules: [
+ {
+ action: 'Block'
+ enabledState: 'Enabled'
+ matchConditions: [
+ {
+ matchValue: [
+ 'ZZ'
+ ]
+ matchVariable: 'RemoteAddr'
+ negateCondition: true
+ operator: 'GeoMatch'
+ }
+ ]
+ name: 'ApplyGeoFilter'
+ priority: 100
+ ruleType: 'MatchRule'
+ }
+ ]
+ }
+ ```
+
+### Parameter: `enableTelemetry`
+
+Enable/Disable usage telemetry for module.
+
+- Required: No
+- Type: bool
+- Default: `True`
+
+### Parameter: `location`
+
+Location for all resources.
+
+- Required: No
+- Type: string
+- Default: `'global'`
+
+### Parameter: `lock`
+
+The lock settings of the service.
+
+- Required: No
+- Type: object
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`kind`](#parameter-lockkind) | string | Specify the type of lock. |
+| [`name`](#parameter-lockname) | string | Specify the name of lock. |
+
+### Parameter: `lock.kind`
+
+Specify the type of lock.
+
+- Required: No
+- Type: string
+- Allowed:
+ ```Bicep
+ [
+ 'CanNotDelete'
+ 'None'
+ 'ReadOnly'
+ ]
+ ```
+
+### Parameter: `lock.name`
+
+Specify the name of lock.
+
+- Required: No
+- Type: string
+
+### Parameter: `managedRules`
+
+Describes the managedRules structure.
+
+- Required: No
+- Type: object
+- Default:
+ ```Bicep
+ {
+ managedRuleSets: [
+ {
+ exclusions: []
+ ruleGroupOverrides: []
+ ruleSetAction: 'Block'
+ ruleSetType: 'Microsoft_DefaultRuleSet'
+ ruleSetVersion: '2.1'
+ }
+ {
+ exclusions: []
+ ruleGroupOverrides: []
+ ruleSetType: 'Microsoft_BotManagerRuleSet'
+ ruleSetVersion: '1.0'
+ }
+ ]
+ }
+ ```
+
+### Parameter: `policySettings`
+
+The PolicySettings for policy.
+
+- Required: No
+- Type: object
+- Default:
+ ```Bicep
+ {
+ enabledState: 'Enabled'
+ mode: 'Prevention'
+ }
+ ```
+
+### Parameter: `roleAssignments`
+
+Array of role assignments to create.
+
+- Required: No
+- Type: array
+
+**Required parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. |
+| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. |
+
+**Optional parameters**
+
+| Parameter | Type | Description |
+| :-- | :-- | :-- |
+| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". |
+| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. |
+| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. |
+| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. |
+| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. |
+
+### Parameter: `roleAssignments.principalId`
+
+The principal ID of the principal (user/group/identity) to assign the role to.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `roleAssignments.roleDefinitionIdOrName`
+
+The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'.
+
+- Required: Yes
+- Type: string
+
+### Parameter: `roleAssignments.condition`
+
+The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".
+
+- Required: No
+- Type: string
+
+### Parameter: `roleAssignments.conditionVersion`
+
+Version of the condition.
+
+- Required: No
+- Type: string
+- Allowed:
+ ```Bicep
+ [
+ '2.0'
+ ]
+ ```
+
+### Parameter: `roleAssignments.delegatedManagedIdentityResourceId`
+
+The Resource Id of the delegated managed identity resource.
+
+- Required: No
+- Type: string
+
+### Parameter: `roleAssignments.description`
+
+The description of the role assignment.
+
+- Required: No
+- Type: string
+
+### Parameter: `roleAssignments.principalType`
+
+The principal type of the assigned principal ID.
+
+- Required: No
+- Type: string
+- Allowed:
+ ```Bicep
+ [
+ 'Device'
+ 'ForeignGroup'
+ 'Group'
+ 'ServicePrincipal'
+ 'User'
+ ]
+ ```
+
+### Parameter: `sku`
+
+The pricing tier of the WAF profile.
+
+- Required: No
+- Type: string
+- Default: `'Standard_AzureFrontDoor'`
+- Allowed:
+ ```Bicep
+ [
+ 'Premium_AzureFrontDoor'
+ 'Standard_AzureFrontDoor'
+ ]
+ ```
+
+### Parameter: `tags`
+
+Resource tags.
+
+- Required: No
+- Type: object
+
+
+## Outputs
+
+| Output | Type | Description |
+| :-- | :-- | :-- |
+| `location` | string | The location the resource was deployed into. |
+| `name` | string | The name of the Front Door WAF policy. |
+| `resourceGroupName` | string | The resource group the Front Door WAF policy was deployed into. |
+| `resourceId` | string | The resource ID of the Front Door WAF policy. |
+
+## Cross-referenced modules
+
+_None_
+
+## Data Collection
+
+The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.
diff --git a/avm/res/network/front-door-web-application-firewall-policy/main.bicep b/avm/res/network/front-door-web-application-firewall-policy/main.bicep
new file mode 100644
index 0000000000..d49e672750
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/main.bicep
@@ -0,0 +1,186 @@
+metadata name = 'Front Door Web Application Firewall (WAF) Policies'
+metadata description = 'This module deploys a Front Door Web Application Firewall (WAF) Policy.'
+metadata owner = 'Azure/module-maintainers'
+
+@description('Required. Name of the Front Door WAF policy.')
+@minLength(1)
+@maxLength(128)
+param name string
+
+@description('Optional. Location for all resources.')
+param location string = 'global'
+
+@allowed([
+ 'Standard_AzureFrontDoor'
+ 'Premium_AzureFrontDoor'
+])
+@description('Optional. The pricing tier of the WAF profile.')
+param sku string = 'Standard_AzureFrontDoor'
+
+@description('Optional. Resource tags.')
+param tags object?
+
+@description('Optional. Enable/Disable usage telemetry for module.')
+param enableTelemetry bool = true
+
+@description('Optional. Describes the managedRules structure.')
+param managedRules object = {
+ managedRuleSets: [
+ {
+ ruleSetType: 'Microsoft_DefaultRuleSet'
+ ruleSetVersion: '2.1'
+ ruleGroupOverrides: []
+ exclusions: []
+ ruleSetAction: 'Block'
+ }
+ {
+ ruleSetType: 'Microsoft_BotManagerRuleSet'
+ ruleSetVersion: '1.0'
+ ruleGroupOverrides: []
+ exclusions: []
+ }
+ ]
+}
+
+@description('Optional. The custom rules inside the policy.')
+param customRules object = {
+ rules: [
+ {
+ name: 'ApplyGeoFilter'
+ priority: 100
+ enabledState: 'Enabled'
+ ruleType: 'MatchRule'
+ action: 'Block'
+ matchConditions: [
+ {
+ matchVariable: 'RemoteAddr'
+ operator: 'GeoMatch'
+ negateCondition: true
+ matchValue: [ 'ZZ' ]
+ }
+ ]
+ }
+ ]
+}
+
+@description('Optional. The PolicySettings for policy.')
+param policySettings object = {
+ enabledState: 'Enabled'
+ mode: 'Prevention'
+}
+
+@description('Optional. The lock settings of the service.')
+param lock lockType
+
+@description('Optional. Array of role assignments to create.')
+param roleAssignments roleAssignmentType
+
+var builtInRoleNames = {
+ Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
+ Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')
+ 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')
+ 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')
+}
+
+resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = if (enableTelemetry) {
+ name: '46d3xbcp.network-frontdoorwebappfirewallpolicy.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}'
+ properties: {
+ mode: 'Incremental'
+ template: {
+ '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#'
+ contentVersion: '1.0.0.0'
+ resources: []
+ outputs: {
+ telemetry: {
+ type: 'String'
+ value: 'For more information, see https://aka.ms/avm/TelemetryInfo'
+ }
+ }
+ }
+ }
+}
+
+resource frontDoorWAFPolicy 'Microsoft.Network/FrontDoorWebApplicationFirewallPolicies@2022-05-01' = {
+ name: name
+ location: location
+ sku: {
+ name: sku
+ }
+ tags: tags
+ properties: {
+ customRules: customRules
+ managedRules: sku == 'Premium_AzureFrontDoor' ? managedRules : { managedRuleSets: [] }
+ policySettings: policySettings
+ }
+}
+
+resource frontDoorWAFPolicy_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') {
+ name: lock.?name ?? 'lock-${name}'
+ properties: {
+ level: lock.?kind ?? ''
+ notes: lock.?kind == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot delete or modify the resource or child resources.'
+ }
+ scope: frontDoorWAFPolicy
+}
+
+resource frontDoorWAFPolicy_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [for (roleAssignment, index) in (roleAssignments ?? []): {
+ name: guid(frontDoorWAFPolicy.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName)
+ properties: {
+ roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') ? roleAssignment.roleDefinitionIdOrName : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)
+ principalId: roleAssignment.principalId
+ description: roleAssignment.?description
+ principalType: roleAssignment.?principalType
+ condition: roleAssignment.?condition
+ conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set
+ delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId
+ }
+ scope: frontDoorWAFPolicy
+}]
+
+@description('The name of the Front Door WAF policy.')
+output name string = frontDoorWAFPolicy.name
+
+@description('The resource ID of the Front Door WAF policy.')
+output resourceId string = frontDoorWAFPolicy.id
+
+@description('The resource group the Front Door WAF policy was deployed into.')
+output resourceGroupName string = resourceGroup().name
+
+@description('The location the resource was deployed into.')
+output location string = frontDoorWAFPolicy.location
+
+// =============== //
+// Definitions //
+// =============== //
+
+type lockType = {
+ @description('Optional. Specify the name of lock.')
+ name: string?
+
+ @description('Optional. Specify the type of lock.')
+ kind: ('CanNotDelete' | 'ReadOnly' | 'None')?
+}?
+
+type roleAssignmentType = {
+ @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.')
+ roleDefinitionIdOrName: string
+
+ @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.')
+ principalId: string
+
+ @description('Optional. The principal type of the assigned principal ID.')
+ principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')?
+
+ @description('Optional. The description of the role assignment.')
+ description: string?
+
+ @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".')
+ condition: string?
+
+ @description('Optional. Version of the condition.')
+ conditionVersion: '2.0'?
+
+ @description('Optional. The Resource Id of the delegated managed identity resource.')
+ delegatedManagedIdentityResourceId: string?
+}[]?
diff --git a/avm/res/network/front-door-web-application-firewall-policy/main.json b/avm/res/network/front-door-web-application-firewall-policy/main.json
new file mode 100644
index 0000000000..4ff87e228d
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/main.json
@@ -0,0 +1,334 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "languageVersion": "2.0",
+ "contentVersion": "1.0.0.0",
+ "metadata": {
+ "_generator": {
+ "name": "bicep",
+ "version": "0.23.1.45101",
+ "templateHash": "15621879470526271545"
+ },
+ "name": "Front Door Web Application Firewall (WAF) Policies",
+ "description": "This module deploys a Front Door Web Application Firewall (WAF) Policy.",
+ "owner": "Azure/module-maintainers"
+ },
+ "definitions": {
+ "lockType": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Specify the name of lock."
+ }
+ },
+ "kind": {
+ "type": "string",
+ "allowedValues": [
+ "CanNotDelete",
+ "None",
+ "ReadOnly"
+ ],
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Specify the type of lock."
+ }
+ }
+ },
+ "nullable": true
+ },
+ "roleAssignmentType": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "roleDefinitionIdOrName": {
+ "type": "string",
+ "metadata": {
+ "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'."
+ }
+ },
+ "principalId": {
+ "type": "string",
+ "metadata": {
+ "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to."
+ }
+ },
+ "principalType": {
+ "type": "string",
+ "allowedValues": [
+ "Device",
+ "ForeignGroup",
+ "Group",
+ "ServicePrincipal",
+ "User"
+ ],
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. The principal type of the assigned principal ID."
+ }
+ },
+ "description": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. The description of the role assignment."
+ }
+ },
+ "condition": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"."
+ }
+ },
+ "conditionVersion": {
+ "type": "string",
+ "allowedValues": [
+ "2.0"
+ ],
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Version of the condition."
+ }
+ },
+ "delegatedManagedIdentityResourceId": {
+ "type": "string",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. The Resource Id of the delegated managed identity resource."
+ }
+ }
+ }
+ },
+ "nullable": true
+ }
+ },
+ "parameters": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 128,
+ "metadata": {
+ "description": "Required. Name of the Front Door WAF policy."
+ }
+ },
+ "location": {
+ "type": "string",
+ "defaultValue": "global",
+ "metadata": {
+ "description": "Optional. Location for all resources."
+ }
+ },
+ "sku": {
+ "type": "string",
+ "defaultValue": "Standard_AzureFrontDoor",
+ "allowedValues": [
+ "Standard_AzureFrontDoor",
+ "Premium_AzureFrontDoor"
+ ],
+ "metadata": {
+ "description": "Optional. The pricing tier of the WAF profile."
+ }
+ },
+ "tags": {
+ "type": "object",
+ "nullable": true,
+ "metadata": {
+ "description": "Optional. Resource tags."
+ }
+ },
+ "enableTelemetry": {
+ "type": "bool",
+ "defaultValue": true,
+ "metadata": {
+ "description": "Optional. Enable/Disable usage telemetry for module."
+ }
+ },
+ "managedRules": {
+ "type": "object",
+ "defaultValue": {
+ "managedRuleSets": [
+ {
+ "ruleSetType": "Microsoft_DefaultRuleSet",
+ "ruleSetVersion": "2.1",
+ "ruleGroupOverrides": [],
+ "exclusions": [],
+ "ruleSetAction": "Block"
+ },
+ {
+ "ruleSetType": "Microsoft_BotManagerRuleSet",
+ "ruleSetVersion": "1.0",
+ "ruleGroupOverrides": [],
+ "exclusions": []
+ }
+ ]
+ },
+ "metadata": {
+ "description": "Optional. Describes the managedRules structure."
+ }
+ },
+ "customRules": {
+ "type": "object",
+ "defaultValue": {
+ "rules": [
+ {
+ "name": "ApplyGeoFilter",
+ "priority": 100,
+ "enabledState": "Enabled",
+ "ruleType": "MatchRule",
+ "action": "Block",
+ "matchConditions": [
+ {
+ "matchVariable": "RemoteAddr",
+ "operator": "GeoMatch",
+ "negateCondition": true,
+ "matchValue": [
+ "ZZ"
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ "metadata": {
+ "description": "Optional. The custom rules inside the policy."
+ }
+ },
+ "policySettings": {
+ "type": "object",
+ "defaultValue": {
+ "enabledState": "Enabled",
+ "mode": "Prevention"
+ },
+ "metadata": {
+ "description": "Optional. The PolicySettings for policy."
+ }
+ },
+ "lock": {
+ "$ref": "#/definitions/lockType",
+ "metadata": {
+ "description": "Optional. The lock settings of the service."
+ }
+ },
+ "roleAssignments": {
+ "$ref": "#/definitions/roleAssignmentType",
+ "metadata": {
+ "description": "Optional. Array of role assignments to create."
+ }
+ }
+ },
+ "variables": {
+ "builtInRoleNames": {
+ "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
+ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
+ "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')]",
+ "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]"
+ }
+ },
+ "resources": {
+ "avmTelemetry": {
+ "condition": "[parameters('enableTelemetry')]",
+ "type": "Microsoft.Resources/deployments",
+ "apiVersion": "2023-07-01",
+ "name": "[format('46d3xbcp.network-frontdoorwebappfirewallpolicy.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]",
+ "properties": {
+ "mode": "Incremental",
+ "template": {
+ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "resources": [],
+ "outputs": {
+ "telemetry": {
+ "type": "String",
+ "value": "For more information, see https://aka.ms/avm/TelemetryInfo"
+ }
+ }
+ }
+ }
+ },
+ "frontDoorWAFPolicy": {
+ "type": "Microsoft.Network/FrontDoorWebApplicationFirewallPolicies",
+ "apiVersion": "2022-05-01",
+ "name": "[parameters('name')]",
+ "location": "[parameters('location')]",
+ "sku": {
+ "name": "[parameters('sku')]"
+ },
+ "tags": "[parameters('tags')]",
+ "properties": {
+ "customRules": "[parameters('customRules')]",
+ "managedRules": "[if(equals(parameters('sku'), 'Premium_AzureFrontDoor'), parameters('managedRules'), createObject('managedRuleSets', createArray()))]",
+ "policySettings": "[parameters('policySettings')]"
+ }
+ },
+ "frontDoorWAFPolicy_lock": {
+ "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]",
+ "type": "Microsoft.Authorization/locks",
+ "apiVersion": "2020-05-01",
+ "scope": "[format('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/{0}', parameters('name'))]",
+ "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]",
+ "properties": {
+ "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]",
+ "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]"
+ },
+ "dependsOn": [
+ "frontDoorWAFPolicy"
+ ]
+ },
+ "frontDoorWAFPolicy_roleAssignments": {
+ "copy": {
+ "name": "frontDoorWAFPolicy_roleAssignments",
+ "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]"
+ },
+ "type": "Microsoft.Authorization/roleAssignments",
+ "apiVersion": "2022-04-01",
+ "scope": "[format('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies/{0}', parameters('name'))]",
+ "name": "[guid(resourceId('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]",
+ "properties": {
+ "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]",
+ "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]",
+ "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]",
+ "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]",
+ "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]",
+ "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]",
+ "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]"
+ },
+ "dependsOn": [
+ "frontDoorWAFPolicy"
+ ]
+ }
+ },
+ "outputs": {
+ "name": {
+ "type": "string",
+ "metadata": {
+ "description": "The name of the Front Door WAF policy."
+ },
+ "value": "[parameters('name')]"
+ },
+ "resourceId": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource ID of the Front Door WAF policy."
+ },
+ "value": "[resourceId('Microsoft.Network/FrontDoorWebApplicationFirewallPolicies', parameters('name'))]"
+ },
+ "resourceGroupName": {
+ "type": "string",
+ "metadata": {
+ "description": "The resource group the Front Door WAF policy was deployed into."
+ },
+ "value": "[resourceGroup().name]"
+ },
+ "location": {
+ "type": "string",
+ "metadata": {
+ "description": "The location the resource was deployed into."
+ },
+ "value": "[reference('frontDoorWAFPolicy', '2022-05-01', 'full').location]"
+ }
+ }
+}
\ No newline at end of file
diff --git a/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep
new file mode 100644
index 0000000000..a2a8bcddd1
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/defaults/main.test.bicep
@@ -0,0 +1,46 @@
+targetScope = 'subscription'
+
+metadata name = 'Using only defaults'
+metadata description = 'This instance deploys the module with the minimum set of required parameters.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'dep-${namePrefix}-network.frontdoorWebApplicationFirewallPolicies-${serviceShort}-rg'
+
+@description('Optional. The location to deploy resources to.')
+param location 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 = 'nagwafpmin'
+
+@description('Optional. A token to inject into the name of each resource.')
+param namePrefix string = '#_namePrefix_#'
+
+// ============ //
+// Dependencies //
+// ============ //
+
+// General resources
+// =================
+resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = {
+ name: resourceGroupName
+ location: location
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
+ params: {
+ name: '${namePrefix}${serviceShort}001'
+ location: location
+ }
+}]
diff --git a/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep
new file mode 100644
index 0000000000..7b3d4e8fb0
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/max/dependencies.bicep
@@ -0,0 +1,13 @@
+@description('Optional. The location to deploy to.')
+param location string = resourceGroup().location
+
+@description('Required. The name of the Managed Identity to create.')
+param managedIdentityName string
+
+resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
+ name: managedIdentityName
+ location: location
+}
+
+@description('The principal ID of the created Managed Identity.')
+output managedIdentityPrincipalId string = managedIdentity.properties.principalId
diff --git a/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep
new file mode 100644
index 0000000000..a952e91e69
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/max/main.test.bicep
@@ -0,0 +1,144 @@
+targetScope = 'subscription'
+
+metadata name = 'Using large parameter set'
+metadata description = 'This instance deploys the module with most of its features enabled.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'dep-${namePrefix}-network.frontdoorWebApplicationFirewallPolicies-${serviceShort}-rg'
+
+@description('Optional. The location to deploy resources to.')
+param location 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 = 'nagwafpmax'
+
+@description('Optional. A token to inject into the name of each resource.')
+param namePrefix string = '#_namePrefix_#'
+
+// ============ //
+// Dependencies //
+// ============ //
+
+// General resources
+// =================
+resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = {
+ name: resourceGroupName
+ location: location
+}
+
+module nestedDependencies 'dependencies.bicep' = {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-nestedDependencies'
+ params: {
+ managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}'
+ location: location
+ }
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
+ params: {
+ name: '${namePrefix}${serviceShort}001'
+ location: location
+ lock: {
+ kind: 'CanNotDelete'
+ name: 'myCustomLockName'
+ }
+ sku: 'Premium_AzureFrontDoor'
+ policySettings: {
+ mode: 'Prevention'
+ redirectUrl: 'http://www.bing.com'
+ customBlockResponseStatusCode: 200
+ customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg=='
+ }
+ customRules: {
+ rules: [
+ {
+ name: 'CustomRule1'
+ priority: 2
+ enabledState: 'Enabled'
+ action: 'Block'
+ ruleType: 'MatchRule'
+ rateLimitDurationInMinutes: 1
+ rateLimitThreshold: 10
+ matchConditions: [
+ {
+ matchVariable: 'RemoteAddr'
+ selector: null
+ operator: 'GeoMatch'
+ negateCondition: false
+ transforms: []
+ matchValue: [
+ 'CH'
+ ]
+ }
+ {
+ matchVariable: 'RequestHeader'
+ selector: 'UserAgent'
+ operator: 'Contains'
+ negateCondition: false
+ transforms: []
+ matchValue: [
+ 'windows'
+ ]
+ }
+ {
+ matchVariable: 'QueryString'
+ operator: 'Contains'
+ negateCondition: false
+ transforms: [
+ 'UrlDecode'
+ 'Lowercase'
+ ]
+ matchValue: [
+ ''
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ managedRules: {
+ managedRuleSets: [
+ {
+ ruleSetType: 'Microsoft_BotManagerRuleSet'
+ ruleSetVersion: '1.0'
+ }
+ ]
+ }
+ tags: {
+ 'hidden-title': 'This is visible in the resource name'
+ Environment: 'Non-Prod'
+ Role: 'DeploymentValidation'
+ }
+ roleAssignments: [
+ {
+ roleDefinitionIdOrName: 'Owner'
+ principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+ principalType: 'ServicePrincipal'
+ }
+ {
+ roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
+ principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+ principalType: 'ServicePrincipal'
+ }
+ {
+ roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')
+ principalId: nestedDependencies.outputs.managedIdentityPrincipalId
+ principalType: 'ServicePrincipal'
+ }
+ ]
+ }
+}]
diff --git a/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep
new file mode 100644
index 0000000000..4e9017dbd7
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/tests/e2e/waf-aligned/main.test.bicep
@@ -0,0 +1,114 @@
+targetScope = 'subscription'
+
+metadata name = 'WAF-aligned'
+metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.'
+
+// ========== //
+// Parameters //
+// ========== //
+
+@description('Optional. The name of the resource group to deploy for testing purposes.')
+@maxLength(90)
+param resourceGroupName string = 'dep-${namePrefix}-network.frontdoorWebApplicationFirewallPolicies-${serviceShort}-rg'
+
+@description('Optional. The location to deploy resources to.')
+param location 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 = 'nagwafpwaf'
+
+@description('Optional. A token to inject into the name of each resource.')
+param namePrefix string = '#_namePrefix_#'
+
+// ============ //
+// Dependencies //
+// ============ //
+
+// General resources
+// =================
+resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = {
+ name: resourceGroupName
+ location: location
+}
+
+// ============== //
+// Test Execution //
+// ============== //
+
+@batchSize(1)
+module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: {
+ scope: resourceGroup
+ name: '${uniqueString(deployment().name, location)}-test-${serviceShort}-${iteration}'
+ params: {
+ name: '${namePrefix}${serviceShort}001'
+ location: location
+ sku: 'Premium_AzureFrontDoor'
+ policySettings: {
+ mode: 'Prevention'
+ redirectUrl: 'http://www.bing.com'
+ customBlockResponseStatusCode: 200
+ customBlockResponseBody: 'PGh0bWw+CjxoZWFkZXI+PHRpdGxlPkhlbGxvPC90aXRsZT48L2hlYWRlcj4KPGJvZHk+CkhlbGxvIHdvcmxkCjwvYm9keT4KPC9odG1sPg=='
+ }
+ customRules: {
+ rules: [
+ {
+ name: 'CustomRule1'
+ priority: 2
+ enabledState: 'Enabled'
+ action: 'Block'
+ ruleType: 'MatchRule'
+ rateLimitDurationInMinutes: 1
+ rateLimitThreshold: 10
+ matchConditions: [
+ {
+ matchVariable: 'RemoteAddr'
+ selector: null
+ operator: 'GeoMatch'
+ negateCondition: false
+ transforms: []
+ matchValue: [
+ 'CH'
+ ]
+ }
+ {
+ matchVariable: 'RequestHeader'
+ selector: 'UserAgent'
+ operator: 'Contains'
+ negateCondition: false
+ transforms: []
+ matchValue: [
+ 'windows'
+ ]
+ }
+ {
+ matchVariable: 'QueryString'
+ operator: 'Contains'
+ negateCondition: false
+ transforms: [
+ 'UrlDecode'
+ 'Lowercase'
+ ]
+ matchValue: [
+ ''
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ managedRules: {
+ managedRuleSets: [
+ {
+ ruleSetType: 'Microsoft_BotManagerRuleSet'
+ ruleSetVersion: '1.0'
+ }
+ ]
+ }
+ tags: {
+ 'hidden-title': 'This is visible in the resource name'
+ Environment: 'Non-Prod'
+ Role: 'DeploymentValidation'
+ }
+ }
+}]
diff --git a/avm/res/network/front-door-web-application-firewall-policy/version.json b/avm/res/network/front-door-web-application-firewall-policy/version.json
new file mode 100644
index 0000000000..83083db694
--- /dev/null
+++ b/avm/res/network/front-door-web-application-firewall-policy/version.json
@@ -0,0 +1,7 @@
+{
+ "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#",
+ "version": "0.1",
+ "pathFilters": [
+ "./main.json"
+ ]
+}
\ No newline at end of file
diff --git a/avm/utilities/pipelines/platform/Switch-WorkflowSate.ps1 b/avm/utilities/pipelines/platform/Switch-WorkflowState.ps1
similarity index 84%
rename from avm/utilities/pipelines/platform/Switch-WorkflowSate.ps1
rename to avm/utilities/pipelines/platform/Switch-WorkflowState.ps1
index 9b7b2929eb..c5a5a703bf 100644
--- a/avm/utilities/pipelines/platform/Switch-WorkflowSate.ps1
+++ b/avm/utilities/pipelines/platform/Switch-WorkflowState.ps1
@@ -24,26 +24,26 @@ Optional. A regex pattern that should not match against the workflow names. Defa
Optional. The GitHub PAT token to use for authentication when interacting with GitHub. If not provided, the PAT must be available in the environment variable 'GH_TOKEN'
.EXAMPLE
-Switch-WorkflowSate -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'enable' -GitHubToken ('iAmAToken' | ConvertTo-SecureString -AsPlainText -Force)
+Switch-WorkflowState -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'enable' -GitHubToken ('iAmAToken' | ConvertTo-SecureString -AsPlainText -Force)
Enable any AVM res/ptn workflow in the [Paul/bicep-registry-modules] repository that is not in state 'active' using a custom GitHub PAT token.
.EXAMPLE
-Switch-WorkflowSate -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'disable'
+Switch-WorkflowState -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'disable'
Disable any workflow in the [Paul/bicep-registry-modules] repository that has the state 'active', assuming you have a GitHub PAT token 'GH_TOKEN' set in your environment.
.EXAMPLE
-Switch-WorkflowSate -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'disable' -IncludePattern 'avm\.res\.network\.'
+Switch-WorkflowState -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'disable' -IncludePattern 'avm\.res\.network\.'
Disable any workflow with a naming matching [avm.res.network*] in the [Paul/bicep-registry-modules] repository that has the state 'active', assuming you have a GitHub PAT token 'GH_TOKEN' set in your environment.
.EXAMPLE
-Switch-WorkflowSate -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'disable' -IncludePattern 'avm\.res\.network' -ExlcudePattern 'avm\.res\.network\.virtual-network'
+Switch-WorkflowState -RepositoryOwner 'Paul' -RepositoryName 'bicep-registry-modules' -TargetState 'disable' -IncludePattern 'avm\.res\.network' -ExlcudePattern 'avm\.res\.network\.virtual-network'
Disable any workflow with a naming matching [avm.res.network*] but exluding those that match the name [avm.res.network.virtual-network] in the [Paul/bicep-registry-modules] repository that has the state 'active', assuming you have a GitHub PAT token 'GH_TOKEN' set in your environment.
#>
-function Switch-WorkflowSate {
+function Switch-WorkflowState {
[CmdletBinding()]
param (
diff --git a/avm/utilities/pipelines/sharedScripts/helper/Merge-FileWithNewContent.ps1 b/avm/utilities/pipelines/sharedScripts/helper/Merge-FileWithNewContent.ps1
index fb00965ae0..28fd3539e0 100644
--- a/avm/utilities/pipelines/sharedScripts/helper/Merge-FileWithNewContent.ps1
+++ b/avm/utilities/pipelines/sharedScripts/helper/Merge-FileWithNewContent.ps1
@@ -144,12 +144,15 @@ function Merge-FileWithNewContent {
# Section is not existing (end of file)
$startContent = $OldContent
if ($OldContent[$startIndex] -ne $SectionStartIdentifier ) {
+ # Add newline if necessary
+ if (-not [String]::IsNullOrEmpty($OldContent[$startIndex])) {
+ $startContent += @('')
+ }
# Add section header
- $startContent = $startContent + @('', $SectionStartIdentifier)
+ $startContent = $startContent + @($SectionStartIdentifier)
}
$endContent = @()
- }
- else {
+ } else {
switch ($ContentType) {
'table' {
$tableStartIndex = $startIndex + 1
@@ -169,8 +172,7 @@ function Merge-FileWithNewContent {
if ($ReadMeFileContent[$startIndex] -notcontains $SectionStartIdentifier) {
$newContent = @('', $SectionStartIdentifier) + $newContent
}
- }
- else {
+ } else {
$endIndex = Get-EndIndex -ReadMeFileContent $OldContent -startIndex $tableStartIndex -ContentType $ContentType
if ($endIndex -ne $OldContent.Count - 1) {
$endContent = $OldContent[$endIndex..($OldContent.Count - 1)]
@@ -195,8 +197,7 @@ function Merge-FileWithNewContent {
if ($ReadMeFileContent[$startIndex] -notcontains $SectionStartIdentifier) {
$newContent = @('', $SectionStartIdentifier) + $newContent
}
- }
- else {
+ } else {
$endIndex = Get-EndIndex -ReadMeFileContent $OldContent -startIndex $listStartIndex -ContentType $ContentType
if ($endIndex -ne $OldContent.Count - 1) {
$endContent = $OldContent[$endIndex..($OldContent.Count - 1)]
@@ -209,8 +210,7 @@ function Merge-FileWithNewContent {
$startContent = $OldContent[0..($startIndex)]
$newContent = @($SectionStartIdentifier, '') + $newContent
$endContent = $OldContent[($startIndex + 1)..($OldContent.Count - 1)]
- }
- else {
+ } else {
# section was found
$startContent = $OldContent[0..($startIndex)]
$endIndex = Get-EndIndex -ReadMeFileContent $OldContent -startIndex $startIndex -ContentType $ContentType