├── avm.bat
├── tests
├── unit
│ └── unit.go
└── README.md
├── .gitattributes
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── avm_question_feedback.yml
│ └── avm_module_issue.yml
├── dependabot.yml
├── workflows
│ └── pr-check.yml
├── actions
│ ├── linting
│ │ └── action.yml
│ ├── e2e-getexamples
│ │ └── action.yml
│ ├── e2e-testexamples
│ │ └── action.yml
│ └── docs-check
│ │ └── action.yml
├── PULL_REQUEST_TEMPLATE.md
├── policies
│ ├── eventResponder.yml
│ └── scheduledSearches.yml
└── copilot-instructions.md
├── examples
├── default
│ ├── _header.md
│ ├── locals.tf
│ ├── variables.tf
│ ├── _footer.md
│ ├── main.tf
│ └── README.md
├── deploy_fw_policy_with_rule_collection_group
│ ├── _header.md
│ ├── locals.tf
│ ├── variables.tf
│ ├── _footer.md
│ ├── main.tf
│ └── README.md
├── deploy_fw_policy_for_avd
│ ├── _header.md
│ ├── locals.tf
│ ├── variables.tf
│ ├── _footer.md
│ ├── main.tf
│ └── README.md
├── deploy_fw_policy_with_ipgroups
│ ├── _header.md
│ ├── locals.tf
│ ├── variables.tf
│ ├── _footer.md
│ ├── main.tf
│ └── README.md
├── README.md
└── .terraform-docs.yml
├── locals.tf
├── .vscode
├── extensions.json
├── settings.json
└── mcp.json
├── modules
├── README.md
├── rule_collection_groups
│ ├── terraform.tf
│ ├── outputs.tf
│ ├── _header.md
│ ├── _footer.md
│ ├── main.tf
│ ├── variables.tf
│ └── README.md
└── .terraform-docs.yml
├── .editorconfig
├── Makefile
├── _header.md
├── CODE_OF_CONDUCT.md
├── terraform.tf
├── outputs.tf
├── .devcontainer
└── devcontainer.json
├── _footer.md
├── CONTRIBUTING.md
├── SUPPORT.md
├── LICENSE
├── .terraform-docs.yml
├── .gitignore
├── main.telemetry.tf
├── avmmakefile
├── SECURITY.md
├── avm
├── avm.ps1
├── main.tf
├── AGENTS.md
├── variables.tf
└── README.md
/avm.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | .\avm.ps1 %1
3 |
--------------------------------------------------------------------------------
/tests/unit/unit.go:
--------------------------------------------------------------------------------
1 | package unit
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
3 | *.csv text eol=crlf
4 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | .github/CODEOWNERS @Azure/avm-core-team-technical-terraform
2 |
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | # Tests
2 |
3 | Create tests in the provided subdirectories.
4 |
--------------------------------------------------------------------------------
/examples/default/_header.md:
--------------------------------------------------------------------------------
1 | # Default example
2 |
3 | This deploys the module in its simplest form.
4 |
--------------------------------------------------------------------------------
/locals.tf:
--------------------------------------------------------------------------------
1 | locals {
2 | role_definition_resource_substring = "providers/Microsoft.Authorization/roleDefinitions"
3 | }
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "EditorConfig.EditorConfig",
4 | "hashicorp.terraform",
5 | "ms-azurertools.vscode-azureterraform"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/modules/README.md:
--------------------------------------------------------------------------------
1 | # Sub-modules
2 |
3 | Create directories for each sub-module if required.
4 | README.md files will be automatically generated for each sub-module using `terraform-docs`.
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 2
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.eol": "\n",
3 | "chat.agent.maxRequests": 500,
4 | "chat.math.enabled": true,
5 | "chat.todoListTool.enabled": true,
6 | "github.copilot.chat.agent.thinkingTool": true
7 | }
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: New AVM Module Proposal 📝
4 | url: https://aka.ms/AVM/ModuleProposal
5 | about: Want a new AVM Module to exist? Let us know!
--------------------------------------------------------------------------------
/modules/rule_collection_groups/terraform.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = "~> 1.5"
3 |
4 | required_providers {
5 | azurerm = {
6 | source = "hashicorp/azurerm"
7 | version = ">= 3.71, < 5.0.0"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | SHELL := /bin/bash
2 | AVM_MAKEFILE_REF := main
3 |
4 | $(shell curl -H 'Cache-Control: no-cache, no-store' -sSL "https://raw.githubusercontent.com/Azure/avm-terraform-governance/$(AVM_MAKEFILE_REF)/Makefile" -o avmmakefile)
5 | -include avmmakefile
6 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 |
4 | updates:
5 | - package-ecosystem: gomod
6 | directory: /tests
7 | schedule:
8 | interval: daily
9 | - package-ecosystem: "github-actions"
10 | directory: "/.github/workflows"
11 | schedule:
12 | interval: daily
13 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_rule_collection_group/_header.md:
--------------------------------------------------------------------------------
1 | # Deploy Azure Firewall Policy with Rule Collection Groups
2 |
3 | This example deploys Azure Firewall Policy with Rules Collection Groups
4 |
5 | - Firewall Policy
6 | - Rule Collection Groups
7 | - Rule Collections
8 | - Network and Application Rules
9 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_for_avd/_header.md:
--------------------------------------------------------------------------------
1 | # Deploy Firewall Policy for Azure Virtual Desktop
2 |
3 | This example deploys an Azure Firewall Policy with the required rules needed for Azure Virtual Desktop.
4 |
5 | - Firewall Policy
6 | - Rule Collection Groups
7 | - Rule Collections
8 | - Network and Application Rules
9 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_ipgroups/_header.md:
--------------------------------------------------------------------------------
1 | # Deploy Firewall Policy with IP Groups
2 |
3 | This deploys an Azure Firewall Policy with IP Groups in the rules
4 |
5 | - Firewall
6 | - Firewall Policy
7 | - Rule Collection Groups
8 | - Rule Collections
9 | - Network and Application Rules
10 | - IP Groups
11 |
--------------------------------------------------------------------------------
/examples/default/locals.tf:
--------------------------------------------------------------------------------
1 |
2 | locals {
3 | azure_regions = [
4 | "westeurope",
5 | "northeurope",
6 | "eastus",
7 | "eastus2",
8 | "westus",
9 | "westus2",
10 | "southcentralus",
11 | "northcentralus",
12 | "centralus",
13 | "eastasia",
14 | "southeastasia",
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_for_avd/locals.tf:
--------------------------------------------------------------------------------
1 |
2 | locals {
3 | azure_regions = [
4 | "westeurope",
5 | "northeurope",
6 | "eastus",
7 | "eastus2",
8 | "westus",
9 | "westus2",
10 | "southcentralus",
11 | "northcentralus",
12 | "centralus",
13 | "eastasia",
14 | "southeastasia",
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_ipgroups/locals.tf:
--------------------------------------------------------------------------------
1 |
2 | locals {
3 | azure_regions = [
4 | "westeurope",
5 | "northeurope",
6 | "eastus",
7 | "eastus2",
8 | "westus3",
9 | "westus2",
10 | "southcentralus",
11 | "canadacentral",
12 | "centralus",
13 | "eastasia",
14 | "southeastasia",
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_rule_collection_group/locals.tf:
--------------------------------------------------------------------------------
1 |
2 | locals {
3 | azure_regions = [
4 | "westeurope",
5 | "northeurope",
6 | "eastus",
7 | "eastus2",
8 | "westus3",
9 | "westus2",
10 | "southcentralus",
11 | "canadacentral",
12 | "centralus",
13 | "eastasia",
14 | "southeastasia",
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/examples/default/variables.tf:
--------------------------------------------------------------------------------
1 | variable "enable_telemetry" {
2 | type = bool
3 | default = true
4 | description = <"
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/terraform.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = "~> 1.5"
3 |
4 | required_providers {
5 | azapi = {
6 | source = "Azure/azapi"
7 | version = "~> 2.4"
8 | }
9 | azurerm = {
10 | source = "hashicorp/azurerm"
11 | version = ">= 3.71, < 5.0.0"
12 | }
13 | modtm = {
14 | source = "Azure/modtm"
15 | version = "~> 0.3"
16 | }
17 | random = {
18 | source = "hashicorp/random"
19 | version = "~> 3.5"
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/.vscode/mcp.json:
--------------------------------------------------------------------------------
1 | {
2 | "servers": {
3 | "terraform-mcp-eva": {
4 | "type": "stdio",
5 | "command": "docker",
6 | "args": [
7 | "run",
8 | "-i",
9 | "--rm",
10 | "-v",
11 | "${workspaceFolder}:/workspace",
12 | "-w",
13 | "/workspace",
14 | "-e",
15 | "TRANSPORT_MODE=stdio",
16 | "-e",
17 | "GITHUB_TOKEN",
18 | "--pull=always",
19 | "ghcr.io/lonegunmanb/terraform-mcp-eva"
20 | ]
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | - Create a directory for each example.
4 | - Create a `_header.md` file in each directory to describe the example.
5 | - See the `default` example provided as a skeleton - this must remain, but you can add others.
6 | - Run `make fmt && make docs` from the repo root to generate the required documentation.
7 |
8 | > **Note:** Examples must be deployable and idempotent. Ensure that no input variables are required to run the example and that random values are used to ensure unique resource names. E.g. use the [naming module](https://registry.terraform.io/modules/Azure/naming/azurerm/latest) to generate a unique name for a resource.
9 |
--------------------------------------------------------------------------------
/outputs.tf:
--------------------------------------------------------------------------------
1 | output "resource" {
2 | description = <<-EOT
3 | "This is the full output for Firewall Policy resource. This is the default output for the module following AVM standards. Review the examples below for the correct output to use in your module."
4 | Examples:
5 | - module.firewall_policy.resource.id
6 | - module.firewall_policy.resource.firewalls
7 | - module.firewall_policy.resource.child_policies
8 | - module.firewall_policy.resource.rule_collection_groups
9 | EOT
10 | value = azurerm_firewall_policy.this
11 | }
12 |
13 | output "resource_id" {
14 | description = "the resource id of the firewall policy"
15 | value = azurerm_firewall_policy.this.id
16 | }
17 |
--------------------------------------------------------------------------------
/modules/rule_collection_groups/_header.md:
--------------------------------------------------------------------------------
1 | # Azure Firewall Policy Rule Collection Group
2 |
3 | This is the sub-module to create Rule Collection Groups in Azure Firewall Policy
4 |
5 | ## Features
6 |
7 | This module supports:
8 |
9 | - Creates Rule Collection Groups
10 | - Creates Rule Collections
11 | - Creates Network Rules, Application Rules, and NAT Rules
12 |
13 | "Major version Zero (0.y.z) is for initial development. Anything MAY change at any time. The module SHOULD NOT be considered stable till at least it is major version one (1.0.0) or greater. Changes will always be via new versions being published and no changes will be made to existing published versions. For more details please go to "
14 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "image": "mcr.microsoft.com/azterraform:avm-latest",
3 | "containerEnv": {
4 | "AVM_IN_CONTAINER": "true"
5 | },
6 | "updateRemoteUserUID": true,
7 | "runArgs": [
8 | "--cap-add=SYS_PTRACE",
9 | "--security-opt",
10 | "seccomp=unconfined",
11 | "--init",
12 | "--network=host"
13 | ],
14 | "mounts": [
15 | "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
16 | ],
17 | "onCreateCommand": "terraform version",
18 | "customizations": {
19 | "vscode": {
20 | "settings": {
21 | "terraform.languageServer.terraform.path": "/home/runtimeuser/tfenv/bin/terraform"
22 | },
23 | "extensions": [
24 | "ms-azuretools.vscode-azureterraform",
25 | "EditorConfig.EditorConfig",
26 | "hashicorp.terraform"
27 | ]
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/_footer.md:
--------------------------------------------------------------------------------
1 |
2 | ## Data Collection
3 |
4 | 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. 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.
5 |
--------------------------------------------------------------------------------
/examples/default/_footer.md:
--------------------------------------------------------------------------------
1 |
2 | ## Data Collection
3 |
4 | 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. 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.
5 |
--------------------------------------------------------------------------------
/modules/rule_collection_groups/_footer.md:
--------------------------------------------------------------------------------
1 |
2 | ## Data Collection
3 |
4 | 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. 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.
5 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_for_avd/_footer.md:
--------------------------------------------------------------------------------
1 |
2 | ## Data Collection
3 |
4 | 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. 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.
5 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_ipgroups/_footer.md:
--------------------------------------------------------------------------------
1 |
2 | ## Data Collection
3 |
4 | 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. 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.
5 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_rule_collection_group/_footer.md:
--------------------------------------------------------------------------------
1 |
2 | ## Data Collection
3 |
4 | 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. 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.
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | This project welcomes contributions and suggestions. Most contributions require you to
4 | agree to a Contributor License Agreement (CLA) declaring that you have the right to,
5 | and actually do, grant us the rights to use your contribution. For details, visit
6 | https://cla.microsoft.com.
7 |
8 | When you submit a pull request, a CLA-bot will automatically determine whether you need
9 | to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the
10 | instructions provided by the bot. You will only need to do this once across all repositories using our CLA.
11 |
12 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
13 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
14 | or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
15 |
--------------------------------------------------------------------------------
/.github/workflows/pr-check.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: PR Check
3 | on:
4 | pull_request:
5 | types: ['opened', 'reopened', 'synchronize']
6 | merge_group:
7 | workflow_dispatch:
8 |
9 | jobs:
10 | check:
11 | permissions: {}
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: checking for fork
15 | shell: pwsh
16 | run: |
17 | $isFork = "${{ github.event.pull_request.head.repo.fork }}"
18 | if($isFork -eq "true") {
19 | echo "### WARNING: This workflow is disabled for forked repositories. Please follow the [release branch process](https://azure.github.io/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#5-create-a-pull-request-to-the-upstream-repository) if end to end tests are required." >> $env:GITHUB_STEP_SUMMARY
20 | }
21 |
22 | run-managed-workflow:
23 | if: github.event.pull_request.head.repo.fork == false
24 | uses: Azure/avm-terraform-governance/.github/workflows/managed-pr-check.yml@main
25 | name: run managed workflow
26 | secrets: inherit
27 | permissions:
28 | id-token: write
29 | contents: read
30 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # Support
2 |
3 | > ⚠️**Note:** For the full details on the support statements, SLAs, and more for the Azure Verified Modules (AVM) initiative please visit [aka.ms/AVM/Support](https://aka.ms/avm/support) ⚠️
4 |
5 | ## How to file issues and get help
6 |
7 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing issues before filing new issues to avoid duplicates. For new issues, file your bug or feature request as a new issue.
8 |
9 | Issues can be created and searched through for existing [issues here](../../issues).
10 |
11 | Please provide as much information as possible when filing an issue. Include screenshots or correlation IDs if possible (please redact any sensitive information).
12 |
13 | For instructions on how to get deployments and correlation ID, please follow this link [here](https://learn.microsoft.com/azure/azure-resource-manager/templates/deployment-history?tabs=azure-portal#get-deployments-and-correlation-id).
14 |
15 | We may ask you to create an Azure support request once we have triaged the issue following the process documented [here](https://learn.microsoft.com/azure/azure-portal/supportability/how-to-create-azure-support-request).
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/.github/actions/linting/action.yml:
--------------------------------------------------------------------------------
1 | author: AVM
2 | name: linting
3 | description: Tests the example supplied in the input. Needs checkout and Azure login prior.
4 | inputs:
5 | github-token:
6 | description: The GitHub token
7 | required: true
8 |
9 | runs:
10 | using: composite
11 | steps:
12 | - uses: hashicorp/setup-terraform@v2
13 | with:
14 | terraform_version: ">=1.5.0"
15 |
16 | - name: terraform init
17 | run: terraform init
18 | shell: bash
19 |
20 | - name: terraform validate
21 | run: terraform validate
22 | shell: bash
23 |
24 | - uses: terraform-linters/setup-tflint@v3
25 | name: Setup TFLint
26 | with:
27 | tflint_version: v0.48.0
28 | env:
29 | GITHUB_TOKEN: ${{ inputs.github-token }}
30 |
31 | - name: get tflint config
32 | run: |
33 | curl --header "Authorization: Bearer ${{ inputs.github-token }}" https://raw.githubusercontent.com/Azure/terraform-azurerm-avm-template/main/.tflint.hcl -o .tflint.hcl
34 | shell: bash
35 |
36 | - name: tflint init
37 | run: tflint --init
38 | shell: bash
39 |
40 | - name: tflint
41 | run: tflint
42 | shell: bash
43 |
--------------------------------------------------------------------------------
/.github/actions/e2e-getexamples/action.yml:
--------------------------------------------------------------------------------
1 | author: AVM
2 | name: e2e - getexamples
3 | description: Gets example directories from `examples/` and outputs them to the next step
4 | inputs:
5 | github-token:
6 | description: The GitHub token to use for the API calls
7 | required: true
8 | outputs:
9 | examples:
10 | description: The examples to test
11 | value: ${{ steps.getexamples.outputs.examples }}
12 | runs:
13 | using: composite
14 | steps:
15 | - name: get examples
16 | id: getexamples
17 | run: |
18 | # Get latest release from GitHub API and get download URL for the Linux x64 binary
19 | URL=$(curl -sL -H "Authorization: Bearer ${{ inputs.github-token }}" https://api.github.com/repos/matt-FFFFFF/jsonls/releases/latest \
20 | | jq -r '.assets[] | select( .name | test("linux_amd64")) | .browser_download_url')
21 |
22 | # Download the binary and extract
23 | curl -sL "$URL" | tar -xvz jsonls
24 |
25 | # Ensure exec bit set
26 | sudo chmod a+x jsonls
27 |
28 | # Move binary to path
29 | sudo mv jsonls /usr/local/bin/jsonls
30 |
31 | # Get the examples
32 | echo examples="$(jsonls -d)" >> "$GITHUB_OUTPUT"
33 | working-directory: examples
34 | shell: bash
35 |
--------------------------------------------------------------------------------
/examples/default/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.3.0"
3 |
4 | required_providers {
5 | azurerm = {
6 | source = "hashicorp/azurerm"
7 | version = ">= 3.71, < 5.0.0"
8 | }
9 | random = {
10 | source = "hashicorp/random"
11 | version = ">= 3.5.0, < 4.0.0"
12 | }
13 | }
14 | }
15 |
16 | provider "azurerm" {
17 | features {}
18 | }
19 |
20 | # This picks a random region from the list of regions.
21 | resource "random_integer" "region_index" {
22 | max = length(local.azure_regions) - 1
23 | min = 0
24 | }
25 |
26 | # This ensures we have unique CAF compliant names for our resources.
27 | module "naming" {
28 | source = "Azure/naming/azurerm"
29 | version = "0.3.0"
30 | }
31 |
32 | # This is required for resource modules
33 | resource "azurerm_resource_group" "this" {
34 | location = local.azure_regions[random_integer.region_index.result]
35 | name = module.naming.resource_group.name_unique
36 | }
37 |
38 | # This is the module call
39 | module "firewall_policy" {
40 | source = "../.."
41 |
42 | location = azurerm_resource_group.this.location
43 | name = module.naming.firewall_policy.name_unique
44 | resource_group_name = azurerm_resource_group.this.name
45 | # source = "Azure/avm-res-network-firewallpolicy/azurerm"
46 | enable_telemetry = var.enable_telemetry
47 | }
--------------------------------------------------------------------------------
/.terraform-docs.yml:
--------------------------------------------------------------------------------
1 | ### To generate the output file to partially incorporate in the README.md,
2 | ### Execute this command in the Terraform module's code folder:
3 | # terraform-docs -c .terraform-docs.yml .
4 |
5 | formatter: "markdown document" # this is required
6 |
7 | version: "~> 0.18"
8 |
9 | header-from: "_header.md"
10 | footer-from: "_footer.md"
11 |
12 | recursive:
13 | enabled: false
14 | path: modules
15 |
16 | sections:
17 | hide: []
18 | show: []
19 |
20 | content: |-
21 |
22 | {{ .Header }}
23 |
24 |
25 | {{ .Requirements }}
26 |
27 | {{ .Resources }}
28 |
29 |
30 | {{ .Inputs }}
31 |
32 | {{ .Outputs }}
33 |
34 | {{ .Modules }}
35 |
36 | {{ .Footer }}
37 |
38 | output:
39 | file: README.md
40 | mode: replace
41 | template: |-
42 |
43 | {{ .Content }}
44 |
45 | output-values:
46 | enabled: false
47 | from: ""
48 |
49 | sort:
50 | enabled: true
51 | by: required
52 |
53 | settings:
54 | anchor: true
55 | color: true
56 | default: true
57 | description: false
58 | escape: true
59 | hide-empty: false
60 | html: true
61 | indent: 2
62 | lockfile: false
63 | read-comments: true
64 | required: true
65 | sensitive: true
66 | type: true
67 |
--------------------------------------------------------------------------------
/modules/.terraform-docs.yml:
--------------------------------------------------------------------------------
1 | ### To generate the output file to partially incorporate in the README.md,
2 | ### Execute this command in the Terraform module's code folder:
3 | # terraform-docs -c .terraform-docs.yml .
4 |
5 | formatter: "markdown document" # this is required
6 |
7 | version: "~> 0.18"
8 |
9 | header-from: "_header.md"
10 | footer-from: "_footer.md"
11 |
12 | recursive:
13 | enabled: false
14 | path: modules
15 |
16 | sections:
17 | hide: []
18 | show: []
19 |
20 | content: |-
21 |
22 | {{ .Header }}
23 |
24 |
25 | {{ .Requirements }}
26 |
27 | {{ .Resources }}
28 |
29 |
30 | {{ .Inputs }}
31 |
32 | {{ .Outputs }}
33 |
34 | {{ .Modules }}
35 |
36 | {{ .Footer }}
37 |
38 | output:
39 | file: README.md
40 | mode: replace
41 | template: |-
42 |
43 | {{ .Content }}
44 |
45 | output-values:
46 | enabled: false
47 | from: ""
48 |
49 | sort:
50 | enabled: true
51 | by: required
52 |
53 | settings:
54 | anchor: true
55 | color: true
56 | default: true
57 | description: false
58 | escape: true
59 | hide-empty: false
60 | html: true
61 | indent: 2
62 | lockfile: false
63 | read-comments: true
64 | required: true
65 | sensitive: true
66 | type: true
67 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local .terraform directories
2 | **/.terraform/*
3 |
4 | # .tfstate files
5 | *.tfstate
6 | *.tfstate.*
7 |
8 | # Crash log files
9 | crash.log
10 | crash.*.log
11 |
12 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as
13 | # password, private keys, and other secrets. These should not be part of version
14 | # control as they are data points which are potentially sensitive and subject
15 | # to change depending on the environment.
16 | *.tfvars
17 | *.tfvars.json
18 |
19 | # Ignore override files as they are usually used to override resources locally and so
20 | # are not checked in
21 | override.tf
22 | override.tf.json
23 | *_override.tf
24 | *_override.tf.json
25 |
26 | # Include override files you do wish to add to version control using negated pattern
27 | # !example_override.tf
28 |
29 | # Ignore Terraform lock file
30 | .terraform.lock.hcl
31 |
32 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
33 | # example: *tfplan*
34 |
35 | # Ignore CLI configuration files
36 | .terraformrc
37 | terraform.rc
38 | *tfplan*
39 | .terraform.lock.hcl
40 | README-generated.md
41 | avm.tflint.hcl
42 | avm.tflint.merged.hcl
43 | avm.tflint_example.hcl
44 | avm.tflint_example.merged.hcl
45 | avmmakefile
46 | *.md.tmp
47 | .DS_Store
48 | avm.tflint_module.hcl
49 | avm.tflint_module.merged.hcl
50 | examples/*/policy
51 | *.mptfbackup
52 | .avm
53 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 |
12 |
13 | ## Type of Change
14 |
15 |
16 |
17 | - [ ] Non-module change (e.g. CI/CD, documentation, etc.)
18 | - [ ] Azure Verified Module updates:
19 | - [ ] Bugfix containing backwards compatible bug fixes
20 | - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description.
21 | - [ ] The bug was found by the module author, and no one has opened an issue to report it yet.
22 | - [ ] Feature update backwards compatible feature updates.
23 | - [ ] Breaking changes.
24 | - [ ] Update to documentation
25 |
26 | # Checklist
27 |
28 | - [ ] I'm sure there are no other open Pull Requests for the same update/change
29 | - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings
30 | - [ ] I did run all [pre-commit](https://azure.github.io/Azure-Verified-Modules/contributing/terraform/terraform-contribution-flow/#5-run-pre-commit-checks) checks
31 |
32 |
33 |
--------------------------------------------------------------------------------
/examples/.terraform-docs.yml:
--------------------------------------------------------------------------------
1 | ### To generate the output file to partially incorporate in the README.md,
2 | ### Execute this command in the Terraform module's code folder:
3 | # terraform-docs -c .terraform-docs.yml .
4 |
5 | formatter: "markdown document" # this is required
6 |
7 | version: "~> 0.18"
8 |
9 | header-from: "_header.md"
10 | footer-from: "_footer.md"
11 |
12 | recursive:
13 | enabled: false
14 | path: modules
15 |
16 | sections:
17 | hide: []
18 | show: []
19 |
20 | content: |-
21 |
22 | {{ .Header }}
23 |
24 | ```hcl
25 | {{ include "main.tf" }}
26 | ```
27 |
28 |
29 | {{ .Requirements }}
30 |
31 | {{ .Resources }}
32 |
33 |
34 | {{ .Inputs }}
35 |
36 | {{ .Outputs }}
37 |
38 | {{ .Modules }}
39 |
40 | {{ .Footer }}
41 | output:
42 | file: README.md
43 | mode: replace
44 | template: |-
45 |
46 | {{ .Content }}
47 |
48 | output-values:
49 | enabled: false
50 | from: ""
51 |
52 | sort:
53 | enabled: true
54 | by: required
55 |
56 | settings:
57 | anchor: true
58 | color: true
59 | default: true
60 | description: false
61 | escape: true
62 | hide-empty: false
63 | html: true
64 | indent: 2
65 | lockfile: false
66 | read-comments: true
67 | required: true
68 | sensitive: true
69 | type: true
70 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/avm_question_feedback.yml:
--------------------------------------------------------------------------------
1 | name: AVM - General Question/Feedback ❔
2 | description: Just got a question or some general feedback? Let us know!
3 | title: "[AVM Question/Feedback]: "
4 | labels:
5 | [
6 | "Language: Terraform :globe_with_meridians:",
7 | "Type: Question/Feedback :raising_hand:",
8 | "Needs: Triage :mag:",
9 | ]
10 | projects: ["Azure/538"]
11 | body:
12 | - type: markdown
13 | attributes:
14 | value: |
15 | Thank you for your question/feedback!
16 |
17 | > **NOTE**: If your question/request is related to the AVM site/documentation, please file an issue in the [AVM repo](https://github.com/Azure/Azure-Verified-Modules/issues/new?assignees=&labels=Type%3A+Question%2FFeedback+%3Araising_hand%3A%2CNeeds%3A+Triage+%3Amag%3A&projects=&template=question_feedback.yml&title=%5BQuestion%2FFeedback%5D%3A+).
18 | - type: checkboxes
19 | id: existing-checks
20 | attributes:
21 | label: Check for previous/existing GitHub issues
22 | description: By submitting this issue, you confirm that you have searched for previous/existing GitHub issues to avoid creating a duplicate.
23 | options:
24 | - label: I have checked for previous/existing GitHub issues
25 | required: true
26 | - type: textarea
27 | id: question-feedback-text
28 | attributes:
29 | label: Description
30 | description: Let us know your question or feedback here!
31 | validations:
32 | required: true
--------------------------------------------------------------------------------
/.github/actions/e2e-testexamples/action.yml:
--------------------------------------------------------------------------------
1 | author: AVM
2 | name: e2e - testexamples
3 | description: Tests the example supplied in the input. Needs checkout and Azure login prior.
4 | inputs:
5 | example:
6 | description: The example directory to test
7 | required: true
8 |
9 | runs:
10 | using: composite
11 | steps:
12 | - uses: hashicorp/setup-terraform@v2
13 | with:
14 | terraform_version: ">=1.5.0"
15 |
16 | - name: terraform init
17 | run: terraform init
18 | working-directory: examples/${{ inputs.example }}
19 | shell: bash
20 |
21 | - name: terraform apply
22 | run: terraform apply -auto-approve
23 | working-directory: examples/${{ inputs.example }}
24 | shell: bash
25 |
26 | - name: terraform plan
27 | id: plan
28 | run: |
29 | terraform plan -detailed-exitcode
30 | echo PLANCODE="$?" >> "$GITHUB_OUTPUT"
31 | continue-on-error: true
32 | working-directory: examples/${{ inputs.example }}
33 | shell: bash
34 |
35 | - name: check idempotent
36 | run: |
37 | echo Error: terraform plan code is ${{ steps.plan.outputs.PLANCODE }}
38 | exit 1
39 | working-directory: examples/${{ inputs.example }}
40 | shell: bash
41 | if: steps.plan.outputs.PLANCODE != 0
42 |
43 | - name: terraform destroy
44 | run: terraform destroy -auto-approve
45 | working-directory: examples/${{ inputs.example }}
46 | shell: bash
47 | if: always()
48 |
--------------------------------------------------------------------------------
/.github/actions/docs-check/action.yml:
--------------------------------------------------------------------------------
1 | author: AVM
2 | name: Docs check
3 | description: Checks that documentation has been updated on PR
4 | runs:
5 | using: composite
6 | steps:
7 | - name: setup go
8 | uses: actions/setup-go@v4
9 | with:
10 | go-version: "1.21.x"
11 | # cache-dependency-path: tests/go.sum
12 |
13 | - name: setup Terraform
14 | uses: hashicorp/setup-terraform@v2
15 | with:
16 | terraform_wrapper: false
17 |
18 | - name: install tools
19 | shell: bash
20 | run: |
21 | go install github.com/katbyte/terrafmt@latest
22 | go install github.com/terraform-docs/terraform-docs@latest
23 |
24 | - name: fmt check
25 | shell: bash
26 | run: |
27 | echo "==> Fixing Terraform code with terraform fmt..."
28 | terraform fmt -recursive
29 | echo "==> Fixing embedded Terraform with terrafmt..."
30 | find . | egrep ".md|.tf" | grep -v README.md | sort | while read f; do terrafmt fmt $$f; done
31 |
32 | - name: docs check
33 | shell: bash
34 | run: |
35 | echo "==> Generating module documentation..."
36 | terraform-docs -c .terraform-docs.yml .
37 | echo "==> Generating examples documentation..."
38 | cd examples && for d in $(ls -d */); do terraform-docs $d; done
39 |
40 | - name: check for changes
41 | shell: bash
42 | run: |
43 | echo "==> Testing for changes to tracked files"
44 | CHANGES=$(git status -suno)
45 | if [ "$CHANGES" ]; then
46 | echo "Repository formatting or documentation is not correct."
47 | echo
48 | git diff
49 | echo
50 | echo "Run 'make fmt && make docs' locally and commit the changes to fix."
51 | exit 1
52 | fi
53 |
--------------------------------------------------------------------------------
/main.telemetry.tf:
--------------------------------------------------------------------------------
1 |
2 | data "modtm_module_source" "telemetry" {
3 | count = var.enable_telemetry ? 1 : 0
4 |
5 | module_path = path.module
6 | }
7 |
8 | resource "random_uuid" "telemetry" {
9 | count = var.enable_telemetry ? 1 : 0
10 | }
11 |
12 | resource "modtm_telemetry" "telemetry" {
13 | count = var.enable_telemetry ? 1 : 0
14 |
15 | tags = merge({
16 | subscription_id = one(data.azapi_client_config.telemetry).subscription_id
17 | tenant_id = one(data.azapi_client_config.telemetry).tenant_id
18 | module_source = one(data.modtm_module_source.telemetry).module_source
19 | module_version = one(data.modtm_module_source.telemetry).module_version
20 | random_id = one(random_uuid.telemetry).result
21 | }, { location = local.main_location })
22 | }
23 | data "azapi_client_config" "telemetry" {
24 | count = var.enable_telemetry ? 1 : 0
25 | }
26 |
27 | locals {
28 | valid_module_source_regex = [
29 | "registry.terraform.io/[A|a]zure/.+",
30 | "registry.opentofu.io/[A|a]zure/.+",
31 | "git::https://github\\.com/[A|a]zure/.+",
32 | "git::ssh:://git@github\\.com/[A|a]zure/.+",
33 | ]
34 | }
35 |
36 | locals {
37 | avm_azapi_headers = !var.enable_telemetry ? {} : (local.fork_avm ? {
38 | fork_avm = "true"
39 | random_id = one(random_uuid.telemetry).result
40 | } : {
41 | avm = "true"
42 | random_id = one(random_uuid.telemetry).result
43 | avm_module_source = one(data.modtm_module_source.telemetry).module_source
44 | avm_module_version = one(data.modtm_module_source.telemetry).module_version
45 | })
46 | }
47 |
48 | locals {
49 | fork_avm = !anytrue([for r in local.valid_module_source_regex : can(regex(r, one(data.modtm_module_source.telemetry).module_source))])
50 | }
51 |
52 | locals {
53 | # tflint-ignore: terraform_unused_declarations
54 | avm_azapi_header = join(" ", [for k, v in local.avm_azapi_headers : "${k}=${v}"])
55 | }
56 | locals {
57 | main_location = var.location
58 | }
59 |
60 |
--------------------------------------------------------------------------------
/avmmakefile:
--------------------------------------------------------------------------------
1 | AVM_PORCH_BASE_URL := git::https://github.com/Azure/avm-terraform-governance//porch-configs
2 | AVM_PORCH_REF := main
3 |
4 | .PHONY: help
5 | help:
6 | @echo "please use 'make '"
7 | @echo "available targets are:"
8 | @echo " help"
9 | @echo " migrate (a no-op, this repo has already been migrated)"
10 | @echo " pre-commit (runs doc generation and repo file sync)"
11 | @echo " pr-check (checks that pre-commit has been run and runs linters)"
12 | @echo " test-examples (tests all examples - set `AVM_EXAMPLE` to the specific example name to only test one)"
13 | @echo " tf-test-unit (runs unit tests in `tests/unit`)"
14 | @echo " tf-test-integration (runs integration tests in `tests/integration`)"
15 | @echo " globalsetup (runs global setup tasks, only if you have a `examples/setup.sh`)"
16 | @echo " globalteardown (runs global teardown tasks, only if you have a `examples/teardown.sh`)"
17 |
18 | .PHONY: migrate
19 | migrate:
20 | @echo "This is a no-op. This repo has already been migrated."
21 |
22 | .PHONY: pre-commit
23 | pre-commit:
24 | @echo "Running pre-commit..."
25 | porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/pre-commit.porch.yaml?ref=$(AVM_PORCH_REF)"
26 |
27 | .PHONY: pr-check
28 | pr-check:
29 | @echo "Running PR check..."
30 | porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/pr-check.porch.yaml?ref=$(AVM_PORCH_REF)"
31 |
32 | .PHONY: test-examples
33 | test-examples:
34 | @echo "Testing examples..."
35 | porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/test-examples.porch.yaml?ref=$(AVM_PORCH_REF)"
36 |
37 | .PHONY: tf-test-unit
38 | tf-test-unit:
39 | @echo "Running terraform unit test..."
40 | AVM_TEST_TYPE="unit" porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/terraform-test.porch.yaml?ref=$(AVM_PORCH_REF)"
41 |
42 | .PHONY: tf-test-integration
43 | tf-test-integration:
44 | @echo "Running terraform integration test..."
45 | AVM_TEST_TYPE="integration" porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/terraform-test.porch.yaml?ref=$(AVM_PORCH_REF)"
46 |
47 | .PHONY: globalsetup
48 | globalsetup:
49 | @echo "Running global setup..."
50 | porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/global-setup.porch.yaml?ref=$(AVM_PORCH_REF)"
51 |
52 | .PHONY: globalteardown
53 | globalteardown:
54 | @echo "Running global teardown..."
55 | porch run ${TUI} -f "$(AVM_PORCH_BASE_URL)/global-teardown.porch.yaml?ref=$(AVM_PORCH_REF)"
56 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/avm_module_issue.yml:
--------------------------------------------------------------------------------
1 | name: AVM - Module Issue ➕🐛🔒
2 | description: Want to request a new Module feature or report a bug? Let us know!
3 | title: "[AVM Module Issue]: "
4 | labels: ["Needs: Triage :mag:", "Language: Terraform :globe_with_meridians:"]
5 | projects: ["Azure/566"]
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thank you for submitting this AVM Module Issue! To help us triage your issue, please provide the below details.
11 |
12 | > **NOTE**: If you'd like to propose a new AVM module, please file an [AVM Module Proposal](https://aka.ms/AVM/ModuleProposal).
13 | - type: checkboxes
14 | id: existing-checks
15 | attributes:
16 | label: Check for previous/existing GitHub issues
17 | description: By submitting this issue, you confirm that you have searched for previous/existing GitHub issues to avoid creating a duplicate.
18 | options:
19 | - label: I have checked for previous/existing GitHub issues
20 | required: true
21 | - type: dropdown
22 | id: issue-type
23 | attributes:
24 | label: Issue Type?
25 | description: How would you best describe this issue? Is this a...
26 | options:
27 | - ""
28 | - "Feature Request"
29 | - "Bug"
30 | - "I'm not sure"
31 | validations:
32 | required: true
33 | - type: input
34 | id: module-version
35 | attributes:
36 | label: (Optional) Module Version
37 | description: Please provide which version(s) of the module does this issue apply to.
38 | validations:
39 | required: false
40 | - type: input
41 | id: correlation-id
42 | attributes:
43 | label: (Optional) Correlation Id
44 | description: Please provide a correlation id if available and appropriate.
45 | validations:
46 | required: false
47 | - type: textarea
48 | id: question-feedback-text
49 | attributes:
50 | label: Description
51 | description: |
52 | Please describe the issue!
53 | > **NOTE**: All requested features must already be supported by the provider and Preview Services ([SFR1](https://azure.github.io/Azure-Verified-Modules/specs/shared/#id-sfr1---category-composition---preview-services)) are not supported.
54 | placeholder: |
55 |
59 | validations:
60 | required: true
61 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_rule_collection_group/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.3.0"
3 |
4 | required_providers {
5 | azurerm = {
6 | source = "hashicorp/azurerm"
7 | version = ">= 3.71, < 5.0.0"
8 | }
9 | random = {
10 | source = "hashicorp/random"
11 | version = ">= 3.5.0, < 4.0.0"
12 | }
13 | }
14 | }
15 |
16 | provider "azurerm" {
17 | features {}
18 | }
19 |
20 | # This picks a random region from the list of regions.
21 | resource "random_integer" "region_index" {
22 | max = length(local.azure_regions) - 1
23 | min = 0
24 | }
25 |
26 | # This ensures we have unique CAF compliant names for our resources.
27 | module "naming" {
28 | source = "Azure/naming/azurerm"
29 | version = "0.3.0"
30 | }
31 |
32 | # This is required for resource modules
33 | resource "azurerm_resource_group" "this" {
34 | location = local.azure_regions[random_integer.region_index.result]
35 | name = module.naming.resource_group.name_unique
36 | }
37 |
38 | # This is the module call
39 | module "firewall_policy" {
40 | source = "../.."
41 |
42 | location = azurerm_resource_group.this.location
43 | name = module.naming.firewall_policy.name_unique
44 | resource_group_name = azurerm_resource_group.this.name
45 | # source = "Azure/avm-res-network-firewallpolicy/azurerm"
46 | enable_telemetry = var.enable_telemetry
47 | }
48 |
49 | module "rule_collection_group" {
50 | source = "../../modules/rule_collection_groups"
51 |
52 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
53 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
54 | firewall_policy_rule_collection_group_name = "NetworkRuleCollectionGroup"
55 | firewall_policy_rule_collection_group_priority = 400
56 | firewall_policy_rule_collection_group_application_rule_collection = [
57 | {
58 | action = "Allow"
59 | name = "ApplicationRuleCollection"
60 | priority = 600
61 | rule = [
62 | {
63 | name = "AllowAll"
64 | description = "Allow traffic to Microsoft.com"
65 | source_addresses = ["10.0.0.0/24"]
66 | protocols = [
67 | {
68 | port = 443
69 | type = "Https"
70 | }
71 | ]
72 | destination_fqdns = ["microsoft.com"]
73 | }
74 | ]
75 | }
76 | ]
77 | firewall_policy_rule_collection_group_network_rule_collection = [
78 | {
79 | action = "Allow"
80 | name = "NetworkRuleCollection"
81 | priority = 400
82 | rule = [
83 | {
84 | name = "OutboundToInternet"
85 | description = "Allow traffic outbound to the Internet"
86 | destination_addresses = ["0.0.0.0/0"]
87 | destination_ports = ["443"]
88 | source_addresses = ["10.0.0.0/24"]
89 | protocols = ["TCP"]
90 | }
91 | ]
92 | }
93 | ]
94 | }
--------------------------------------------------------------------------------
/examples/default/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Default example
4 |
5 | This deploys the module in its simplest form.
6 |
7 | ```hcl
8 | terraform {
9 | required_version = ">= 1.3.0"
10 |
11 | required_providers {
12 | azurerm = {
13 | source = "hashicorp/azurerm"
14 | version = ">= 3.71, < 5.0.0"
15 | }
16 | random = {
17 | source = "hashicorp/random"
18 | version = ">= 3.5.0, < 4.0.0"
19 | }
20 | }
21 | }
22 |
23 | provider "azurerm" {
24 | features {}
25 | }
26 |
27 | # This picks a random region from the list of regions.
28 | resource "random_integer" "region_index" {
29 | max = length(local.azure_regions) - 1
30 | min = 0
31 | }
32 |
33 | # This ensures we have unique CAF compliant names for our resources.
34 | module "naming" {
35 | source = "Azure/naming/azurerm"
36 | version = "0.3.0"
37 | }
38 |
39 | # This is required for resource modules
40 | resource "azurerm_resource_group" "this" {
41 | location = local.azure_regions[random_integer.region_index.result]
42 | name = module.naming.resource_group.name_unique
43 | }
44 |
45 | # This is the module call
46 | module "firewall_policy" {
47 | source = "../.."
48 |
49 | location = azurerm_resource_group.this.location
50 | name = module.naming.firewall_policy.name_unique
51 | resource_group_name = azurerm_resource_group.this.name
52 | # source = "Azure/avm-res-network-firewallpolicy/azurerm"
53 | enable_telemetry = var.enable_telemetry
54 | }
55 | ```
56 |
57 |
58 | ## Requirements
59 |
60 | The following requirements are needed by this module:
61 |
62 | - [terraform](#requirement\_terraform) (>= 1.3.0)
63 |
64 | - [azurerm](#requirement\_azurerm) (>= 3.71, < 5.0.0)
65 |
66 | - [random](#requirement\_random) (>= 3.5.0, < 4.0.0)
67 |
68 | ## Resources
69 |
70 | The following resources are used by this module:
71 |
72 | - [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource)
73 | - [random_integer.region_index](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) (resource)
74 |
75 |
76 | ## Required Inputs
77 |
78 | No required inputs.
79 |
80 | ## Optional Inputs
81 |
82 | The following input variables are optional (have default values):
83 |
84 | ### [enable\_telemetry](#input\_enable\_telemetry)
85 |
86 | Description: This variable controls whether or not telemetry is enabled for the module.
87 | For more information see https://aka.ms/avm/telemetryinfo.
88 | If it is set to false, then no telemetry will be collected.
89 |
90 | Type: `bool`
91 |
92 | Default: `true`
93 |
94 | ## Outputs
95 |
96 | No outputs.
97 |
98 | ## Modules
99 |
100 | The following Modules are called:
101 |
102 | ### [firewall\_policy](#module\_firewall\_policy)
103 |
104 | Source: ../..
105 |
106 | Version:
107 |
108 | ### [naming](#module\_naming)
109 |
110 | Source: Azure/naming/azurerm
111 |
112 | Version: 0.3.0
113 |
114 |
115 | ## Data Collection
116 |
117 | 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. 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.
118 |
--------------------------------------------------------------------------------
/modules/rule_collection_groups/main.tf:
--------------------------------------------------------------------------------
1 | resource "azurerm_firewall_policy_rule_collection_group" "this" {
2 | firewall_policy_id = var.firewall_policy_rule_collection_group_firewall_policy_id
3 | name = var.firewall_policy_rule_collection_group_name
4 | priority = var.firewall_policy_rule_collection_group_priority
5 |
6 | dynamic "application_rule_collection" {
7 | for_each = var.firewall_policy_rule_collection_group_application_rule_collection == null ? [] : var.firewall_policy_rule_collection_group_application_rule_collection
8 |
9 | content {
10 | action = application_rule_collection.value.action
11 | name = application_rule_collection.value.name
12 | priority = application_rule_collection.value.priority
13 |
14 | dynamic "rule" {
15 | for_each = application_rule_collection.value.rule
16 |
17 | content {
18 | name = rule.value.name
19 | description = rule.value.description
20 | destination_addresses = rule.value.destination_addresses
21 | destination_fqdn_tags = rule.value.destination_fqdn_tags
22 | destination_fqdns = rule.value.destination_fqdns
23 | destination_urls = rule.value.destination_urls
24 | source_addresses = rule.value.source_addresses
25 | source_ip_groups = rule.value.source_ip_groups
26 | terminate_tls = rule.value.terminate_tls
27 | web_categories = rule.value.web_categories
28 |
29 | dynamic "http_headers" {
30 | for_each = rule.value.http_headers == null ? [] : rule.value.http_headers
31 |
32 | content {
33 | name = http_headers.value.name
34 | value = http_headers.value.value
35 | }
36 | }
37 | dynamic "protocols" {
38 | for_each = rule.value.protocols == null ? [] : rule.value.protocols
39 |
40 | content {
41 | port = protocols.value.port
42 | type = protocols.value.type
43 | }
44 | }
45 | }
46 | }
47 | }
48 | }
49 | dynamic "nat_rule_collection" {
50 | for_each = var.firewall_policy_rule_collection_group_nat_rule_collection == null ? [] : var.firewall_policy_rule_collection_group_nat_rule_collection
51 |
52 | content {
53 | action = nat_rule_collection.value.action
54 | name = nat_rule_collection.value.name
55 | priority = nat_rule_collection.value.priority
56 |
57 | dynamic "rule" {
58 | for_each = nat_rule_collection.value.rule
59 |
60 | content {
61 | name = rule.value.name
62 | protocols = rule.value.protocols
63 | translated_port = rule.value.translated_port
64 | destination_address = rule.value.destination_address
65 | destination_ports = rule.value.destination_ports
66 | source_addresses = rule.value.source_addresses
67 | source_ip_groups = rule.value.source_ip_groups
68 | translated_address = rule.value.translated_address
69 | translated_fqdn = rule.value.translated_fqdn
70 | }
71 | }
72 | }
73 | }
74 | dynamic "network_rule_collection" {
75 | for_each = var.firewall_policy_rule_collection_group_network_rule_collection == null ? [] : var.firewall_policy_rule_collection_group_network_rule_collection
76 |
77 | content {
78 | action = network_rule_collection.value.action
79 | name = network_rule_collection.value.name
80 | priority = network_rule_collection.value.priority
81 |
82 | dynamic "rule" {
83 | for_each = network_rule_collection.value.rule
84 |
85 | content {
86 | destination_ports = rule.value.destination_ports
87 | name = rule.value.name
88 | protocols = rule.value.protocols
89 | destination_addresses = rule.value.destination_addresses
90 | destination_fqdns = rule.value.destination_fqdns
91 | destination_ip_groups = rule.value.destination_ip_groups
92 | source_addresses = rule.value.source_addresses
93 | source_ip_groups = rule.value.source_ip_groups
94 | }
95 | }
96 | }
97 | }
98 | dynamic "timeouts" {
99 | for_each = var.firewall_policy_rule_collection_group_timeouts == null ? [] : [var.firewall_policy_rule_collection_group_timeouts]
100 |
101 | content {
102 | create = timeouts.value.create
103 | delete = timeouts.value.delete
104 | read = timeouts.value.read
105 | update = timeouts.value.update
106 | }
107 | }
108 | }
--------------------------------------------------------------------------------
/avm:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -e
4 |
5 | usage () {
6 | echo "Usage: avm "
7 | }
8 |
9 | # We need to do this because bash doesn't like it when a script is updated in place.
10 | if [ -z ${AVM_SCRIPT_FORKED} ]; then
11 | # If AVM_SCRIPT_FORKED is not set, we are running the script from the original repository
12 | # Set AVM_SCRIPT_FORKED to true to avoid running this block again
13 | export AVM_SCRIPT_FORKED=true
14 |
15 | # Make a copy of this script in the current directory
16 | # and run that copy.
17 | cp "$0" .avm
18 | chmod +x .avm
19 | exec ./.avm "$@"
20 | fi
21 |
22 | # Default values for environment variables
23 | CONTAINER_RUNTIME=${CONTAINER_RUNTIME:-"docker"}
24 | CONTAINER_IMAGE=${CONTAINER_IMAGE:-"mcr.microsoft.com/azterraform:avm-latest"}
25 | CONTAINER_PULL_POLICY=${CONTAINER_PULL_POLICY:-"always"}
26 | AVM_MAKEFILE_REF=${AVM_MAKEFILE_REF:-"main"}
27 | AVM_PORCH_REF=${AVM_PORCH_REF:-"main"}
28 |
29 | if [ ! "$(command -v "${CONTAINER_RUNTIME}")" ] && [ -z "${AVM_IN_CONTAINER}" ]; then
30 | echo "Error: ${CONTAINER_RUNTIME} is not installed. Please install ${CONTAINER_RUNTIME} first."
31 | exit 1
32 | fi
33 |
34 | if [ -z "$1" ]; then
35 | echo "Error: Please provide a make target. See https://github.com/Azure/avm-terraform-governance/blob/main/Makefile for available targets."
36 | echo
37 | usage
38 | exit 1
39 | fi
40 |
41 | # Check if AZURE_CONFIG_DIR is set, if not, set it to ~/.azure
42 | if [ -z "${AZURE_CONFIG_DIR}" ]; then
43 | AZURE_CONFIG_DIR="${HOME}/.azure"
44 | fi
45 |
46 | # Check if AZURE_CONFIG_DIR exists, if it does, mount it to the container
47 | if [ -d "${AZURE_CONFIG_DIR}" ]; then
48 | AZURE_CONFIG_MOUNT="-v ${AZURE_CONFIG_DIR}:/home/runtimeuser/.azure"
49 | fi
50 |
51 | # If the host Docker socket exists, mount it into the container so the container can talk to the host docker daemon
52 | if [ -S /var/run/docker.sock ]; then
53 | DOCKER_SOCK_MOUNT="-v /var/run/docker.sock:/var/run/docker.sock"
54 | fi
55 |
56 | # If we are in GitHub Copilot Coding Agent, we need to mount the SSL certificates from the host
57 | SSL_CERT_MOUNTS=""
58 | if [ -n "${COPILOT_AGENT_ACTION}" ]; then
59 | # Mount host's CA bundle to container's expected paths
60 | SSL_CERT_MOUNTS="${SSL_CERT_MOUNTS} -v /etc/ssl/certs/ca-certificates.crt:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro"
61 | SSL_CERT_MOUNTS="${SSL_CERT_MOUNTS} -v /etc/ssl/certs/ca-certificates.crt:/etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt:ro"
62 | fi
63 |
64 | # New: allow overriding TUI behavior with PORCH_FORCE_TUI and PORCH_NO_TUI environment variables.
65 | # - If PORCH_FORCE_TUI is set, force TUI and interactive mode (even in GH Actions).
66 | # - If PORCH_NO_TUI is set, explicitly disable TUI.
67 | # - Otherwise, fallback to previous behavior: enable TUI only when not in GitHub Actions and NO_COLOR is not set.
68 | if [ -n "${PORCH_FORCE_TUI}" ]; then
69 | TUI="--tui"
70 | DOCKER_INTERACTIVE="-it"
71 | export FORCE_COLOR=1
72 | elif [ -n "${PORCH_NO_TUI}" ]; then
73 | # Explicitly disable TUI and interactive flags
74 | TUI=""
75 | DOCKER_INTERACTIVE=""
76 | else
77 | # If we are not in GitHub Actions and NO_COLOR is not set, we want to use TUI and interactive mode
78 | if [ -z "${GITHUB_RUN_ID}" ] && [ -z "${NO_COLOR}" ]; then
79 | TUI="--tui"
80 | DOCKER_INTERACTIVE="-it"
81 | export FORCE_COLOR=1
82 | fi
83 | fi
84 |
85 | # if AVM_PORCH_BASE_URL is set, we want to add it to the make command
86 | if [ -n "${AVM_PORCH_BASE_URL}" ]; then
87 | PORCH_BASE_URL_MAKE_ADD="PORCH_BASE_URL=${AVM_PORCH_BASE_URL}"
88 | fi
89 |
90 | # Check if we are running in a container
91 | # If we are then just run make directly
92 | if [ -z "${AVM_IN_CONTAINER}" ]; then
93 | ${CONTAINER_RUNTIME} run \
94 | --pull "${CONTAINER_PULL_POLICY}" \
95 | --user "$(id -u):$(id -g)" \
96 | --rm \
97 | ${DOCKER_INTERACTIVE} \
98 | -v "$(pwd)":/src \
99 | ${AZURE_CONFIG_MOUNT:-} \
100 | ${DOCKER_SOCK_MOUNT:-} \
101 | ${SSL_CERT_MOUNTS:-} \
102 | -e ARM_CLIENT_ID \
103 | -e ARM_OIDC_REQUEST_TOKEN \
104 | -e ARM_OIDC_REQUEST_URL \
105 | -e ARM_SUBSCRIPTION_ID \
106 | -e ARM_TENANT_ID \
107 | -e ARM_USE_OIDC \
108 | -e FORCE_COLOR \
109 | -e GITHUB_TOKEN \
110 | -e NO_COLOR \
111 | -e PORCH_LOG_LEVEL \
112 | -e TF_IN_AUTOMATION=1 \
113 | --env-file <(env | grep '^TF_VAR_') \
114 | --env-file <(env | grep '^AVM_') \
115 | "${CONTAINER_IMAGE}" \
116 | make \
117 | TUI="${TUI}" \
118 | AVM_MAKEFILE_REF="${AVM_MAKEFILE_REF}" \
119 | "${PORCH_BASE_URL_MAKE_ADD}" \
120 | AVM_PORCH_REF="${AVM_PORCH_REF}" \
121 | "$1"
122 | else
123 | make TUI="${TUI}" AVM_MAKEFILE_REF="${AVM_MAKEFILE_REF}" ${PORCH_BASE_URL_MAKE_ADD} AVM_PORCH_REF="${AVM_PORCH_REF}" "$1"
124 | fi
125 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_ipgroups/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.3.0"
3 |
4 | required_providers {
5 | azurerm = {
6 | source = "hashicorp/azurerm"
7 | version = ">= 3.71, < 5.0.0"
8 | }
9 | random = {
10 | source = "hashicorp/random"
11 | version = ">= 3.5.0, < 4.0.0"
12 | }
13 | }
14 | }
15 |
16 | provider "azurerm" {
17 | features {}
18 | }
19 |
20 | # This picks a random region from the list of regions.
21 | resource "random_integer" "region_index" {
22 | max = length(local.azure_regions) - 1
23 | min = 0
24 | }
25 |
26 | # This ensures we have unique CAF compliant names for our resources.
27 | module "naming" {
28 | source = "Azure/naming/azurerm"
29 | version = "0.3.0"
30 | }
31 |
32 | # This is required for resource modules
33 | resource "azurerm_resource_group" "rg" {
34 | location = local.azure_regions[random_integer.region_index.result]
35 | name = module.naming.resource_group.name_unique
36 | }
37 |
38 | module "vnet" {
39 | source = "Azure/avm-res-network-virtualnetwork/azurerm"
40 | version = "0.16.0"
41 |
42 | location = azurerm_resource_group.rg.location
43 | parent_id = azurerm_resource_group.rg.id
44 | address_space = ["10.1.0.0/16"]
45 | enable_telemetry = var.enable_telemetry
46 | name = module.naming.virtual_network.name_unique
47 | }
48 |
49 | resource "azurerm_subnet" "subnet" {
50 | address_prefixes = ["10.1.0.0/26"]
51 | name = "AzureFirewallSubnet"
52 | resource_group_name = azurerm_resource_group.rg.name
53 | virtual_network_name = module.vnet.resource.name
54 | }
55 |
56 | resource "azurerm_public_ip" "pip" {
57 | allocation_method = "Static"
58 | location = azurerm_resource_group.rg.location
59 | name = "pip"
60 | resource_group_name = azurerm_resource_group.rg.name
61 | sku = "Standard"
62 | zones = ["1", "2", "3"]
63 | }
64 |
65 | resource "azurerm_ip_group" "ipgroup_1" {
66 | location = azurerm_resource_group.rg.location
67 | name = "ipgroup1"
68 | resource_group_name = azurerm_resource_group.rg.name
69 | cidrs = ["192.168.0.1", "172.16.240.0/20", "10.48.0.0/12"]
70 | }
71 |
72 | resource "azurerm_ip_group" "ipgroup_2" {
73 | location = azurerm_resource_group.rg.location
74 | name = "ipgroup2"
75 | resource_group_name = azurerm_resource_group.rg.name
76 | cidrs = ["10.100.10.0/24", "192.100.10.4", "10.150.20.20"]
77 | }
78 |
79 | # This is the module call
80 | module "firewall" {
81 | source = "Azure/avm-res-network-azurefirewall/azurerm"
82 | version = "0.4.0"
83 |
84 | firewall_sku_name = "AZFW_VNet"
85 | firewall_sku_tier = "Standard"
86 | location = azurerm_resource_group.rg.location
87 | name = module.naming.firewall.name
88 | resource_group_name = azurerm_resource_group.rg.name
89 | enable_telemetry = var.enable_telemetry
90 | firewall_ip_configuration = [
91 | {
92 | name = "ipconfig1"
93 | subnet_id = azurerm_subnet.subnet.id
94 | public_ip_address_id = azurerm_public_ip.pip.id
95 | }
96 | ]
97 | firewall_policy_id = module.firewall_policy.resource.id
98 | firewall_zones = ["1", "2", "3"]
99 | }
100 |
101 | module "firewall_policy" {
102 | source = "../.."
103 |
104 | location = azurerm_resource_group.rg.location
105 | name = module.naming.firewall_policy.name
106 | resource_group_name = azurerm_resource_group.rg.name
107 | enable_telemetry = var.enable_telemetry
108 | }
109 |
110 | module "rule_collection_group" {
111 | source = "../../modules/rule_collection_groups"
112 |
113 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
114 | firewall_policy_rule_collection_group_name = "IPGroupRCG"
115 | firewall_policy_rule_collection_group_priority = 400
116 | firewall_policy_rule_collection_group_application_rule_collection = [
117 | {
118 | action = "Allow"
119 | name = "ApplicationRuleCollection"
120 | priority = 201
121 | rule = [
122 | {
123 | name = "AllowMicrosoft"
124 | destination_fqdns = ["*.microsoft.com"]
125 | source_ip_groups = [azurerm_ip_group.ipgroup_2.id]
126 | protocols = [
127 | {
128 | port = 443
129 | type = "Https"
130 | }
131 | ]
132 | }
133 | ]
134 | }
135 | ]
136 | firewall_policy_rule_collection_group_network_rule_collection = [
137 | {
138 | action = "Allow"
139 | name = "NetworkRuleCollection"
140 | priority = 101
141 | rule = [
142 | {
143 | name = "OutboundToIPGroups"
144 | destination_ports = ["443"]
145 | destination_ip_groups = [azurerm_ip_group.ipgroup_1.id]
146 | source_ip_groups = [azurerm_ip_group.ipgroup_2.id]
147 | protocols = ["TCP"]
148 | }
149 | ]
150 | }
151 | ]
152 | }
153 |
--------------------------------------------------------------------------------
/avm.ps1:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env pwsh
2 |
3 | [CmdletBinding()]
4 | param(
5 | [Parameter(Position = 0, Mandatory = $true)]
6 | [string]$Target
7 | )
8 |
9 | Set-StrictMode -Version 3.0
10 | $ErrorActionPreference = "Stop"
11 |
12 | function Show-Usage {
13 | Write-Host "Usage: avm "
14 | }
15 |
16 | # Default values for environment variables
17 | $CONTAINER_RUNTIME = if ($env:CONTAINER_RUNTIME) { $env:CONTAINER_RUNTIME } else { "docker" }
18 | $CONTAINER_IMAGE = if ($env:CONTAINER_IMAGE) { $env:CONTAINER_IMAGE } else { "mcr.microsoft.com/azterraform:avm-latest" }
19 | $CONTAINER_PULL_POLICY = if ($env:CONTAINER_PULL_POLICY) { $env:CONTAINER_PULL_POLICY } else { "always" }
20 | $MAKEFILE_REF = if ($env:MAKEFILE_REF) { $env:MAKEFILE_REF } else { "main" }
21 | $PORCH_REF = if ($env:PORCH_REF) { $env:PORCH_REF } else { "main" }
22 |
23 | # Check if container runtime is available
24 | if (-not (Get-Command $CONTAINER_RUNTIME -ErrorAction SilentlyContinue) -and -not $env:AVM_IN_CONTAINER) {
25 | Write-Error "Error: $CONTAINER_RUNTIME is not installed. Please install $CONTAINER_RUNTIME first."
26 | exit 1
27 | }
28 |
29 | # Check if AZURE_CONFIG_DIR is set, if not, set it to ~/.azure
30 | $AZURE_CONFIG_DIR = if ($env:AZURE_CONFIG_DIR) {
31 | $env:AZURE_CONFIG_DIR
32 | }
33 | else {
34 | if ($IsWindows) {
35 | Join-Path $env:USERPROFILE ".azure"
36 | }
37 | else {
38 | Join-Path $env:HOME ".azure"
39 | }
40 | }
41 |
42 | # Check if AZURE_CONFIG_DIR exists, if it does, mount it to the container
43 | $AZURE_CONFIG_MOUNT = $null
44 | $AZURE_CONFIG_MOUNT_PATH = $null
45 | if (Test-Path $AZURE_CONFIG_DIR) {
46 | $AZURE_CONFIG_MOUNT = "-v"
47 | $AZURE_CONFIG_MOUNT_PATH = "${AZURE_CONFIG_DIR}:/home/runtimeuser/.azure"
48 | }
49 |
50 | # New: allow overriding TUI behavior with PORCH_FORCE_TUI and PORCH_NO_TUI environment variables.
51 | # - If PORCH_FORCE_TUI is set, force TUI and interactive mode (even in GH Actions).
52 | # - If PORCH_NO_TUI is set, explicitly disable TUI.
53 | # - Otherwise, fallback to previous behavior: enable TUI only when not in GitHub Actions and NO_COLOR is not set.
54 | $TUI = $null
55 | $DOCKER_INTERACTIVE = $null
56 | if ($env:PORCH_FORCE_TUI -and $env:PORCH_FORCE_TUI -ne "") {
57 | $TUI = "--tui"
58 | $DOCKER_INTERACTIVE = "-it"
59 | $env:FORCE_COLOR = "1"
60 | }
61 | elseif ($env:PORCH_NO_TUI -and $env:PORCH_NO_TUI -ne "") {
62 | # Explicitly disable TUI and interactive flags
63 | $TUI = $null
64 | $DOCKER_INTERACTIVE = $null
65 | }
66 | else {
67 | # If we are not in GitHub Actions and NO_COLOR is not set, we want to use TUI and interactive mode
68 | if (-not $env:GITHUB_RUN_ID -and -not $env:NO_COLOR) {
69 | $TUI = "--tui"
70 | $DOCKER_INTERACTIVE = "-it"
71 | $env:FORCE_COLOR = "1"
72 | }
73 | }
74 |
75 | # if PORCH_BASE_URL is set, we want to add it to the make command
76 | $PORCH_BASE_URL_MAKE_ADD = $null
77 | if ($env:PORCH_BASE_URL) {
78 | $PORCH_BASE_URL_MAKE_ADD = "PORCH_BASE_URL=$($env:PORCH_BASE_URL)"
79 | }
80 |
81 | # Check if we are running in a container
82 | # If we are then just run make directly
83 | if (-not $env:AVM_IN_CONTAINER) {
84 | # Build the docker command arguments
85 | $dockerArgs = @(
86 | "run"
87 | "--pull", $CONTAINER_PULL_POLICY
88 | "--rm"
89 | )
90 |
91 | # Add user parameter only on Unix-like systems
92 | if (-not $IsWindows) {
93 | try {
94 | $userId = & id -u
95 | $groupId = & id -g
96 | $dockerArgs += @("--user", "${userId}:${groupId}")
97 | }
98 | catch {
99 | Write-Warning "Could not determine user/group ID, running without --user parameter"
100 | }
101 | }
102 |
103 | if ($DOCKER_INTERACTIVE) {
104 | $dockerArgs += $DOCKER_INTERACTIVE
105 | }
106 |
107 | $dockerArgs += @(
108 | "-v", "$(Get-Location):/src"
109 | )
110 |
111 | if ($AZURE_CONFIG_MOUNT -and $AZURE_CONFIG_MOUNT_PATH) {
112 | $dockerArgs += @($AZURE_CONFIG_MOUNT, $AZURE_CONFIG_MOUNT_PATH)
113 | }
114 |
115 | # Add environment variables
116 | $envVars = @(
117 | "ARM_CLIENT_ID",
118 | "ARM_OIDC_REQUEST_TOKEN",
119 | "ARM_OIDC_REQUEST_URL",
120 | "ARM_SUBSCRIPTION_ID",
121 | "ARM_TENANT_ID",
122 | "ARM_USE_OIDC",
123 | "AVM_EXAMPLE",
124 | "CONFTEST_APRL_URL",
125 | "CONFTEST_AVMSEC_URL",
126 | "CONFTEST_EXCEPTIONS_URL",
127 | "FORCE_COLOR",
128 | "GITHUB_TOKEN",
129 | "GREPT_URL",
130 | "MPTF_URL",
131 | "NO_COLOR",
132 | "PORCH_LOG_LEVEL",
133 | "TEST_TYPE",
134 | "TFLINT_CONFIG_URL"
135 | )
136 |
137 | foreach ($envVar in $envVars) {
138 | $envValue = [System.Environment]::GetEnvironmentVariable($envVar)
139 | if ($null -ne $envValue -and $envValue -ne "") {
140 | $dockerArgs += @("-e", $envVar)
141 | }
142 | }
143 |
144 | # Add TF_IN_AUTOMATION
145 | $dockerArgs += @("-e", "TF_IN_AUTOMATION=1")
146 |
147 | # Add TF_VAR_ environment variables
148 | Get-ChildItem env: | Where-Object { $_.Name -like "TF_VAR_*" } | ForEach-Object {
149 | $dockerArgs += @("-e", "$($_.Name)=$($_.Value)")
150 | }
151 |
152 | # Add AVM_ environment variables
153 | Get-ChildItem env: | Where-Object { $_.Name -like "AVM_*" } | ForEach-Object {
154 | $dockerArgs += @("-e", "$($_.Name)=$($_.Value)")
155 | }
156 |
157 | $dockerArgs += $CONTAINER_IMAGE
158 | $dockerArgs += "make"
159 |
160 | if ($TUI) {
161 | $dockerArgs += "TUI=$TUI"
162 | }
163 |
164 | $dockerArgs += "MAKEFILE_REF=$MAKEFILE_REF"
165 |
166 | if ($PORCH_BASE_URL_MAKE_ADD) {
167 | $dockerArgs += $PORCH_BASE_URL_MAKE_ADD
168 | }
169 |
170 | $dockerArgs += "PORCH_REF=$PORCH_REF"
171 | $dockerArgs += $Target
172 |
173 | & $CONTAINER_RUNTIME @dockerArgs
174 | }
175 | else {
176 | # Build make command arguments
177 | $makeArgs = @()
178 |
179 | if ($TUI) {
180 | $makeArgs += "TUI=$TUI"
181 | }
182 |
183 | $makeArgs += "MAKEFILE_REF=$MAKEFILE_REF"
184 |
185 | if ($PORCH_BASE_URL_MAKE_ADD) {
186 | $makeArgs += $PORCH_BASE_URL_MAKE_ADD
187 | }
188 |
189 | $makeArgs += "PORCH_REF=$PORCH_REF"
190 | $makeArgs += $Target
191 |
192 | & make @makeArgs
193 | }
194 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_rule_collection_group/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Deploy Azure Firewall Policy with Rule Collection Groups
4 |
5 | This example deploys Azure Firewall Policy with Rules Collection Groups
6 |
7 | - Firewall Policy
8 | - Rule Collection Groups
9 | - Rule Collections
10 | - Network and Application Rules
11 |
12 | ```hcl
13 | terraform {
14 | required_version = ">= 1.3.0"
15 |
16 | required_providers {
17 | azurerm = {
18 | source = "hashicorp/azurerm"
19 | version = ">= 3.71, < 5.0.0"
20 | }
21 | random = {
22 | source = "hashicorp/random"
23 | version = ">= 3.5.0, < 4.0.0"
24 | }
25 | }
26 | }
27 |
28 | provider "azurerm" {
29 | features {}
30 | }
31 |
32 | # This picks a random region from the list of regions.
33 | resource "random_integer" "region_index" {
34 | max = length(local.azure_regions) - 1
35 | min = 0
36 | }
37 |
38 | # This ensures we have unique CAF compliant names for our resources.
39 | module "naming" {
40 | source = "Azure/naming/azurerm"
41 | version = "0.3.0"
42 | }
43 |
44 | # This is required for resource modules
45 | resource "azurerm_resource_group" "this" {
46 | location = local.azure_regions[random_integer.region_index.result]
47 | name = module.naming.resource_group.name_unique
48 | }
49 |
50 | # This is the module call
51 | module "firewall_policy" {
52 | source = "../.."
53 |
54 | location = azurerm_resource_group.this.location
55 | name = module.naming.firewall_policy.name_unique
56 | resource_group_name = azurerm_resource_group.this.name
57 | # source = "Azure/avm-res-network-firewallpolicy/azurerm"
58 | enable_telemetry = var.enable_telemetry
59 | }
60 |
61 | module "rule_collection_group" {
62 | source = "../../modules/rule_collection_groups"
63 |
64 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
65 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
66 | firewall_policy_rule_collection_group_name = "NetworkRuleCollectionGroup"
67 | firewall_policy_rule_collection_group_priority = 400
68 | firewall_policy_rule_collection_group_application_rule_collection = [
69 | {
70 | action = "Allow"
71 | name = "ApplicationRuleCollection"
72 | priority = 600
73 | rule = [
74 | {
75 | name = "AllowAll"
76 | description = "Allow traffic to Microsoft.com"
77 | source_addresses = ["10.0.0.0/24"]
78 | protocols = [
79 | {
80 | port = 443
81 | type = "Https"
82 | }
83 | ]
84 | destination_fqdns = ["microsoft.com"]
85 | }
86 | ]
87 | }
88 | ]
89 | firewall_policy_rule_collection_group_network_rule_collection = [
90 | {
91 | action = "Allow"
92 | name = "NetworkRuleCollection"
93 | priority = 400
94 | rule = [
95 | {
96 | name = "OutboundToInternet"
97 | description = "Allow traffic outbound to the Internet"
98 | destination_addresses = ["0.0.0.0/0"]
99 | destination_ports = ["443"]
100 | source_addresses = ["10.0.0.0/24"]
101 | protocols = ["TCP"]
102 | }
103 | ]
104 | }
105 | ]
106 | }
107 | ```
108 |
109 |
110 | ## Requirements
111 |
112 | The following requirements are needed by this module:
113 |
114 | - [terraform](#requirement\_terraform) (>= 1.3.0)
115 |
116 | - [azurerm](#requirement\_azurerm) (>= 3.71, < 5.0.0)
117 |
118 | - [random](#requirement\_random) (>= 3.5.0, < 4.0.0)
119 |
120 | ## Resources
121 |
122 | The following resources are used by this module:
123 |
124 | - [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource)
125 | - [random_integer.region_index](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) (resource)
126 |
127 |
128 | ## Required Inputs
129 |
130 | No required inputs.
131 |
132 | ## Optional Inputs
133 |
134 | The following input variables are optional (have default values):
135 |
136 | ### [enable\_telemetry](#input\_enable\_telemetry)
137 |
138 | Description: This variable controls whether or not telemetry is enabled for the module.
139 | For more information see https://aka.ms/avm/telemetryinfo.
140 | If it is set to false, then no telemetry will be collected.
141 |
142 | Type: `bool`
143 |
144 | Default: `true`
145 |
146 | ## Outputs
147 |
148 | No outputs.
149 |
150 | ## Modules
151 |
152 | The following Modules are called:
153 |
154 | ### [firewall\_policy](#module\_firewall\_policy)
155 |
156 | Source: ../..
157 |
158 | Version:
159 |
160 | ### [naming](#module\_naming)
161 |
162 | Source: Azure/naming/azurerm
163 |
164 | Version: 0.3.0
165 |
166 | ### [rule\_collection\_group](#module\_rule\_collection\_group)
167 |
168 | Source: ../../modules/rule_collection_groups
169 |
170 | Version:
171 |
172 |
173 | ## Data Collection
174 |
175 | 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. 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.
176 |
--------------------------------------------------------------------------------
/.github/policies/eventResponder.yml:
--------------------------------------------------------------------------------
1 | id: avmEventResponder
2 | name: AVM Event Responder
3 | description: AVM Event Responder
4 | resource: repository
5 | disabled: false
6 |
7 | configuration:
8 | resourceManagementConfiguration:
9 | eventResponderTasks:
10 | - description: 'ITA06 - If a new issue or PR is opened add the "Needs: Triage :mag:" label'
11 | if:
12 | - or:
13 | - payloadType: Issues
14 | - payloadType: Pull_Request
15 | - isAction:
16 | action: Opened
17 | then:
18 | - addLabel:
19 | label: "Needs: Triage :mag:"
20 | - addReply:
21 | reply: |
22 | > [!IMPORTANT]
23 | > **The "Needs: Triage :mag:" label must be removed once the triage process is complete!**
24 |
25 | > [!TIP]
26 | > For additional guidance on how to triage this issue/PR, see the [Terraform Issue Triage](https://azure.github.io/Azure-Verified-Modules/help-support/issue-triage/terraform-issue-triage) documentation.
27 |
28 | - description: 'ITA09 - When #RR is used in an issue, add the "Needs: Author Feedback :ear:" label'
29 | if:
30 | - or:
31 | - payloadType: Pull_Request_Review_Comment
32 | - payloadType: Issue_Comment
33 | - commentContains:
34 | pattern: "#RR"
35 | - not:
36 | hasLabel:
37 | label: "Needs: Author Feedback :ear:"
38 | then:
39 | - addLabel:
40 | label: "Needs: Author Feedback :ear:"
41 |
42 | - description: 'ITA10 - When #wontfix is used in an issue, mark it by using the label of "Status: Won''t Fix :broken_heart:"'
43 | if:
44 | - or:
45 | - payloadType: Pull_Request_Review_Comment
46 | - payloadType: Issue_Comment
47 | - commentContains:
48 | pattern: "#wontfix"
49 | - not:
50 | hasLabel:
51 | label: "Status: Won't Fix :broken_heart:"
52 | then:
53 | - addLabel:
54 | label: "Status: Won't Fix :broken_heart:"
55 | - closeIssue
56 |
57 | - description: 'ITA11 - When the author replies, remove the "Needs: Author Feedback :ear:" label and label with "Needs: Attention :wave:"'
58 | if:
59 | - or:
60 | - payloadType: Pull_Request_Review_Comment
61 | - payloadType: Issue_Comment
62 | - not:
63 | isAction:
64 | action: Closed
65 | - hasLabel:
66 | label: "Needs: Author Feedback :ear:"
67 | - isActivitySender:
68 | issueAuthor: true
69 | then:
70 | - removeLabel:
71 | label: "Needs: Author Feedback :ear:"
72 | - removeLabel:
73 | label: "Status: No Recent Activity :zzz:"
74 | - addLabel:
75 | label: "Needs: Attention :wave:"
76 |
77 | - description: "ITA12 - Clean email replies on every comment"
78 | if:
79 | - payloadType: Issue_Comment
80 | then:
81 | - cleanEmailReply
82 |
83 | - description: 'ITA15 - remove the "Needs: Triage" label from a PR, if it already has a "Type: XYZ" label added at the time of creating it.'
84 | if:
85 | - payloadType: Pull_Request
86 | - isAction:
87 | action: Opened
88 | - or:
89 | - hasLabel:
90 | label: "Type: Bug :bug:"
91 | - hasLabel:
92 | label: "Type: Documentation :page_facing_up:"
93 | - hasLabel:
94 | label: "Type: Duplicate :palms_up_together:"
95 | - hasLabel:
96 | label: "Type: Feature Request :heavy_plus_sign:"
97 | - hasLabel:
98 | label: "Type: Hygiene :broom:"
99 | - hasLabel:
100 | label: "Type: New Module Proposal :bulb:"
101 | - hasLabel:
102 | label: "Type: Question/Feedback :raising_hand:"
103 | - hasLabel:
104 | label: "Type: Security Bug :lock:"
105 | - isAssignedToSomeone
106 | then:
107 | - removeLabel:
108 | label: "Needs: Triage :mag:"
109 |
110 | - description: 'ITA20 - If the type is feature request, assign the "Type: Feature Request :heavy_plus_sign:" label on the issue'
111 | if:
112 | - payloadType: Issues
113 | - isAction:
114 | action: Opened
115 | - bodyContains:
116 | pattern: |
117 | ### Issue Type?
118 |
119 | Feature Request
120 | - not:
121 | hasLabel:
122 | label: "Type: Feature Request :heavy_plus_sign:"
123 | then:
124 | - addLabel:
125 | label: "Type: Feature Request :heavy_plus_sign:"
126 |
127 | - description: 'ITA21 - If the type is bug, assign the "Type: Bug :bug:" label on the issue'
128 | if:
129 | - payloadType: Issues
130 | - isAction:
131 | action: Opened
132 | - bodyContains:
133 | pattern: |
134 | ### Issue Type?
135 |
136 | Bug
137 | - not:
138 | hasLabel:
139 | label: "Type: Bug :bug:"
140 | then:
141 | - addLabel:
142 | label: "Type: Bug :bug:"
143 |
144 | - description: 'ITA22 - If the type is security bug, assign the "Type: Security Bug :lock:" label on the issue'
145 | if:
146 | - payloadType: Issues
147 | - isAction:
148 | action: Opened
149 | - bodyContains:
150 | pattern: |
151 | ### Issue Type?
152 |
153 | Security Bug
154 | - not:
155 | hasLabel:
156 | label: "Type: Security Bug :lock:"
157 | then:
158 | - addLabel:
159 | label: "Type: Security Bug :lock:"
160 |
161 | - description: 'ITA23 - Remove the "Status: In PR" label from an issue when it''s closed.'
162 | if:
163 | - payloadType: Issues
164 | - isAction:
165 | action: Closed
166 | - hasLabel:
167 | label: "Status: In PR :point_right:"
168 | then:
169 | - removeLabel:
170 | label: "Status: In PR :point_right:"
171 |
--------------------------------------------------------------------------------
/modules/rule_collection_groups/variables.tf:
--------------------------------------------------------------------------------
1 | variable "firewall_policy_rule_collection_group_firewall_policy_id" {
2 | type = string
3 | description = "(Required) The ID of the Firewall Policy where the Firewall Policy Rule Collection Group should exist. Changing this forces a new Firewall Policy Rule Collection Group to be created."
4 | nullable = false
5 | }
6 |
7 | variable "firewall_policy_rule_collection_group_name" {
8 | type = string
9 | description = "(Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created."
10 | nullable = false
11 | }
12 |
13 | variable "firewall_policy_rule_collection_group_priority" {
14 | type = number
15 | description = "(Required) The priority of the Firewall Policy Rule Collection Group. The range is 100-65000."
16 | nullable = false
17 | }
18 |
19 | variable "firewall_policy_rule_collection_group_application_rule_collection" {
20 | type = list(object({
21 | action = string
22 | name = string
23 | priority = number
24 | rule = list(object({
25 | description = optional(string)
26 | destination_addresses = optional(list(string), [])
27 | destination_fqdn_tags = optional(list(string), [])
28 | destination_fqdns = optional(list(string), [])
29 | destination_urls = optional(list(string), [])
30 | name = string
31 | source_addresses = optional(list(string), [])
32 | source_ip_groups = optional(list(string), [])
33 | terminate_tls = optional(bool)
34 | web_categories = optional(list(string), [])
35 | http_headers = optional(list(object({
36 | name = string
37 | value = string
38 | })))
39 | protocols = optional(list(object({
40 | port = number
41 | type = string
42 | })))
43 | }))
44 | }))
45 | default = null
46 | description = <<-EOT
47 | - `action` - (Required) The action to take for the application rules in this collection. Possible values are `Allow` and `Deny`.
48 | - `name` - (Required) The name which should be used for this application rule collection.
49 | - `priority` - (Required) The priority of the application rule collection. The range is `100`
50 |
51 | ---
52 | `rule` block supports the following:
53 | - `description` -
54 | - `destination_addresses` -
55 | - `destination_fqdn_tags` -
56 | - `destination_fqdns` -
57 | - `destination_urls` -
58 | - `name` - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
59 | - `source_addresses` -
60 | - `source_ip_groups` -
61 | - `terminate_tls` -
62 | - `web_categories` -
63 |
64 | ---
65 | `http_headers` block supports the following:
66 | - `name` - (Required) Specifies the name of the header.
67 | - `value` - (Required) Specifies the value of the value.
68 |
69 | ---
70 | `protocols` block supports the following:
71 | - `port` - (Required) Port number of the protocol. Range is 0-64000.
72 | - `type` - (Required) Protocol type. Possible values are `Http` and `Https`.
73 | EOT
74 | }
75 |
76 | variable "firewall_policy_rule_collection_group_nat_rule_collection" {
77 | type = list(object({
78 | action = string
79 | name = string
80 | priority = number
81 | rule = list(object({
82 | description = optional(string)
83 | destination_address = optional(string)
84 | destination_ports = optional(list(string), [])
85 | name = string
86 | protocols = list(string)
87 | source_addresses = optional(list(string), [])
88 | source_ip_groups = optional(list(string), [])
89 | translated_address = optional(string)
90 | translated_fqdn = optional(string)
91 | translated_port = number
92 | }))
93 | }))
94 | default = null
95 | description = <<-EOT
96 | - `action` - (Required) The action to take for the NAT rules in this collection. Currently, the only possible value is `Dnat`.
97 | - `name` - (Required) The name which should be used for this NAT rule collection.
98 | - `priority` - (Required) The priority of the NAT rule collection. The range is `100`
99 |
100 | ---
101 | `rule` block supports the following:
102 | - `description` -
103 | - `destination_address` -
104 | - `destination_ports` -
105 | - `name` - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
106 | - `protocols` -
107 | - `source_addresses` -
108 | - `source_ip_groups` -
109 | - `translated_address` -
110 | - `translated_fqdn` -
111 | - `translated_port` -
112 | EOT
113 | }
114 |
115 | variable "firewall_policy_rule_collection_group_network_rule_collection" {
116 | type = list(object({
117 | action = string
118 | name = string
119 | priority = number
120 | rule = list(object({
121 | description = optional(string)
122 | destination_addresses = optional(list(string), [])
123 | destination_fqdns = optional(list(string), [])
124 | destination_ip_groups = optional(list(string), [])
125 | destination_ports = list(string)
126 | name = string
127 | protocols = list(string)
128 | source_addresses = optional(list(string), [])
129 | source_ip_groups = optional(list(string), [])
130 | }))
131 | }))
132 | default = null
133 | description = <<-EOT
134 | - `action` - (Required) The action to take for the network rules in this collection. Possible values are `Allow` and `Deny`.
135 | - `name` - (Required) The name which should be used for this network rule collection.
136 | - `priority` - (Required) The priority of the network rule collection. The range is `100`
137 |
138 | ---
139 | `rule` block supports the following:
140 | - `description` -
141 | - `destination_addresses` -
142 | - `destination_fqdns` -
143 | - `destination_ip_groups` -
144 | - `destination_ports` -
145 | - `name` - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
146 | - `protocols` -
147 | - `source_addresses` -
148 | - `source_ip_groups` -
149 | EOT
150 | }
151 |
152 | variable "firewall_policy_rule_collection_group_timeouts" {
153 | type = object({
154 | create = optional(string)
155 | delete = optional(string)
156 | read = optional(string)
157 | update = optional(string)
158 | })
159 | default = null
160 | description = <<-EOT
161 | - `create` - (Defaults to 30 minutes) Used when creating the Firewall Policy Rule Collection Group.
162 | - `delete` - (Defaults to 30 minutes) Used when deleting the Firewall Policy Rule Collection Group.
163 | - `read` - (Defaults to 5 minutes) Used when retrieving the Firewall Policy Rule Collection Group.
164 | - `update` - (Defaults to 30 minutes) Used when updating the Firewall Policy Rule Collection Group.
165 | EOT
166 | }
167 |
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | resource "azurerm_firewall_policy" "this" {
2 | location = var.location
3 | name = var.name
4 | resource_group_name = var.resource_group_name
5 | auto_learn_private_ranges_enabled = var.firewall_policy_auto_learn_private_ranges_enabled
6 | base_policy_id = var.firewall_policy_base_policy_id
7 | private_ip_ranges = var.firewall_policy_private_ip_ranges
8 | sku = var.firewall_policy_sku
9 | sql_redirect_allowed = var.firewall_policy_sql_redirect_allowed
10 | tags = var.tags
11 | threat_intelligence_mode = var.firewall_policy_threat_intelligence_mode
12 |
13 | dynamic "dns" {
14 | for_each = var.firewall_policy_dns == null ? [] : [var.firewall_policy_dns]
15 |
16 | content {
17 | proxy_enabled = dns.value.proxy_enabled
18 | servers = dns.value.servers
19 | }
20 | }
21 | dynamic "explicit_proxy" {
22 | for_each = var.firewall_policy_explicit_proxy == null ? [] : [var.firewall_policy_explicit_proxy]
23 |
24 | content {
25 | enable_pac_file = explicit_proxy.value.enable_pac_file
26 | enabled = explicit_proxy.value.enabled
27 | http_port = explicit_proxy.value.http_port
28 | https_port = explicit_proxy.value.https_port
29 | pac_file = explicit_proxy.value.pac_file
30 | pac_file_port = explicit_proxy.value.pac_file_port
31 | }
32 | }
33 | dynamic "identity" {
34 | for_each = var.firewall_policy_identity == null ? [] : [var.firewall_policy_identity]
35 |
36 | content {
37 | type = identity.value.type
38 | identity_ids = identity.value.identity_ids
39 | }
40 | }
41 | dynamic "insights" {
42 | for_each = var.firewall_policy_insights == null ? [] : [var.firewall_policy_insights]
43 |
44 | content {
45 | default_log_analytics_workspace_id = insights.value.default_log_analytics_workspace_id
46 | enabled = insights.value.enabled
47 | retention_in_days = insights.value.retention_in_days
48 |
49 | dynamic "log_analytics_workspace" {
50 | for_each = insights.value.log_analytics_workspace == null ? [] : insights.value.log_analytics_workspace
51 |
52 | content {
53 | firewall_location = log_analytics_workspace.value.firewall_location
54 | id = log_analytics_workspace.value.id
55 | }
56 | }
57 | }
58 | }
59 | dynamic "intrusion_detection" {
60 | for_each = var.firewall_policy_intrusion_detection == null ? [] : [var.firewall_policy_intrusion_detection]
61 |
62 | content {
63 | mode = intrusion_detection.value.mode
64 | private_ranges = intrusion_detection.value.private_ranges
65 |
66 | dynamic "signature_overrides" {
67 | for_each = intrusion_detection.value.signature_overrides == null ? [] : intrusion_detection.value.signature_overrides
68 |
69 | content {
70 | id = signature_overrides.value.id
71 | state = signature_overrides.value.state
72 | }
73 | }
74 | dynamic "traffic_bypass" {
75 | for_each = intrusion_detection.value.traffic_bypass == null ? [] : intrusion_detection.value.traffic_bypass
76 |
77 | content {
78 | name = traffic_bypass.value.name
79 | protocol = traffic_bypass.value.protocol
80 | description = traffic_bypass.value.description
81 | destination_addresses = traffic_bypass.value.destination_addresses
82 | destination_ip_groups = traffic_bypass.value.destination_ip_groups
83 | destination_ports = traffic_bypass.value.destination_ports
84 | source_addresses = traffic_bypass.value.source_addresses
85 | source_ip_groups = traffic_bypass.value.source_ip_groups
86 | }
87 | }
88 | }
89 | }
90 | dynamic "threat_intelligence_allowlist" {
91 | for_each = var.firewall_policy_threat_intelligence_allowlist == null ? [] : [var.firewall_policy_threat_intelligence_allowlist]
92 |
93 | content {
94 | fqdns = threat_intelligence_allowlist.value.fqdns
95 | ip_addresses = threat_intelligence_allowlist.value.ip_addresses
96 | }
97 | }
98 | dynamic "timeouts" {
99 | for_each = var.firewall_policy_timeouts == null ? [] : [var.firewall_policy_timeouts]
100 |
101 | content {
102 | create = timeouts.value.create
103 | delete = timeouts.value.delete
104 | read = timeouts.value.read
105 | update = timeouts.value.update
106 | }
107 | }
108 | dynamic "tls_certificate" {
109 | for_each = var.firewall_policy_tls_certificate == null ? [] : [var.firewall_policy_tls_certificate]
110 |
111 | content {
112 | key_vault_secret_id = tls_certificate.value.key_vault_secret_id
113 | name = tls_certificate.value.name
114 | }
115 | }
116 | }
117 |
118 | # Assigning Roles to the Virtual Network based on the provided configurations.
119 | resource "azurerm_role_assignment" "this" {
120 | for_each = var.role_assignments
121 |
122 | principal_id = each.value.principal_id
123 | scope = azurerm_firewall_policy.this.id
124 | condition = each.value.condition
125 | condition_version = each.value.condition_version
126 | delegated_managed_identity_resource_id = each.value.delegated_managed_identity_resource_id
127 | role_definition_id = strcontains(lower(each.value.role_definition_id_or_name), lower(local.role_definition_resource_substring)) ? each.value.role_definition_id_or_name : null
128 | role_definition_name = strcontains(lower(each.value.role_definition_id_or_name), lower(local.role_definition_resource_substring)) ? null : each.value.role_definition_id_or_name
129 | skip_service_principal_aad_check = each.value.skip_service_principal_aad_check
130 | }
131 |
132 | resource "azurerm_monitor_diagnostic_setting" "this" {
133 | for_each = var.diagnostic_settings
134 |
135 | name = each.value.name != null ? each.value.name : "diag-${var.name}"
136 | target_resource_id = azurerm_firewall_policy.this.id
137 | eventhub_authorization_rule_id = each.value.event_hub_authorization_rule_resource_id
138 | eventhub_name = each.value.event_hub_name
139 | log_analytics_destination_type = each.value.log_analytics_destination_type
140 | log_analytics_workspace_id = each.value.workspace_resource_id
141 | partner_solution_id = each.value.marketplace_partner_resource_id
142 | storage_account_id = each.value.storage_account_resource_id
143 |
144 | dynamic "enabled_log" {
145 | for_each = each.value.log_categories
146 |
147 | content {
148 | category = enabled_log.value
149 | }
150 | }
151 | dynamic "enabled_log" {
152 | for_each = each.value.log_groups
153 |
154 | content {
155 | category_group = enabled_log.value
156 | }
157 | }
158 | dynamic "metric" {
159 | for_each = each.value.metric_categories
160 |
161 | content {
162 | category = metric.value
163 | }
164 | }
165 | }
166 |
167 | # required AVM resources interfaces
168 | resource "azurerm_management_lock" "this" {
169 | count = var.lock != null ? 1 : 0
170 |
171 | lock_level = var.lock.kind
172 | name = coalesce(var.lock.name, "lock-${var.lock.kind}")
173 | scope = azurerm_firewall_policy.this.id # TODO: Replace with your azurerm resource name
174 | notes = var.lock.kind == "CanNotDelete" ? "Cannot delete the resource or its child resources." : "Cannot delete or modify the resource or its child resources."
175 | }
--------------------------------------------------------------------------------
/AGENTS.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: ' Azure Verified Modules (AVM) and Terraform'
3 | applyTo: '**/*.terraform, **/*.tf, **/*.tfvars, **/*.tfstate, **/*.tflint.hcl, **/*.tf.json, **/*.tfvars.json'
4 | ---
5 |
6 | # Azure Verified Modules (AVM) Terraform
7 |
8 | ## Overview
9 |
10 | Azure Verified Modules (AVM) are pre-built, tested, and validated Terraform and Bicep modules that follow Azure best practices. Use these modules to create, update, or review Azure Infrastructure as Code (IaC) with confidence.
11 |
12 | ## Custom Instructions for GitHub Copilot Agents
13 |
14 | **IMPORTANT**: When GitHub Copilot Agent or GitHub Copilot Coding Agent is working on this repository, the following local unit tests MUST be executed to comply with PR checks. Failure to run these tests will cause PR validation failures:
15 |
16 | ```bash
17 | PORCH_NO_TUI=1 ./avm pre-commit
18 | git add . && git commit -m "chore: avm pre-commit"
19 | PORCH_NO_TUI=1 ./avm pr-check
20 | ```
21 |
22 | These commands must be run before any pull request is created or updated to ensure compliance with the Azure Verified Modules standards and prevent CI/CD pipeline failures.
23 | More details on the AVM process can be found in the [Azure Verified Modules Contribution documentation](https://azure.github.io/Azure-Verified-Modules/contributing/terraform/testing/).
24 |
25 | **Failure to run these tests will cause PR validation failures and prevent successful merges.**
26 |
27 | ## Module Discovery
28 |
29 | ### Terraform Registry
30 |
31 | - Search for "avm" + resource name
32 | - Filter by "Partner" tag to find official AVM modules
33 | - Example: Search "avm storage account" → filter by Partner
34 |
35 | ### Official AVM Index
36 |
37 | - **Terraform Resources**: `https://azure.github.io/Azure-Verified-Modules/indexes/terraform/tf-resource-modules/`
38 | - **Terraform Patterns**: `https://azure.github.io/Azure-Verified-Modules/indexes/terraform/tf-pattern-modules/`
39 | - **Bicep Resources**: `https://azure.github.io/Azure-Verified-Modules/indexes/bicep/bicep-resource-modules/`
40 | - **Bicep Patterns**: `https://azure.github.io/Azure-Verified-Modules/indexes/bicep/bicep-pattern-modules/`
41 |
42 | ## Terraform Module Usage
43 |
44 | ### From Examples
45 |
46 | 1. Copy the example code from the module documentation
47 | 2. Replace `source = "../../"` with `source = "Azure/avm-res-{service}-{resource}/azurerm"`
48 | 3. Add `version = "1.0.0"` (use latest available)
49 | 4. Set `enable_telemetry = true`
50 |
51 | ### From Scratch
52 |
53 | 1. Copy the Provision Instructions from module documentation
54 | 2. Configure required and optional inputs
55 | 3. Pin the module version
56 | 4. Enable telemetry
57 |
58 | ### Example Usage
59 |
60 | ```hcl
61 | module "storage_account" {
62 | source = "Azure/avm-res-storage-storageaccount/azurerm"
63 | version = "0.1.0"
64 |
65 | enable_telemetry = true
66 | location = "East US"
67 | name = "mystorageaccount"
68 | resource_group_name = "my-rg"
69 |
70 | # Additional configuration...
71 | }
72 | ```
73 |
74 | ## Naming Conventions
75 |
76 | ### Module Types
77 |
78 | - **Resource Modules**: `Azure/avm-res-{service}-{resource}/azurerm`
79 | - Example: `Azure/avm-res-storage-storageaccount/azurerm`
80 | - **Pattern Modules**: `Azure/avm-ptn-{pattern}/azurerm`
81 | - Example: `Azure/avm-ptn-aks-enterprise/azurerm`
82 | - **Utility Modules**: `Azure/avm-utl-{utility}/azurerm`
83 | - Example: `Azure/avm-utl-regions/azurerm`
84 |
85 | ### Service Naming
86 |
87 | - Use kebab-case for services and resources
88 | - Follow Azure service names (e.g., `storage-storageaccount`, `network-virtualnetwork`)
89 |
90 | ## Version Management
91 |
92 | ### Check Available Versions
93 |
94 | - Endpoint: `https://registry.terraform.io/v1/modules/Azure/{module}/azurerm/versions`
95 | - Example: `https://registry.terraform.io/v1/modules/Azure/avm-res-storage-storageaccount/azurerm/versions`
96 |
97 | ### Version Pinning Best Practices
98 |
99 | - For providers: use pessimistic version constraints for minor version: `version = "~> 1.0"`
100 | - For modules: Pin to specific versions: `version = "1.2.3"`
101 |
102 | ## Module Sources
103 |
104 | ### Terraform Registry
105 |
106 | - **URL Pattern**: `https://registry.terraform.io/modules/Azure/{module}/azurerm/latest`
107 | - **Example**: `https://registry.terraform.io/modules/Azure/avm-res-storage-storageaccount/azurerm/latest`
108 |
109 | ### GitHub Repository
110 |
111 | - **URL Pattern**: `https://github.com/Azure/terraform-azurerm-avm-{type}-{service}-{resource}`
112 | - **Examples**:
113 | - Resource: `https://github.com/Azure/terraform-azurerm-avm-res-storage-storageaccount`
114 | - Pattern: `https://github.com/Azure/terraform-azurerm-avm-ptn-aks-enterprise`
115 |
116 | ## Development Best Practices
117 |
118 | ### Module Usage
119 |
120 | - ✅ **Always** pin module versions
121 | - ✅ **Start** with official examples from module documentation
122 | - ✅ **Review** all inputs and outputs before implementation
123 | - ✅ **Enable** telemetry: `enable_telemetry = true`
124 | - ✅ **Use** AVM utility modules for common patterns
125 |
126 | ### Code Quality
127 |
128 | - ✅ **Always** run `terraform fmt` after making changes
129 | - ✅ **Always** run `terraform validate` after making changes
130 | - ✅ **Use** meaningful variable names and descriptions
131 | - ✅ **Use** snake_case
132 | - ✅ **Add** proper tags and metadata
133 | - ✅ **Document** complex configurations
134 |
135 | ### Validation Requirements
136 |
137 | Before creating or updating any pull request:
138 |
139 | ```bash
140 | # Format code
141 | terraform fmt -recursive
142 |
143 | # Validate syntax
144 | terraform validate
145 |
146 | # AVM-specific validation (MANDATORY)
147 | export PORCH_NO_TUI=1
148 | ./avm pre-commit
149 |
150 | ./avm pr-check
151 | ```
152 |
153 | ## Tool Integration
154 |
155 | ### Use Available Tools
156 |
157 | - **Deployment Guidance**: Use `azure_get_deployment_best_practices` tool
158 | - **Service Documentation**: Use `microsoft.docs.mcp` tool for Azure service-specific guidance
159 | - **Schema Information**: Use `query_azapi_resource_schema` & `query_azapi_resource_document` to query AzAPI resources and schemas.
160 | - **Provider resources and resource schemas**: Use `list_terraform_provider_items` & `query_terraform_schema` to query azurerm resource schema.
161 |
162 | ### GitHub Copilot Integration
163 |
164 | When working with AVM repositories:
165 |
166 | 1. Always check for existing modules before creating new resources
167 | 2. Use the official examples as starting points
168 | 3. Run all validation tests before committing
169 | 4. Document any customizations or deviations from examples
170 |
171 | ## Common Patterns
172 |
173 | ### Resource Group Module
174 |
175 | ```hcl
176 | module "resource_group" {
177 | source = "Azure/avm-res-resources-resourcegroup/azurerm"
178 | version = "0.1.0" # use latest
179 |
180 | enable_telemetry = true
181 | location = var.location
182 | name = var.resource_group_name
183 | }
184 | ```
185 |
186 | ### Virtual Network Module
187 |
188 | ```hcl
189 | module "virtual_network" {
190 | source = "Azure/avm-res-network-virtualnetwork/azurerm"
191 | version = "0.1.0" # use latest
192 |
193 | enable_telemetry = true
194 | location = module.resource_group.location
195 | name = var.vnet_name
196 | resource_group_name = module.resource_group.name
197 | address_space = ["10.0.0.0/16"]
198 | }
199 | ```
200 |
201 | ## Troubleshooting
202 |
203 | ### Common Issues
204 |
205 | 1. **Version Conflicts**: Always check compatibility between module and provider versions
206 | 2. **Missing Dependencies**: Ensure all required resources are created first
207 | 3. **Validation Failures**: Run AVM validation tools before committing
208 | 4. **Documentation**: Always refer to the latest module documentation
209 |
210 | ### Support Resources
211 |
212 | - **AVM Documentation**: `https://azure.github.io/Azure-Verified-Modules/`
213 | - **GitHub Issues**: Report issues in the specific module's GitHub repository
214 | - **Community**: Azure Terraform Provider GitHub discussions
215 |
216 | ## Compliance Checklist
217 |
218 | Before submitting any AVM-related code:
219 |
220 | - [ ] Module version is pinned
221 | - [ ] Telemetry is enabled
222 | - [ ] Code is formatted (`terraform fmt`)
223 | - [ ] Code is validated (`terraform validate`)
224 | - [ ] AVM pre-commit checks pass (`./avm pre-commit`)
225 | - [ ] AVM PR checks pass (`./avm pr-check`)
226 | - [ ] Documentation is updated
227 | - [ ] Examples are tested and working
228 |
--------------------------------------------------------------------------------
/.github/copilot-instructions.md:
--------------------------------------------------------------------------------
1 | ---
2 | description: ' Azure Verified Modules (AVM) and Terraform'
3 | applyTo: '**/*.terraform, **/*.tf, **/*.tfvars, **/*.tfstate, **/*.tflint.hcl, **/*.tf.json, **/*.tfvars.json'
4 | ---
5 |
6 | # Azure Verified Modules (AVM) Terraform
7 |
8 | ## Overview
9 |
10 | Azure Verified Modules (AVM) are pre-built, tested, and validated Terraform and Bicep modules that follow Azure best practices. Use these modules to create, update, or review Azure Infrastructure as Code (IaC) with confidence.
11 |
12 | ## Custom Instructions for GitHub Copilot Agents
13 |
14 | **IMPORTANT**: When GitHub Copilot Agent or GitHub Copilot Coding Agent is working on this repository, the following local unit tests MUST be executed to comply with PR checks. Failure to run these tests will cause PR validation failures:
15 |
16 | ```bash
17 | PORCH_NO_TUI=1 ./avm pre-commit
18 | git add . && git commit -m "chore: avm pre-commit"
19 | PORCH_NO_TUI=1 ./avm pr-check
20 | ```
21 |
22 | These commands must be run before any pull request is created or updated to ensure compliance with the Azure Verified Modules standards and prevent CI/CD pipeline failures.
23 | More details on the AVM process can be found in the [Azure Verified Modules Contribution documentation](https://azure.github.io/Azure-Verified-Modules/contributing/terraform/testing/).
24 |
25 | **Failure to run these tests will cause PR validation failures and prevent successful merges.**
26 |
27 | ## Module Discovery
28 |
29 | ### Terraform Registry
30 |
31 | - Search for "avm" + resource name
32 | - Filter by "Partner" tag to find official AVM modules
33 | - Example: Search "avm storage account" → filter by Partner
34 |
35 | ### Official AVM Index
36 |
37 | - **Terraform Resources**: `https://azure.github.io/Azure-Verified-Modules/indexes/terraform/tf-resource-modules/`
38 | - **Terraform Patterns**: `https://azure.github.io/Azure-Verified-Modules/indexes/terraform/tf-pattern-modules/`
39 | - **Bicep Resources**: `https://azure.github.io/Azure-Verified-Modules/indexes/bicep/bicep-resource-modules/`
40 | - **Bicep Patterns**: `https://azure.github.io/Azure-Verified-Modules/indexes/bicep/bicep-pattern-modules/`
41 |
42 | ## Terraform Module Usage
43 |
44 | ### From Examples
45 |
46 | 1. Copy the example code from the module documentation
47 | 2. Replace `source = "../../"` with `source = "Azure/avm-res-{service}-{resource}/azurerm"`
48 | 3. Add `version = "1.0.0"` (use latest available)
49 | 4. Set `enable_telemetry = true`
50 |
51 | ### From Scratch
52 |
53 | 1. Copy the Provision Instructions from module documentation
54 | 2. Configure required and optional inputs
55 | 3. Pin the module version
56 | 4. Enable telemetry
57 |
58 | ### Example Usage
59 |
60 | ```hcl
61 | module "storage_account" {
62 | source = "Azure/avm-res-storage-storageaccount/azurerm"
63 | version = "0.1.0"
64 |
65 | enable_telemetry = true
66 | location = "East US"
67 | name = "mystorageaccount"
68 | resource_group_name = "my-rg"
69 |
70 | # Additional configuration...
71 | }
72 | ```
73 |
74 | ## Naming Conventions
75 |
76 | ### Module Types
77 |
78 | - **Resource Modules**: `Azure/avm-res-{service}-{resource}/azurerm`
79 | - Example: `Azure/avm-res-storage-storageaccount/azurerm`
80 | - **Pattern Modules**: `Azure/avm-ptn-{pattern}/azurerm`
81 | - Example: `Azure/avm-ptn-aks-enterprise/azurerm`
82 | - **Utility Modules**: `Azure/avm-utl-{utility}/azurerm`
83 | - Example: `Azure/avm-utl-regions/azurerm`
84 |
85 | ### Service Naming
86 |
87 | - Use kebab-case for services and resources
88 | - Follow Azure service names (e.g., `storage-storageaccount`, `network-virtualnetwork`)
89 |
90 | ## Version Management
91 |
92 | ### Check Available Versions
93 |
94 | - Endpoint: `https://registry.terraform.io/v1/modules/Azure/{module}/azurerm/versions`
95 | - Example: `https://registry.terraform.io/v1/modules/Azure/avm-res-storage-storageaccount/azurerm/versions`
96 |
97 | ### Version Pinning Best Practices
98 |
99 | - For providers: use pessimistic version constraints for minor version: `version = "~> 1.0"`
100 | - For modules: Pin to specific versions: `version = "1.2.3"`
101 |
102 | ## Module Sources
103 |
104 | ### Terraform Registry
105 |
106 | - **URL Pattern**: `https://registry.terraform.io/modules/Azure/{module}/azurerm/latest`
107 | - **Example**: `https://registry.terraform.io/modules/Azure/avm-res-storage-storageaccount/azurerm/latest`
108 |
109 | ### GitHub Repository
110 |
111 | - **URL Pattern**: `https://github.com/Azure/terraform-azurerm-avm-{type}-{service}-{resource}`
112 | - **Examples**:
113 | - Resource: `https://github.com/Azure/terraform-azurerm-avm-res-storage-storageaccount`
114 | - Pattern: `https://github.com/Azure/terraform-azurerm-avm-ptn-aks-enterprise`
115 |
116 | ## Development Best Practices
117 |
118 | ### Module Usage
119 |
120 | - ✅ **Always** pin module versions
121 | - ✅ **Start** with official examples from module documentation
122 | - ✅ **Review** all inputs and outputs before implementation
123 | - ✅ **Enable** telemetry: `enable_telemetry = true`
124 | - ✅ **Use** AVM utility modules for common patterns
125 |
126 | ### Code Quality
127 |
128 | - ✅ **Always** run `terraform fmt` after making changes
129 | - ✅ **Always** run `terraform validate` after making changes
130 | - ✅ **Use** meaningful variable names and descriptions
131 | - ✅ **Use** snake_case
132 | - ✅ **Add** proper tags and metadata
133 | - ✅ **Document** complex configurations
134 |
135 | ### Validation Requirements
136 |
137 | Before creating or updating any pull request:
138 |
139 | ```bash
140 | # Format code
141 | terraform fmt -recursive
142 |
143 | # Validate syntax
144 | terraform validate
145 |
146 | # AVM-specific validation (MANDATORY)
147 | export PORCH_NO_TUI=1
148 | ./avm pre-commit
149 |
150 | ./avm pr-check
151 | ```
152 |
153 | ## Tool Integration
154 |
155 | ### Use Available Tools
156 |
157 | - **Deployment Guidance**: Use `azure_get_deployment_best_practices` tool
158 | - **Service Documentation**: Use `microsoft.docs.mcp` tool for Azure service-specific guidance
159 | - **Schema Information**: Use `query_azapi_resource_schema` & `query_azapi_resource_document` to query AzAPI resources and schemas.
160 | - **Provider resources and resource schemas**: Use `list_terraform_provider_items` & `query_terraform_schema` to query azurerm resource schema.
161 |
162 | ### GitHub Copilot Integration
163 |
164 | When working with AVM repositories:
165 |
166 | 1. Always check for existing modules before creating new resources
167 | 2. Use the official examples as starting points
168 | 3. Run all validation tests before committing
169 | 4. Document any customizations or deviations from examples
170 |
171 | ## Common Patterns
172 |
173 | ### Resource Group Module
174 |
175 | ```hcl
176 | module "resource_group" {
177 | source = "Azure/avm-res-resources-resourcegroup/azurerm"
178 | version = "0.1.0" # use latest
179 |
180 | enable_telemetry = true
181 | location = var.location
182 | name = var.resource_group_name
183 | }
184 | ```
185 |
186 | ### Virtual Network Module
187 |
188 | ```hcl
189 | module "virtual_network" {
190 | source = "Azure/avm-res-network-virtualnetwork/azurerm"
191 | version = "0.1.0" # use latest
192 |
193 | enable_telemetry = true
194 | location = module.resource_group.location
195 | name = var.vnet_name
196 | resource_group_name = module.resource_group.name
197 | address_space = ["10.0.0.0/16"]
198 | }
199 | ```
200 |
201 | ## Troubleshooting
202 |
203 | ### Common Issues
204 |
205 | 1. **Version Conflicts**: Always check compatibility between module and provider versions
206 | 2. **Missing Dependencies**: Ensure all required resources are created first
207 | 3. **Validation Failures**: Run AVM validation tools before committing
208 | 4. **Documentation**: Always refer to the latest module documentation
209 |
210 | ### Support Resources
211 |
212 | - **AVM Documentation**: `https://azure.github.io/Azure-Verified-Modules/`
213 | - **GitHub Issues**: Report issues in the specific module's GitHub repository
214 | - **Community**: Azure Terraform Provider GitHub discussions
215 |
216 | ## Compliance Checklist
217 |
218 | Before submitting any AVM-related code:
219 |
220 | - [ ] Module version is pinned
221 | - [ ] Telemetry is enabled
222 | - [ ] Code is formatted (`terraform fmt`)
223 | - [ ] Code is validated (`terraform validate`)
224 | - [ ] AVM pre-commit checks pass (`./avm pre-commit`)
225 | - [ ] AVM PR checks pass (`./avm pr-check`)
226 | - [ ] Documentation is updated
227 | - [ ] Examples are tested and working
228 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_with_ipgroups/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Deploy Firewall Policy with IP Groups
4 |
5 | This deploys an Azure Firewall Policy with IP Groups in the rules
6 |
7 | - Firewall
8 | - Firewall Policy
9 | - Rule Collection Groups
10 | - Rule Collections
11 | - Network and Application Rules
12 | - IP Groups
13 |
14 | ```hcl
15 | terraform {
16 | required_version = ">= 1.3.0"
17 |
18 | required_providers {
19 | azurerm = {
20 | source = "hashicorp/azurerm"
21 | version = ">= 3.71, < 5.0.0"
22 | }
23 | random = {
24 | source = "hashicorp/random"
25 | version = ">= 3.5.0, < 4.0.0"
26 | }
27 | }
28 | }
29 |
30 | provider "azurerm" {
31 | features {}
32 | }
33 |
34 | # This picks a random region from the list of regions.
35 | resource "random_integer" "region_index" {
36 | max = length(local.azure_regions) - 1
37 | min = 0
38 | }
39 |
40 | # This ensures we have unique CAF compliant names for our resources.
41 | module "naming" {
42 | source = "Azure/naming/azurerm"
43 | version = "0.3.0"
44 | }
45 |
46 | # This is required for resource modules
47 | resource "azurerm_resource_group" "rg" {
48 | location = local.azure_regions[random_integer.region_index.result]
49 | name = module.naming.resource_group.name_unique
50 | }
51 |
52 | module "vnet" {
53 | source = "Azure/avm-res-network-virtualnetwork/azurerm"
54 | version = "0.16.0"
55 |
56 | location = azurerm_resource_group.rg.location
57 | parent_id = azurerm_resource_group.rg.id
58 | address_space = ["10.1.0.0/16"]
59 | enable_telemetry = var.enable_telemetry
60 | name = module.naming.virtual_network.name_unique
61 | }
62 |
63 | resource "azurerm_subnet" "subnet" {
64 | address_prefixes = ["10.1.0.0/26"]
65 | name = "AzureFirewallSubnet"
66 | resource_group_name = azurerm_resource_group.rg.name
67 | virtual_network_name = module.vnet.resource.name
68 | }
69 |
70 | resource "azurerm_public_ip" "pip" {
71 | allocation_method = "Static"
72 | location = azurerm_resource_group.rg.location
73 | name = "pip"
74 | resource_group_name = azurerm_resource_group.rg.name
75 | sku = "Standard"
76 | zones = ["1", "2", "3"]
77 | }
78 |
79 | resource "azurerm_ip_group" "ipgroup_1" {
80 | location = azurerm_resource_group.rg.location
81 | name = "ipgroup1"
82 | resource_group_name = azurerm_resource_group.rg.name
83 | cidrs = ["192.168.0.1", "172.16.240.0/20", "10.48.0.0/12"]
84 | }
85 |
86 | resource "azurerm_ip_group" "ipgroup_2" {
87 | location = azurerm_resource_group.rg.location
88 | name = "ipgroup2"
89 | resource_group_name = azurerm_resource_group.rg.name
90 | cidrs = ["10.100.10.0/24", "192.100.10.4", "10.150.20.20"]
91 | }
92 |
93 | # This is the module call
94 | module "firewall" {
95 | source = "Azure/avm-res-network-azurefirewall/azurerm"
96 | version = "0.4.0"
97 |
98 | firewall_sku_name = "AZFW_VNet"
99 | firewall_sku_tier = "Standard"
100 | location = azurerm_resource_group.rg.location
101 | name = module.naming.firewall.name
102 | resource_group_name = azurerm_resource_group.rg.name
103 | enable_telemetry = var.enable_telemetry
104 | firewall_ip_configuration = [
105 | {
106 | name = "ipconfig1"
107 | subnet_id = azurerm_subnet.subnet.id
108 | public_ip_address_id = azurerm_public_ip.pip.id
109 | }
110 | ]
111 | firewall_policy_id = module.firewall_policy.resource.id
112 | firewall_zones = ["1", "2", "3"]
113 | }
114 |
115 | module "firewall_policy" {
116 | source = "../.."
117 |
118 | location = azurerm_resource_group.rg.location
119 | name = module.naming.firewall_policy.name
120 | resource_group_name = azurerm_resource_group.rg.name
121 | enable_telemetry = var.enable_telemetry
122 | }
123 |
124 | module "rule_collection_group" {
125 | source = "../../modules/rule_collection_groups"
126 |
127 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
128 | firewall_policy_rule_collection_group_name = "IPGroupRCG"
129 | firewall_policy_rule_collection_group_priority = 400
130 | firewall_policy_rule_collection_group_application_rule_collection = [
131 | {
132 | action = "Allow"
133 | name = "ApplicationRuleCollection"
134 | priority = 201
135 | rule = [
136 | {
137 | name = "AllowMicrosoft"
138 | destination_fqdns = ["*.microsoft.com"]
139 | source_ip_groups = [azurerm_ip_group.ipgroup_2.id]
140 | protocols = [
141 | {
142 | port = 443
143 | type = "Https"
144 | }
145 | ]
146 | }
147 | ]
148 | }
149 | ]
150 | firewall_policy_rule_collection_group_network_rule_collection = [
151 | {
152 | action = "Allow"
153 | name = "NetworkRuleCollection"
154 | priority = 101
155 | rule = [
156 | {
157 | name = "OutboundToIPGroups"
158 | destination_ports = ["443"]
159 | destination_ip_groups = [azurerm_ip_group.ipgroup_1.id]
160 | source_ip_groups = [azurerm_ip_group.ipgroup_2.id]
161 | protocols = ["TCP"]
162 | }
163 | ]
164 | }
165 | ]
166 | }
167 | ```
168 |
169 |
170 | ## Requirements
171 |
172 | The following requirements are needed by this module:
173 |
174 | - [terraform](#requirement\_terraform) (>= 1.3.0)
175 |
176 | - [azurerm](#requirement\_azurerm) (>= 3.71, < 5.0.0)
177 |
178 | - [random](#requirement\_random) (>= 3.5.0, < 4.0.0)
179 |
180 | ## Resources
181 |
182 | The following resources are used by this module:
183 |
184 | - [azurerm_ip_group.ipgroup_1](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/ip_group) (resource)
185 | - [azurerm_ip_group.ipgroup_2](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/ip_group) (resource)
186 | - [azurerm_public_ip.pip](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) (resource)
187 | - [azurerm_resource_group.rg](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource)
188 | - [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) (resource)
189 | - [random_integer.region_index](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) (resource)
190 |
191 |
192 | ## Required Inputs
193 |
194 | No required inputs.
195 |
196 | ## Optional Inputs
197 |
198 | The following input variables are optional (have default values):
199 |
200 | ### [enable\_telemetry](#input\_enable\_telemetry)
201 |
202 | Description: This variable controls whether or not telemetry is enabled for the module.
203 | For more information see https://aka.ms/avm/telemetryinfo.
204 | If it is set to false, then no telemetry will be collected.
205 |
206 | Type: `bool`
207 |
208 | Default: `true`
209 |
210 | ## Outputs
211 |
212 | No outputs.
213 |
214 | ## Modules
215 |
216 | The following Modules are called:
217 |
218 | ### [firewall](#module\_firewall)
219 |
220 | Source: Azure/avm-res-network-azurefirewall/azurerm
221 |
222 | Version: 0.4.0
223 |
224 | ### [firewall\_policy](#module\_firewall\_policy)
225 |
226 | Source: ../..
227 |
228 | Version:
229 |
230 | ### [naming](#module\_naming)
231 |
232 | Source: Azure/naming/azurerm
233 |
234 | Version: 0.3.0
235 |
236 | ### [rule\_collection\_group](#module\_rule\_collection\_group)
237 |
238 | Source: ../../modules/rule_collection_groups
239 |
240 | Version:
241 |
242 | ### [vnet](#module\_vnet)
243 |
244 | Source: Azure/avm-res-network-virtualnetwork/azurerm
245 |
246 | Version: 0.16.0
247 |
248 |
249 | ## Data Collection
250 |
251 | 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. 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.
252 |
--------------------------------------------------------------------------------
/.github/policies/scheduledSearches.yml:
--------------------------------------------------------------------------------
1 | id: avmScheduledSearches
2 | name: AVM Scheduled Searches
3 | description: AVM Scheduled Searches
4 | resource: repository
5 | disabled: false
6 |
7 | configuration:
8 | resourceManagementConfiguration:
9 | scheduledSearches:
10 | - description: "ITA01TF.1 - Label and comment AVM issues that have been marked as requiring triage and have not had any activity for 3 business days."
11 | frequencies:
12 | - weekday:
13 | day: Monday
14 | time: 12:00
15 | - weekday:
16 | day: Tuesday
17 | time: 12:00
18 | - weekday:
19 | day: Wednesday
20 | time: 12:00
21 | filters:
22 | - isIssue
23 | - isOpen
24 | - hasLabel:
25 | label: "Needs: Triage :mag:"
26 | - isNotLabeledWith:
27 | label: "Status: Response Overdue :triangular_flag_on_post:"
28 | - noActivitySince:
29 | days: 5
30 | actions:
31 | - mentionUsers:
32 | mentionees:
33 | - Azure/avm-core-team-technical-terraform
34 | replyTemplate: |
35 | > [!WARNING]
36 | > **Tagging the AVM Core Team (${mentionees}) due to a module owner or contributor having not responded to this issue within 3 business days. The AVM Core Team will attempt to contact the module owners/contributors directly.**
37 |
38 | > [!TIP]
39 | > - To prevent further actions to take effect, the "Status: Response Overdue 🚩" label must be removed, once this issue has been responded to.
40 | > - To avoid this rule being (re)triggered, the ""Needs: Triage :mag:" label must be removed as part of the triage process (when the issue is first responded to)!
41 | - addLabel:
42 | label: "Status: Response Overdue :triangular_flag_on_post:"
43 |
44 | - description: "ITA01TF.2 - Label and comment AVM issues that have been marked as requiring triage and have not had any activity for 3 business days."
45 | frequencies:
46 | - weekday:
47 | day: Thursday
48 | time: 12:00
49 | - weekday:
50 | day: Friday
51 | time: 12:00
52 | filters:
53 | - isIssue
54 | - isOpen
55 | - hasLabel:
56 | label: "Needs: Triage :mag:"
57 | - isNotLabeledWith:
58 | label: "Status: Response Overdue :triangular_flag_on_post:"
59 | - noActivitySince:
60 | days: 3
61 | actions:
62 | - mentionUsers:
63 | mentionees:
64 | - Azure/avm-core-team-technical-terraform
65 | replyTemplate: |
66 | > [!WARNING]
67 | > **Tagging the AVM Core Team (${mentionees}) due to a module owner or contributor having not responded to this issue within 3 business days. The AVM Core Team will attempt to contact the module owners/contributors directly.**
68 |
69 | > [!TIP]
70 | > - To prevent further actions to take effect, the "Status: Response Overdue 🚩" label must be removed, once this issue has been responded to.
71 | > - To avoid this rule being (re)triggered, the ""Needs: Triage :mag:" label must be removed as part of the triage process (when the issue is first responded to)!
72 | - addLabel:
73 | label: "Status: Response Overdue :triangular_flag_on_post:"
74 | - assignTo:
75 | user: Azure/avm-core-team-technical-terraform
76 |
77 | - description: "ITA02TF.1 - Label and comment issues as Needs Immediate Attention and leave comment if after an additional 3 business days there's still no update to the issue."
78 | frequencies:
79 | - weekday:
80 | day: Monday
81 | time: 12:00
82 | - weekday:
83 | day: Tuesday
84 | time: 12:00
85 | - weekday:
86 | day: Wednesday
87 | time: 12:00
88 | filters:
89 | - isIssue
90 | - isOpen
91 | - hasLabel:
92 | label: "Status: Response Overdue :triangular_flag_on_post:"
93 | - isNotLabeledWith:
94 | label: "Needs: Immediate Attention :bangbang:"
95 | - noActivitySince:
96 | days: 5
97 | actions:
98 | - mentionUsers:
99 | mentionees:
100 | - Azure/avm-core-team-technical-terraform
101 | replyTemplate: |
102 | > [!CAUTION]
103 | > **This issue requires the AVM Core Team's (${mentionees}) immediate attention as it hasn't been responded to within 6 business days. **
104 |
105 | > [!TIP]
106 | > - To avoid this rule being (re)triggered, the "Needs: Triage :mag:" and "Status: Response Overdue :triangular_flag_on_post:" labels must be removed when the issue is first responded to!
107 | > - Remove the "Needs: Immediate Attention :bangbang:" label once the issue has been responded to.
108 | - addLabel:
109 | label: "Needs: Immediate Attention :bangbang:"
110 |
111 | - description: "ITA02TF.2 - Label and comment issues as Needs Immediate Attention and leave comment if after an additional 3 business days there's still no update to the issue."
112 | frequencies:
113 | - weekday:
114 | day: Thursday
115 | time: 12:00
116 | - weekday:
117 | day: Friday
118 | time: 12:00
119 | filters:
120 | - isIssue
121 | - isOpen
122 | - hasLabel:
123 | label: "Status: Response Overdue :triangular_flag_on_post:"
124 | - isNotLabeledWith:
125 | label: "Needs: Immediate Attention :bangbang:"
126 | - noActivitySince:
127 | days: 3
128 | actions:
129 | - mentionUsers:
130 | mentionees:
131 | - Azure/avm-core-team-technical-terraform
132 | replyTemplate: |
133 | > [!CAUTION]
134 | > **This issue requires the AVM Core Team's (${mentionees}) immediate attention as it hasn't been responded to within 6 business days.**
135 |
136 | > [!TIP]
137 | > - To avoid this rule being (re)triggered, the "Needs: Triage :mag:" and "Status: Response Overdue :triangular_flag_on_post:" labels must be removed when the issue is first responded to!
138 | > - Remove the "Needs: Immediate Attention :bangbang:" label once the issue has been responded to.
139 | - addLabel:
140 | label: "Needs: Immediate Attention :bangbang:"
141 |
142 | - description: "ITA03TF - Label and mention Terraform PG to security issues that have not had any activity for 5 business days."
143 | frequencies:
144 | - weekday:
145 | day: Monday
146 | time: 12:00
147 | - weekday:
148 | day: Tuesday
149 | time: 12:00
150 | - weekday:
151 | day: Wednesday
152 | time: 12:00
153 | - weekday:
154 | day: Thursday
155 | time: 12:00
156 | - weekday:
157 | day: Friday
158 | time: 12:00
159 | filters:
160 | - isIssue
161 | - isOpen
162 | - hasLabel:
163 | label: "Needs: Triage :mag:"
164 | - hasLabel:
165 | label: "Type: Security Bug :lock:"
166 | - hasLabel:
167 | label: "Status: Response Overdue :triangular_flag_on_post:"
168 | - noActivitySince:
169 | days: 7
170 | actions:
171 | - mentionUsers:
172 | mentionees:
173 | - Azure/terraform-avm
174 | replyTemplate: |
175 | > [!CAUTION]
176 | > **Tagging the Terraform PG team (${mentionees}) due to a module owner or contributor having not responded to this issue within 3 business days. The AVM Core Team will attempt to contact the module owners/contributors directly.**
177 |
178 | > [!TIP]
179 | > - To avoid this rule being (re)triggered, the "Needs: Triage :mag:" and "Status: Response Overdue :triangular_flag_on_post:" labels must be removed when the issue is first responded to!
180 | > - Remove the "Needs: Immediate Attention :bangbang:" label once the issue has been responded to.
181 | - addLabel:
182 | label: "Needs: Immediate Attention :bangbang:"
183 | - assignTo:
184 | user: Azure/terraform-avm
185 |
186 | - description: "ITA04 - Label issues and PRs that have been marked as requiring author feedback but have not had any activity for 4 days."
187 | frequencies:
188 | - hourly:
189 | hour: 3
190 | filters:
191 | - isOpen
192 | - hasLabel:
193 | label: "Needs: Author Feedback :ear:"
194 | - noActivitySince:
195 | days: 4
196 | - isNotLabeledWith:
197 | label: "Status: No Recent Activity :zzz:"
198 | actions:
199 | - addLabel:
200 | label: "Status: No Recent Activity :zzz:"
201 | - addReply:
202 | reply: |
203 | - addReply:
204 | reply: |
205 | > [!IMPORTANT]
206 | > @${issueAuthor}, this issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **4 days**.
207 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_for_avd/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_version = ">= 1.3.0"
3 |
4 | required_providers {
5 | azurerm = {
6 | source = "hashicorp/azurerm"
7 | version = ">= 3.71, < 5.0.0"
8 | }
9 | random = {
10 | source = "hashicorp/random"
11 | version = ">= 3.5.0, < 4.0.0"
12 | }
13 | }
14 | }
15 |
16 | provider "azurerm" {
17 | features {}
18 | }
19 |
20 | # This picks a random region from the list of regions.
21 | resource "random_integer" "region_index" {
22 | max = length(local.azure_regions) - 1
23 | min = 0
24 | }
25 |
26 | # This ensures we have unique CAF compliant names for our resources.
27 | module "naming" {
28 | source = "Azure/naming/azurerm"
29 | version = "0.3.0"
30 | }
31 |
32 | # This is required for resource modules
33 | resource "azurerm_resource_group" "this" {
34 | location = local.azure_regions[random_integer.region_index.result]
35 | name = module.naming.resource_group.name_unique
36 | }
37 |
38 | # This is the module call
39 | module "firewall_policy" {
40 | source = "../.."
41 |
42 | location = azurerm_resource_group.this.location
43 | name = module.naming.firewall_policy.name_unique
44 | resource_group_name = azurerm_resource_group.this.name
45 | # source = "Azure/avm-res-network-firewallpolicy/azurerm"
46 | enable_telemetry = var.enable_telemetry
47 | firewall_policy_dns = {
48 | proxy_enabled = true
49 | }
50 | }
51 |
52 | module "avd_core_rule_collection_group" {
53 | source = "../../modules/rule_collection_groups"
54 |
55 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
56 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
57 | firewall_policy_rule_collection_group_name = "NetworkRuleCollectionGroup"
58 | firewall_policy_rule_collection_group_priority = 1000
59 | firewall_policy_rule_collection_group_network_rule_collection = [{
60 | action = "Allow"
61 | name = "AVDCoreNetworkRules"
62 | priority = 500
63 | rule = [
64 | {
65 | name = "Login to Microsoft"
66 | source_addresses = ["10.100.0.0/24"]
67 | destination_fqdns = ["login.microsoftonline.com"]
68 | protocols = ["TCP"]
69 | destination_ports = ["443"]
70 | },
71 | {
72 | name = "AVD"
73 | source_addresses = ["10.100.0.0/24"]
74 | destination_addresses = ["WindowsVirtualDesktop", "AzureFrontDoor.Frontend", "AzureMonitor"]
75 | protocols = ["TCP"]
76 | destination_ports = ["443"]
77 | },
78 | {
79 | name = "GCS"
80 | source_addresses = ["10.100.0.0/24"]
81 | destination_fqdns = ["gcs.prod.monitoring.core.windows.net"]
82 | protocols = ["TCP"]
83 | destination_ports = ["443"]
84 | },
85 | {
86 | name = "DNS"
87 | source_addresses = ["10.100.0.0/24"]
88 | destination_addresses = ["AzureDNS"]
89 | protocols = ["TCP", "UDP"]
90 | destination_ports = ["53"]
91 | },
92 | {
93 | name = "azkms"
94 | source_addresses = ["10.100.0.0/24"]
95 | destination_fqdns = ["azkms.core.windows.net"]
96 | protocols = ["TCP"]
97 | destination_ports = ["1688"]
98 | },
99 | {
100 | name = "KMS"
101 | source_addresses = ["10.100.0.0/24"]
102 | destination_fqdns = ["kms.core.windows.net"]
103 | protocols = ["TCP"]
104 | destination_ports = ["1688"]
105 | },
106 | {
107 | name = "mrglobalblob"
108 | source_addresses = ["10.100.0.0/24"]
109 | destination_fqdns = ["mrsglobalsteus2prod.blob.core.windows.net"]
110 | protocols = ["TCP"]
111 | destination_ports = ["443"]
112 | },
113 | {
114 | name = "wvdportalstorageblob"
115 | source_addresses = ["10.100.0.0/24"]
116 | destination_fqdns = ["wvdportalstorageblob.blob.core.windows.net"]
117 | protocols = ["TCP"]
118 | destination_ports = ["443"]
119 | },
120 | {
121 | name = "oneocsp"
122 | source_addresses = ["10.100.0.0/24"]
123 | destination_fqdns = ["oneocsp.microsoft.com"]
124 | protocols = ["TCP"]
125 | destination_ports = ["443"]
126 | },
127 | {
128 | name = "microsoft.com"
129 | source_addresses = ["10.100.0.0/24"]
130 | destination_fqdns = ["www.microsoft.com"]
131 | protocols = ["TCP"]
132 | destination_ports = ["443"]
133 | },
134 | ]
135 | }
136 | ]
137 | }
138 |
139 |
140 | module "avd_optional_rule_collection_group" {
141 | source = "../../modules/rule_collection_groups"
142 |
143 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
144 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
145 | firewall_policy_rule_collection_group_name = "AVDOptionalRuleCollectionGroup"
146 | firewall_policy_rule_collection_group_priority = 1050
147 | firewall_policy_rule_collection_group_application_rule_collection = [{
148 | action = "Allow"
149 | name = "AVDOptionalApplicationRules"
150 | priority = 600
151 | rule = [
152 | {
153 | name = "Windows"
154 | source_addresses = ["10.0.0.0/24"]
155 | destination_fqdn_tags = ["WindowsUpdate", "WindowsDiagnostics", "MicrosoftActiveProtectionService"]
156 | protocols = [
157 | {
158 | port = 443
159 | type = "Https"
160 | }
161 | ]
162 | },
163 | {
164 | name = "Events"
165 | source_addresses = ["10.0.0.0/24"]
166 | destination_fqdns = ["*.events.data.microsoft.com"]
167 | protocols = [
168 | {
169 | port = 443
170 | type = "Https"
171 | }
172 | ]
173 | },
174 | {
175 | name = "sfx"
176 | source_addresses = ["10.0.0.0/24"]
177 | destination_fqdns = ["*.sfx.ms"]
178 | protocols = [
179 | {
180 | port = 443
181 | type = "Https"
182 | }
183 | ]
184 | },
185 | {
186 | name = "digicert"
187 | source_addresses = ["10.0.0.0/24"]
188 | destination_fqdns = ["*.digicert.com"]
189 | protocols = [
190 | {
191 | port = 443
192 | type = "Https"
193 | }
194 | ]
195 | },
196 | {
197 | name = "Azure DNS"
198 | source_addresses = ["10.0.0.0/24"]
199 | destination_fqdns = ["*.azure-dns.com", "*.azure-dns.net"]
200 | protocols = [
201 | {
202 | port = 443
203 | type = "Https"
204 | }
205 | ]
206 | },
207 | ]
208 | }
209 | ]
210 | firewall_policy_rule_collection_group_network_rule_collection = [{
211 | action = "Allow"
212 | name = "AVDOptionalNetworkRules"
213 | priority = 500
214 | rule = [
215 | {
216 | name = "time"
217 | source_addresses = ["10.0.0.0/24"]
218 | destination_fqdns = ["time.windows.com"]
219 | protocols = ["UDP"]
220 | destination_ports = ["123"]
221 | },
222 | {
223 | name = "login windows.net"
224 | source_addresses = ["10.0.0.0/24"]
225 | destination_fqdns = ["login.windows.net"]
226 | protocols = ["TCP"]
227 | destination_ports = ["443"]
228 | },
229 | {
230 | name = "msftconnecttest"
231 | source_addresses = ["10.0.0.0/24"]
232 | destination_fqdns = ["www.msftconnecttest.com"]
233 | protocols = ["TCP"]
234 | destination_ports = ["443"]
235 | },
236 | ]
237 | }
238 | ]
239 | }
240 |
241 | module "m365rulecollectiongroup" {
242 | source = "../../modules/rule_collection_groups"
243 |
244 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
245 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
246 | firewall_policy_rule_collection_group_name = "M365RuleCollectionGroup"
247 | firewall_policy_rule_collection_group_priority = 2000
248 | firewall_policy_rule_collection_group_network_rule_collection = [{
249 | action = "Allow"
250 | name = "M365NetworkRules"
251 | priority = 500
252 | rule = [
253 | {
254 | name = "M365"
255 | source_addresses = ["10.0.0.0/24"]
256 | destination_addresses = ["Office365.Common.Allow.Required"]
257 | protocols = ["TCP"]
258 | destination_ports = ["443"]
259 | }
260 | ]
261 | }
262 | ]
263 | }
264 |
265 | module "internetrulecollectiongroup" {
266 | source = "../../modules/rule_collection_groups"
267 |
268 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
269 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
270 | firewall_policy_rule_collection_group_name = "InternetRuleCollectionGroup"
271 | firewall_policy_rule_collection_group_priority = 3000
272 | firewall_policy_rule_collection_group_network_rule_collection = [{
273 | action = "Allow"
274 | name = "InternetNetworkRules"
275 | priority = 500
276 | rule = [
277 | {
278 | name = "Internet"
279 | source_addresses = ["10.0.0.0/24"]
280 | destination_addresses = ["*"]
281 | protocols = ["TCP"]
282 | destination_ports = ["443", "80"]
283 | }
284 | ]
285 | }
286 | ]
287 | }
--------------------------------------------------------------------------------
/modules/rule_collection_groups/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Azure Firewall Policy Rule Collection Group
4 |
5 | This is the sub-module to create Rule Collection Groups in Azure Firewall Policy
6 |
7 | ## Features
8 |
9 | This module supports:
10 |
11 | - Creates Rule Collection Groups
12 | - Creates Rule Collections
13 | - Creates Network Rules, Application Rules, and NAT Rules
14 |
15 | "Major version Zero (0.y.z) is for initial development. Anything MAY change at any time. The module SHOULD NOT be considered stable till at least it is major version one (1.0.0) or greater. Changes will always be via new versions being published and no changes will be made to existing published versions. For more details please go to "
16 |
17 |
18 | ## Requirements
19 |
20 | The following requirements are needed by this module:
21 |
22 | - [terraform](#requirement\_terraform) (~> 1.5)
23 |
24 | - [azurerm](#requirement\_azurerm) (>= 3.71, < 5.0.0)
25 |
26 | ## Resources
27 |
28 | The following resources are used by this module:
29 |
30 | - [azurerm_firewall_policy_rule_collection_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/firewall_policy_rule_collection_group) (resource)
31 |
32 |
33 | ## Required Inputs
34 |
35 | The following input variables are required:
36 |
37 | ### [firewall\_policy\_rule\_collection\_group\_firewall\_policy\_id](#input\_firewall\_policy\_rule\_collection\_group\_firewall\_policy\_id)
38 |
39 | Description: (Required) The ID of the Firewall Policy where the Firewall Policy Rule Collection Group should exist. Changing this forces a new Firewall Policy Rule Collection Group to be created.
40 |
41 | Type: `string`
42 |
43 | ### [firewall\_policy\_rule\_collection\_group\_name](#input\_firewall\_policy\_rule\_collection\_group\_name)
44 |
45 | Description: (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
46 |
47 | Type: `string`
48 |
49 | ### [firewall\_policy\_rule\_collection\_group\_priority](#input\_firewall\_policy\_rule\_collection\_group\_priority)
50 |
51 | Description: (Required) The priority of the Firewall Policy Rule Collection Group. The range is 100-65000.
52 |
53 | Type: `number`
54 |
55 | ## Optional Inputs
56 |
57 | The following input variables are optional (have default values):
58 |
59 | ### [firewall\_policy\_rule\_collection\_group\_application\_rule\_collection](#input\_firewall\_policy\_rule\_collection\_group\_application\_rule\_collection)
60 |
61 | Description: - `action` - (Required) The action to take for the application rules in this collection. Possible values are `Allow` and `Deny`.
62 | - `name` - (Required) The name which should be used for this application rule collection.
63 | - `priority` - (Required) The priority of the application rule collection. The range is `100`
64 |
65 | ---
66 | `rule` block supports the following:
67 | - `description` -
68 | - `destination_addresses` -
69 | - `destination_fqdn_tags` -
70 | - `destination_fqdns` -
71 | - `destination_urls` -
72 | - `name` - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
73 | - `source_addresses` -
74 | - `source_ip_groups` -
75 | - `terminate_tls` -
76 | - `web_categories` -
77 |
78 | ---
79 | `http_headers` block supports the following:
80 | - `name` - (Required) Specifies the name of the header.
81 | - `value` - (Required) Specifies the value of the value.
82 |
83 | ---
84 | `protocols` block supports the following:
85 | - `port` - (Required) Port number of the protocol. Range is 0-64000.
86 | - `type` - (Required) Protocol type. Possible values are `Http` and `Https`.
87 |
88 | Type:
89 |
90 | ```hcl
91 | list(object({
92 | action = string
93 | name = string
94 | priority = number
95 | rule = list(object({
96 | description = optional(string)
97 | destination_addresses = optional(list(string), [])
98 | destination_fqdn_tags = optional(list(string), [])
99 | destination_fqdns = optional(list(string), [])
100 | destination_urls = optional(list(string), [])
101 | name = string
102 | source_addresses = optional(list(string), [])
103 | source_ip_groups = optional(list(string), [])
104 | terminate_tls = optional(bool)
105 | web_categories = optional(list(string), [])
106 | http_headers = optional(list(object({
107 | name = string
108 | value = string
109 | })))
110 | protocols = optional(list(object({
111 | port = number
112 | type = string
113 | })))
114 | }))
115 | }))
116 | ```
117 |
118 | Default: `null`
119 |
120 | ### [firewall\_policy\_rule\_collection\_group\_nat\_rule\_collection](#input\_firewall\_policy\_rule\_collection\_group\_nat\_rule\_collection)
121 |
122 | Description: - `action` - (Required) The action to take for the NAT rules in this collection. Currently, the only possible value is `Dnat`.
123 | - `name` - (Required) The name which should be used for this NAT rule collection.
124 | - `priority` - (Required) The priority of the NAT rule collection. The range is `100`
125 |
126 | ---
127 | `rule` block supports the following:
128 | - `description` -
129 | - `destination_address` -
130 | - `destination_ports` -
131 | - `name` - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
132 | - `protocols` -
133 | - `source_addresses` -
134 | - `source_ip_groups` -
135 | - `translated_address` -
136 | - `translated_fqdn` -
137 | - `translated_port` -
138 |
139 | Type:
140 |
141 | ```hcl
142 | list(object({
143 | action = string
144 | name = string
145 | priority = number
146 | rule = list(object({
147 | description = optional(string)
148 | destination_address = optional(string)
149 | destination_ports = optional(list(string), [])
150 | name = string
151 | protocols = list(string)
152 | source_addresses = optional(list(string), [])
153 | source_ip_groups = optional(list(string), [])
154 | translated_address = optional(string)
155 | translated_fqdn = optional(string)
156 | translated_port = number
157 | }))
158 | }))
159 | ```
160 |
161 | Default: `null`
162 |
163 | ### [firewall\_policy\_rule\_collection\_group\_network\_rule\_collection](#input\_firewall\_policy\_rule\_collection\_group\_network\_rule\_collection)
164 |
165 | Description: - `action` - (Required) The action to take for the network rules in this collection. Possible values are `Allow` and `Deny`.
166 | - `name` - (Required) The name which should be used for this network rule collection.
167 | - `priority` - (Required) The priority of the network rule collection. The range is `100`
168 |
169 | ---
170 | `rule` block supports the following:
171 | - `description` -
172 | - `destination_addresses` -
173 | - `destination_fqdns` -
174 | - `destination_ip_groups` -
175 | - `destination_ports` -
176 | - `name` - (Required) The name which should be used for this Firewall Policy Rule Collection Group. Changing this forces a new Firewall Policy Rule Collection Group to be created.
177 | - `protocols` -
178 | - `source_addresses` -
179 | - `source_ip_groups` -
180 |
181 | Type:
182 |
183 | ```hcl
184 | list(object({
185 | action = string
186 | name = string
187 | priority = number
188 | rule = list(object({
189 | description = optional(string)
190 | destination_addresses = optional(list(string), [])
191 | destination_fqdns = optional(list(string), [])
192 | destination_ip_groups = optional(list(string), [])
193 | destination_ports = list(string)
194 | name = string
195 | protocols = list(string)
196 | source_addresses = optional(list(string), [])
197 | source_ip_groups = optional(list(string), [])
198 | }))
199 | }))
200 | ```
201 |
202 | Default: `null`
203 |
204 | ### [firewall\_policy\_rule\_collection\_group\_timeouts](#input\_firewall\_policy\_rule\_collection\_group\_timeouts)
205 |
206 | Description: - `create` - (Defaults to 30 minutes) Used when creating the Firewall Policy Rule Collection Group.
207 | - `delete` - (Defaults to 30 minutes) Used when deleting the Firewall Policy Rule Collection Group.
208 | - `read` - (Defaults to 5 minutes) Used when retrieving the Firewall Policy Rule Collection Group.
209 | - `update` - (Defaults to 30 minutes) Used when updating the Firewall Policy Rule Collection Group.
210 |
211 | Type:
212 |
213 | ```hcl
214 | object({
215 | create = optional(string)
216 | delete = optional(string)
217 | read = optional(string)
218 | update = optional(string)
219 | })
220 | ```
221 |
222 | Default: `null`
223 |
224 | ## Outputs
225 |
226 | The following outputs are exported:
227 |
228 | ### [resource](#output\_resource)
229 |
230 | Description: this is the resource of the rule collection group
231 |
232 | ### [resource\_id](#output\_resource\_id)
233 |
234 | Description: the resource id of the rule\_collection\_group
235 |
236 | ## Modules
237 |
238 | No modules.
239 |
240 |
241 | ## Data Collection
242 |
243 | 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. 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.
244 |
--------------------------------------------------------------------------------
/examples/deploy_fw_policy_for_avd/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Deploy Firewall Policy for Azure Virtual Desktop
4 |
5 | This example deploys an Azure Firewall Policy with the required rules needed for Azure Virtual Desktop.
6 |
7 | - Firewall Policy
8 | - Rule Collection Groups
9 | - Rule Collections
10 | - Network and Application Rules
11 |
12 | ```hcl
13 | terraform {
14 | required_version = ">= 1.3.0"
15 |
16 | required_providers {
17 | azurerm = {
18 | source = "hashicorp/azurerm"
19 | version = ">= 3.71, < 5.0.0"
20 | }
21 | random = {
22 | source = "hashicorp/random"
23 | version = ">= 3.5.0, < 4.0.0"
24 | }
25 | }
26 | }
27 |
28 | provider "azurerm" {
29 | features {}
30 | }
31 |
32 | # This picks a random region from the list of regions.
33 | resource "random_integer" "region_index" {
34 | max = length(local.azure_regions) - 1
35 | min = 0
36 | }
37 |
38 | # This ensures we have unique CAF compliant names for our resources.
39 | module "naming" {
40 | source = "Azure/naming/azurerm"
41 | version = "0.3.0"
42 | }
43 |
44 | # This is required for resource modules
45 | resource "azurerm_resource_group" "this" {
46 | location = local.azure_regions[random_integer.region_index.result]
47 | name = module.naming.resource_group.name_unique
48 | }
49 |
50 | # This is the module call
51 | module "firewall_policy" {
52 | source = "../.."
53 |
54 | location = azurerm_resource_group.this.location
55 | name = module.naming.firewall_policy.name_unique
56 | resource_group_name = azurerm_resource_group.this.name
57 | # source = "Azure/avm-res-network-firewallpolicy/azurerm"
58 | enable_telemetry = var.enable_telemetry
59 | firewall_policy_dns = {
60 | proxy_enabled = true
61 | }
62 | }
63 |
64 | module "avd_core_rule_collection_group" {
65 | source = "../../modules/rule_collection_groups"
66 |
67 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
68 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
69 | firewall_policy_rule_collection_group_name = "NetworkRuleCollectionGroup"
70 | firewall_policy_rule_collection_group_priority = 1000
71 | firewall_policy_rule_collection_group_network_rule_collection = [{
72 | action = "Allow"
73 | name = "AVDCoreNetworkRules"
74 | priority = 500
75 | rule = [
76 | {
77 | name = "Login to Microsoft"
78 | source_addresses = ["10.100.0.0/24"]
79 | destination_fqdns = ["login.microsoftonline.com"]
80 | protocols = ["TCP"]
81 | destination_ports = ["443"]
82 | },
83 | {
84 | name = "AVD"
85 | source_addresses = ["10.100.0.0/24"]
86 | destination_addresses = ["WindowsVirtualDesktop", "AzureFrontDoor.Frontend", "AzureMonitor"]
87 | protocols = ["TCP"]
88 | destination_ports = ["443"]
89 | },
90 | {
91 | name = "GCS"
92 | source_addresses = ["10.100.0.0/24"]
93 | destination_fqdns = ["gcs.prod.monitoring.core.windows.net"]
94 | protocols = ["TCP"]
95 | destination_ports = ["443"]
96 | },
97 | {
98 | name = "DNS"
99 | source_addresses = ["10.100.0.0/24"]
100 | destination_addresses = ["AzureDNS"]
101 | protocols = ["TCP", "UDP"]
102 | destination_ports = ["53"]
103 | },
104 | {
105 | name = "azkms"
106 | source_addresses = ["10.100.0.0/24"]
107 | destination_fqdns = ["azkms.core.windows.net"]
108 | protocols = ["TCP"]
109 | destination_ports = ["1688"]
110 | },
111 | {
112 | name = "KMS"
113 | source_addresses = ["10.100.0.0/24"]
114 | destination_fqdns = ["kms.core.windows.net"]
115 | protocols = ["TCP"]
116 | destination_ports = ["1688"]
117 | },
118 | {
119 | name = "mrglobalblob"
120 | source_addresses = ["10.100.0.0/24"]
121 | destination_fqdns = ["mrsglobalsteus2prod.blob.core.windows.net"]
122 | protocols = ["TCP"]
123 | destination_ports = ["443"]
124 | },
125 | {
126 | name = "wvdportalstorageblob"
127 | source_addresses = ["10.100.0.0/24"]
128 | destination_fqdns = ["wvdportalstorageblob.blob.core.windows.net"]
129 | protocols = ["TCP"]
130 | destination_ports = ["443"]
131 | },
132 | {
133 | name = "oneocsp"
134 | source_addresses = ["10.100.0.0/24"]
135 | destination_fqdns = ["oneocsp.microsoft.com"]
136 | protocols = ["TCP"]
137 | destination_ports = ["443"]
138 | },
139 | {
140 | name = "microsoft.com"
141 | source_addresses = ["10.100.0.0/24"]
142 | destination_fqdns = ["www.microsoft.com"]
143 | protocols = ["TCP"]
144 | destination_ports = ["443"]
145 | },
146 | ]
147 | }
148 | ]
149 | }
150 |
151 |
152 | module "avd_optional_rule_collection_group" {
153 | source = "../../modules/rule_collection_groups"
154 |
155 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
156 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
157 | firewall_policy_rule_collection_group_name = "AVDOptionalRuleCollectionGroup"
158 | firewall_policy_rule_collection_group_priority = 1050
159 | firewall_policy_rule_collection_group_application_rule_collection = [{
160 | action = "Allow"
161 | name = "AVDOptionalApplicationRules"
162 | priority = 600
163 | rule = [
164 | {
165 | name = "Windows"
166 | source_addresses = ["10.0.0.0/24"]
167 | destination_fqdn_tags = ["WindowsUpdate", "WindowsDiagnostics", "MicrosoftActiveProtectionService"]
168 | protocols = [
169 | {
170 | port = 443
171 | type = "Https"
172 | }
173 | ]
174 | },
175 | {
176 | name = "Events"
177 | source_addresses = ["10.0.0.0/24"]
178 | destination_fqdns = ["*.events.data.microsoft.com"]
179 | protocols = [
180 | {
181 | port = 443
182 | type = "Https"
183 | }
184 | ]
185 | },
186 | {
187 | name = "sfx"
188 | source_addresses = ["10.0.0.0/24"]
189 | destination_fqdns = ["*.sfx.ms"]
190 | protocols = [
191 | {
192 | port = 443
193 | type = "Https"
194 | }
195 | ]
196 | },
197 | {
198 | name = "digicert"
199 | source_addresses = ["10.0.0.0/24"]
200 | destination_fqdns = ["*.digicert.com"]
201 | protocols = [
202 | {
203 | port = 443
204 | type = "Https"
205 | }
206 | ]
207 | },
208 | {
209 | name = "Azure DNS"
210 | source_addresses = ["10.0.0.0/24"]
211 | destination_fqdns = ["*.azure-dns.com", "*.azure-dns.net"]
212 | protocols = [
213 | {
214 | port = 443
215 | type = "Https"
216 | }
217 | ]
218 | },
219 | ]
220 | }
221 | ]
222 | firewall_policy_rule_collection_group_network_rule_collection = [{
223 | action = "Allow"
224 | name = "AVDOptionalNetworkRules"
225 | priority = 500
226 | rule = [
227 | {
228 | name = "time"
229 | source_addresses = ["10.0.0.0/24"]
230 | destination_fqdns = ["time.windows.com"]
231 | protocols = ["UDP"]
232 | destination_ports = ["123"]
233 | },
234 | {
235 | name = "login windows.net"
236 | source_addresses = ["10.0.0.0/24"]
237 | destination_fqdns = ["login.windows.net"]
238 | protocols = ["TCP"]
239 | destination_ports = ["443"]
240 | },
241 | {
242 | name = "msftconnecttest"
243 | source_addresses = ["10.0.0.0/24"]
244 | destination_fqdns = ["www.msftconnecttest.com"]
245 | protocols = ["TCP"]
246 | destination_ports = ["443"]
247 | },
248 | ]
249 | }
250 | ]
251 | }
252 |
253 | module "m365rulecollectiongroup" {
254 | source = "../../modules/rule_collection_groups"
255 |
256 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
257 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
258 | firewall_policy_rule_collection_group_name = "M365RuleCollectionGroup"
259 | firewall_policy_rule_collection_group_priority = 2000
260 | firewall_policy_rule_collection_group_network_rule_collection = [{
261 | action = "Allow"
262 | name = "M365NetworkRules"
263 | priority = 500
264 | rule = [
265 | {
266 | name = "M365"
267 | source_addresses = ["10.0.0.0/24"]
268 | destination_addresses = ["Office365.Common.Allow.Required"]
269 | protocols = ["TCP"]
270 | destination_ports = ["443"]
271 | }
272 | ]
273 | }
274 | ]
275 | }
276 |
277 | module "internetrulecollectiongroup" {
278 | source = "../../modules/rule_collection_groups"
279 |
280 | # source = "Azure/avm-res-network-firewallpolicy/azurerm//modules/rule_collection_groups"
281 | firewall_policy_rule_collection_group_firewall_policy_id = module.firewall_policy.resource.id
282 | firewall_policy_rule_collection_group_name = "InternetRuleCollectionGroup"
283 | firewall_policy_rule_collection_group_priority = 3000
284 | firewall_policy_rule_collection_group_network_rule_collection = [{
285 | action = "Allow"
286 | name = "InternetNetworkRules"
287 | priority = 500
288 | rule = [
289 | {
290 | name = "Internet"
291 | source_addresses = ["10.0.0.0/24"]
292 | destination_addresses = ["*"]
293 | protocols = ["TCP"]
294 | destination_ports = ["443", "80"]
295 | }
296 | ]
297 | }
298 | ]
299 | }
300 | ```
301 |
302 |
303 | ## Requirements
304 |
305 | The following requirements are needed by this module:
306 |
307 | - [terraform](#requirement\_terraform) (>= 1.3.0)
308 |
309 | - [azurerm](#requirement\_azurerm) (>= 3.71, < 5.0.0)
310 |
311 | - [random](#requirement\_random) (>= 3.5.0, < 4.0.0)
312 |
313 | ## Resources
314 |
315 | The following resources are used by this module:
316 |
317 | - [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource)
318 | - [random_integer.region_index](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) (resource)
319 |
320 |
321 | ## Required Inputs
322 |
323 | No required inputs.
324 |
325 | ## Optional Inputs
326 |
327 | The following input variables are optional (have default values):
328 |
329 | ### [enable\_telemetry](#input\_enable\_telemetry)
330 |
331 | Description: This variable controls whether or not telemetry is enabled for the module.
332 | For more information see https://aka.ms/avm/telemetryinfo.
333 | If it is set to false, then no telemetry will be collected.
334 |
335 | Type: `bool`
336 |
337 | Default: `true`
338 |
339 | ## Outputs
340 |
341 | No outputs.
342 |
343 | ## Modules
344 |
345 | The following Modules are called:
346 |
347 | ### [avd\_core\_rule\_collection\_group](#module\_avd\_core\_rule\_collection\_group)
348 |
349 | Source: ../../modules/rule_collection_groups
350 |
351 | Version:
352 |
353 | ### [avd\_optional\_rule\_collection\_group](#module\_avd\_optional\_rule\_collection\_group)
354 |
355 | Source: ../../modules/rule_collection_groups
356 |
357 | Version:
358 |
359 | ### [firewall\_policy](#module\_firewall\_policy)
360 |
361 | Source: ../..
362 |
363 | Version:
364 |
365 | ### [internetrulecollectiongroup](#module\_internetrulecollectiongroup)
366 |
367 | Source: ../../modules/rule_collection_groups
368 |
369 | Version:
370 |
371 | ### [m365rulecollectiongroup](#module\_m365rulecollectiongroup)
372 |
373 | Source: ../../modules/rule_collection_groups
374 |
375 | Version:
376 |
377 | ### [naming](#module\_naming)
378 |
379 | Source: Azure/naming/azurerm
380 |
381 | Version: 0.3.0
382 |
383 |
384 | ## Data Collection
385 |
386 | 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. 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.
387 |
--------------------------------------------------------------------------------
/variables.tf:
--------------------------------------------------------------------------------
1 | variable "location" {
2 | type = string
3 | description = "(Required) The Azure Region where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created."
4 | nullable = false
5 | }
6 |
7 | variable "name" {
8 | type = string
9 | description = "(Required) The name which should be used for this Firewall Policy. Changing this forces a new Firewall Policy to be created."
10 | nullable = false
11 | }
12 |
13 | variable "resource_group_name" {
14 | type = string
15 | description = "(Required) The name of the Resource Group where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created."
16 | nullable = false
17 | }
18 |
19 | variable "diagnostic_settings" {
20 | type = map(object({
21 | name = optional(string, null)
22 | log_categories = optional(set(string), [])
23 | log_groups = optional(set(string), ["allLogs"])
24 | metric_categories = optional(set(string), ["AllMetrics"])
25 | log_analytics_destination_type = optional(string, "Dedicated")
26 | workspace_resource_id = optional(string, null)
27 | storage_account_resource_id = optional(string, null)
28 | event_hub_authorization_rule_resource_id = optional(string, null)
29 | event_hub_name = optional(string, null)
30 | marketplace_partner_resource_id = optional(string, null)
31 | }))
32 | default = {}
33 | description = <.
70 | If it is set to false, then no telemetry will be collected.
71 | DESCRIPTION
72 | nullable = false
73 | }
74 |
75 | variable "firewall_policy_auto_learn_private_ranges_enabled" {
76 | type = bool
77 | default = null
78 | description = "(Optional) Whether enable auto learn private ip range."
79 | }
80 |
81 | variable "firewall_policy_base_policy_id" {
82 | type = string
83 | default = null
84 | description = "(Optional) The ID of the base Firewall Policy."
85 | }
86 |
87 | variable "firewall_policy_dns" {
88 | type = object({
89 | proxy_enabled = optional(bool)
90 | servers = optional(list(string))
91 | })
92 | default = null
93 | description = <<-EOT
94 | - `proxy_enabled` - (Optional) Whether to enable DNS proxy on Firewalls attached to this Firewall Policy? Defaults to `false`.
95 | - `servers` - (Optional) A list of custom DNS servers' IP addresses.
96 | EOT
97 | }
98 |
99 | variable "firewall_policy_explicit_proxy" {
100 | type = object({
101 | enable_pac_file = optional(bool)
102 | enabled = optional(bool)
103 | http_port = optional(number)
104 | https_port = optional(number)
105 | pac_file = optional(string)
106 | pac_file_port = optional(number)
107 | })
108 | default = null
109 | description = <<-EOT
110 | - `enable_pac_file` - (Optional) Whether the pac file port and url need to be provided.
111 | - `enabled` - (Optional) Whether the explicit proxy is enabled for this Firewall Policy.
112 | - `http_port` - (Optional) The port number for explicit http protocol.
113 | - `https_port` - (Optional) The port number for explicit proxy https protocol.
114 | - `pac_file` - (Optional) Specifies a SAS URL for PAC file.
115 | - `pac_file_port` - (Optional) Specifies a port number for firewall to serve PAC file.
116 | EOT
117 | }
118 |
119 | variable "firewall_policy_identity" {
120 | type = object({
121 | identity_ids = optional(set(string))
122 | type = string
123 | })
124 | default = null
125 | description = <<-EOT
126 | - `identity_ids` - (Optional) Specifies a list of User Assigned Managed Identity IDs to be assigned to this Firewall Policy.
127 | - `type` - (Required) Specifies the type of Managed Service Identity that should be configured on this Firewall Policy. Only possible value is `UserAssigned`.
128 | EOT
129 | }
130 |
131 | variable "firewall_policy_insights" {
132 | type = object({
133 | default_log_analytics_workspace_id = string
134 | enabled = bool
135 | retention_in_days = optional(number)
136 | log_analytics_workspace = optional(list(object({
137 | firewall_location = string
138 | id = string
139 | })))
140 | })
141 | default = null
142 | description = <<-EOT
143 | - `default_log_analytics_workspace_id` - (Required) The ID of the default Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to, when there is no location matches in the `log_analytics_workspace`.
144 | - `enabled` - (Required) Whether the insights functionality is enabled for this Firewall Policy.
145 | - `retention_in_days` - (Optional) The log retention period in days.
146 |
147 | ---
148 | `log_analytics_workspace` block supports the following:
149 | - `firewall_location` - (Required) The location of the Firewalls, that when matches this Log Analytics Workspace will be used to consume their logs.
150 | - `id` - (Required) The ID of the Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to when their locations match the `firewall_location`.
151 | EOT
152 | }
153 |
154 | variable "firewall_policy_intrusion_detection" {
155 | type = object({
156 | mode = optional(string)
157 | private_ranges = optional(list(string))
158 | signature_overrides = optional(list(object({
159 | id = optional(string)
160 | state = optional(string)
161 | })))
162 | traffic_bypass = optional(list(object({
163 | description = optional(string)
164 | destination_addresses = optional(set(string))
165 | destination_ip_groups = optional(set(string))
166 | destination_ports = optional(set(string))
167 | name = string
168 | protocol = string
169 | source_addresses = optional(set(string))
170 | source_ip_groups = optional(set(string))
171 | })))
172 | })
173 | default = null
174 | description = <<-EOT
175 | - `mode` - (Optional) In which mode you want to run intrusion detection: `Off`, `Alert` or `Deny`.
176 | - `private_ranges` - (Optional) A list of Private IP address ranges to identify traffic direction. By default, only ranges defined by IANA RFC 1918 are considered private IP addresses.
177 |
178 | ---
179 | `signature_overrides` block supports the following:
180 | - `id` - (Optional) 12-digit number (id) which identifies your signature.
181 | - `state` - (Optional) state can be any of `Off`, `Alert` or `Deny`.
182 |
183 | ---
184 | `traffic_bypass` block supports the following:
185 | - `description` - (Optional) The description for this bypass traffic setting.
186 | - `destination_addresses` - (Optional) Specifies a list of destination IP addresses that shall be bypassed by intrusion detection.
187 | - `destination_ip_groups` - (Optional) Specifies a list of destination IP groups that shall be bypassed by intrusion detection.
188 | - `destination_ports` - (Optional) Specifies a list of destination IP ports that shall be bypassed by intrusion detection.
189 | - `name` - (Required) The name which should be used for this bypass traffic setting.
190 | - `protocol` - (Required) The protocols any of `ANY`, `TCP`, `ICMP`, `UDP` that shall be bypassed by intrusion detection.
191 | - `source_addresses` - (Optional) Specifies a list of source addresses that shall be bypassed by intrusion detection.
192 | - `source_ip_groups` - (Optional) Specifies a list of source IP groups that shall be bypassed by intrusion detection.
193 | EOT
194 | }
195 |
196 | variable "firewall_policy_private_ip_ranges" {
197 | type = list(string)
198 | default = null
199 | description = "(Optional) A list of private IP ranges to which traffic will not be SNAT."
200 | }
201 |
202 | variable "firewall_policy_sku" {
203 | type = string
204 | default = null
205 | description = "(Optional) The SKU Tier of the Firewall Policy. Possible values are `Standard`, `Premium` and `Basic`. Changing this forces a new Firewall Policy to be created."
206 | }
207 |
208 | variable "firewall_policy_sql_redirect_allowed" {
209 | type = bool
210 | default = null
211 | description = "(Optional) Whether SQL Redirect traffic filtering is allowed. Enabling this flag requires no rule using ports between `11000`-`11999`."
212 | }
213 |
214 | variable "firewall_policy_threat_intelligence_allowlist" {
215 | type = object({
216 | fqdns = optional(set(string))
217 | ip_addresses = optional(set(string))
218 | })
219 | default = null
220 | description = <<-EOT
221 | - `fqdns` - (Optional) A list of FQDNs that will be skipped for threat detection.
222 | - `ip_addresses` - (Optional) A list of IP addresses or CIDR ranges that will be skipped for threat detection.
223 | EOT
224 | }
225 |
226 | variable "firewall_policy_threat_intelligence_mode" {
227 | type = string
228 | default = null
229 | description = "(Optional) The operation mode for Threat Intelligence. Possible values are `Alert`, `Deny` and `Off`. Defaults to `Alert`."
230 | }
231 |
232 | variable "firewall_policy_timeouts" {
233 | type = object({
234 | create = optional(string)
235 | delete = optional(string)
236 | read = optional(string)
237 | update = optional(string)
238 | })
239 | default = null
240 | description = <<-EOT
241 | - `create` - (Defaults to 30 minutes) Used when creating the Firewall Policy.
242 | - `delete` - (Defaults to 30 minutes) Used when deleting the Firewall Policy.
243 | - `read` - (Defaults to 5 minutes) Used when retrieving the Firewall Policy.
244 | - `update` - (Defaults to 30 minutes) Used when updating the Firewall Policy.
245 | EOT
246 | }
247 |
248 | variable "firewall_policy_tls_certificate" {
249 | type = object({
250 | key_vault_secret_id = string
251 | name = string
252 | })
253 | default = null
254 | description = <<-EOT
255 | - `key_vault_secret_id` - (Required) The ID of the Key Vault, where the secret or certificate is stored.
256 | - `name` - (Required) The name of the certificate.
257 | EOT
258 | }
259 |
260 | variable "lock" {
261 | type = object({
262 | kind = string
263 | name = optional(string, null)
264 | })
265 | default = null
266 | description = <. The map key is deliberately arbitrary to avoid issues where map keys maybe unknown at plan time.
293 |
294 | - `role_definition_id_or_name` - The ID or name of the role definition to assign to the principal.
295 | - `principal_id` - The ID of the principal to assign the role to.
296 | - `description` - (Optional) The description of the role assignment.
297 | - `skip_service_principal_aad_check` - (Optional) If set to true, skips the Azure Active Directory check for the service principal in the tenant. Defaults to false.
298 | - `condition` - (Optional) The condition which will be used to scope the role assignment.
299 | - `condition_version` - (Optional) The version of the condition syntax. Leave as `null` if you are not using a condition, if you are then valid values are '2.0'.
300 | - `delegated_managed_identity_resource_id` - (Optional) The delegated Azure Resource Id which contains a Managed Identity. Changing this forces a new resource to be created. This field is only used in cross-tenant scenario.
301 | - `principal_type` - (Optional) The type of the `principal_id`. Possible values are `User`, `Group` and `ServicePrincipal`. It is necessary to explicitly set this attribute when creating role assignments if the principal creating the assignment is constrained by ABAC rules that filters on the PrincipalType attribute.
302 |
303 | > Note: only set `skip_service_principal_aad_check` to true if you are assigning a role to a service principal.
304 | DESCRIPTION
305 | nullable = false
306 | }
307 |
308 | variable "tags" {
309 | type = map(string)
310 | default = null
311 | description = "(Optional) A mapping of tags to assign to the resource."
312 | }
313 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # terraform-azurerm-avm-network-firewallpolicy
4 |
5 | This is the module to create an Azure Firewall Policy
6 |
7 | "Major version Zero (0.y.z) is for initial development. Anything MAY change at any time. The module SHOULD NOT be considered stable till at least it is major version one (1.0.0) or greater. Changes will always be via new versions being published and no changes will be made to existing published versions. For more details please go to "
8 |
9 |
10 | ## Requirements
11 |
12 | The following requirements are needed by this module:
13 |
14 | - [terraform](#requirement\_terraform) (~> 1.5)
15 |
16 | - [azapi](#requirement\_azapi) (~> 2.4)
17 |
18 | - [azurerm](#requirement\_azurerm) (>= 3.71, < 5.0.0)
19 |
20 | - [modtm](#requirement\_modtm) (~> 0.3)
21 |
22 | - [random](#requirement\_random) (~> 3.5)
23 |
24 | ## Resources
25 |
26 | The following resources are used by this module:
27 |
28 | - [azurerm_firewall_policy.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/firewall_policy) (resource)
29 | - [azurerm_management_lock.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/management_lock) (resource)
30 | - [azurerm_monitor_diagnostic_setting.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_diagnostic_setting) (resource)
31 | - [azurerm_role_assignment.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource)
32 | - [modtm_telemetry.telemetry](https://registry.terraform.io/providers/Azure/modtm/latest/docs/resources/telemetry) (resource)
33 | - [random_uuid.telemetry](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/uuid) (resource)
34 | - [azapi_client_config.telemetry](https://registry.terraform.io/providers/Azure/azapi/latest/docs/data-sources/client_config) (data source)
35 | - [modtm_module_source.telemetry](https://registry.terraform.io/providers/Azure/modtm/latest/docs/data-sources/module_source) (data source)
36 |
37 |
38 | ## Required Inputs
39 |
40 | The following input variables are required:
41 |
42 | ### [location](#input\_location)
43 |
44 | Description: (Required) The Azure Region where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created.
45 |
46 | Type: `string`
47 |
48 | ### [name](#input\_name)
49 |
50 | Description: (Required) The name which should be used for this Firewall Policy. Changing this forces a new Firewall Policy to be created.
51 |
52 | Type: `string`
53 |
54 | ### [resource\_group\_name](#input\_resource\_group\_name)
55 |
56 | Description: (Required) The name of the Resource Group where the Firewall Policy should exist. Changing this forces a new Firewall Policy to be created.
57 |
58 | Type: `string`
59 |
60 | ## Optional Inputs
61 |
62 | The following input variables are optional (have default values):
63 |
64 | ### [diagnostic\_settings](#input\_diagnostic\_settings)
65 |
66 | Description: A map of diagnostic settings to create on the Key Vault. The map key is deliberately arbitrary to avoid issues where map keys maybe unknown at plan time.
67 |
68 | - `name` - (Optional) The name of the diagnostic setting. One will be generated if not set, however this will not be unique if you want to create multiple diagnostic setting resources.
69 | - `log_categories` - (Optional) A set of log categories to send to the log analytics workspace. Defaults to `[]`.
70 | - `log_groups` - (Optional) A set of log groups to send to the log analytics workspace. Defaults to `["allLogs"]`.
71 | - `metric_categories` - (Optional) A set of metric categories to send to the log analytics workspace. Defaults to `["AllMetrics"]`.
72 | - `log_analytics_destination_type` - (Optional) The destination type for the diagnostic setting. Possible values are `Dedicated` and `AzureDiagnostics`. Defaults to `Dedicated`.
73 | - `workspace_resource_id` - (Optional) The resource ID of the log analytics workspace to send logs and metrics to.
74 | - `storage_account_resource_id` - (Optional) The resource ID of the storage account to send logs and metrics to.
75 | - `event_hub_authorization_rule_resource_id` - (Optional) The resource ID of the event hub authorization rule to send logs and metrics to.
76 | - `event_hub_name` - (Optional) The name of the event hub. If none is specified, the default event hub will be selected.
77 | - `marketplace_partner_resource_id` - (Optional) The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic LogsLogs.
78 |
79 | Type:
80 |
81 | ```hcl
82 | map(object({
83 | name = optional(string, null)
84 | log_categories = optional(set(string), [])
85 | log_groups = optional(set(string), ["allLogs"])
86 | metric_categories = optional(set(string), ["AllMetrics"])
87 | log_analytics_destination_type = optional(string, "Dedicated")
88 | workspace_resource_id = optional(string, null)
89 | storage_account_resource_id = optional(string, null)
90 | event_hub_authorization_rule_resource_id = optional(string, null)
91 | event_hub_name = optional(string, null)
92 | marketplace_partner_resource_id = optional(string, null)
93 | }))
94 | ```
95 |
96 | Default: `{}`
97 |
98 | ### [enable\_telemetry](#input\_enable\_telemetry)
99 |
100 | Description: This variable controls whether or not telemetry is enabled for the module.
101 | For more information see .
102 | If it is set to false, then no telemetry will be collected.
103 |
104 | Type: `bool`
105 |
106 | Default: `true`
107 |
108 | ### [firewall\_policy\_auto\_learn\_private\_ranges\_enabled](#input\_firewall\_policy\_auto\_learn\_private\_ranges\_enabled)
109 |
110 | Description: (Optional) Whether enable auto learn private ip range.
111 |
112 | Type: `bool`
113 |
114 | Default: `null`
115 |
116 | ### [firewall\_policy\_base\_policy\_id](#input\_firewall\_policy\_base\_policy\_id)
117 |
118 | Description: (Optional) The ID of the base Firewall Policy.
119 |
120 | Type: `string`
121 |
122 | Default: `null`
123 |
124 | ### [firewall\_policy\_dns](#input\_firewall\_policy\_dns)
125 |
126 | Description: - `proxy_enabled` - (Optional) Whether to enable DNS proxy on Firewalls attached to this Firewall Policy? Defaults to `false`.
127 | - `servers` - (Optional) A list of custom DNS servers' IP addresses.
128 |
129 | Type:
130 |
131 | ```hcl
132 | object({
133 | proxy_enabled = optional(bool)
134 | servers = optional(list(string))
135 | })
136 | ```
137 |
138 | Default: `null`
139 |
140 | ### [firewall\_policy\_explicit\_proxy](#input\_firewall\_policy\_explicit\_proxy)
141 |
142 | Description: - `enable_pac_file` - (Optional) Whether the pac file port and url need to be provided.
143 | - `enabled` - (Optional) Whether the explicit proxy is enabled for this Firewall Policy.
144 | - `http_port` - (Optional) The port number for explicit http protocol.
145 | - `https_port` - (Optional) The port number for explicit proxy https protocol.
146 | - `pac_file` - (Optional) Specifies a SAS URL for PAC file.
147 | - `pac_file_port` - (Optional) Specifies a port number for firewall to serve PAC file.
148 |
149 | Type:
150 |
151 | ```hcl
152 | object({
153 | enable_pac_file = optional(bool)
154 | enabled = optional(bool)
155 | http_port = optional(number)
156 | https_port = optional(number)
157 | pac_file = optional(string)
158 | pac_file_port = optional(number)
159 | })
160 | ```
161 |
162 | Default: `null`
163 |
164 | ### [firewall\_policy\_identity](#input\_firewall\_policy\_identity)
165 |
166 | Description: - `identity_ids` - (Optional) Specifies a list of User Assigned Managed Identity IDs to be assigned to this Firewall Policy.
167 | - `type` - (Required) Specifies the type of Managed Service Identity that should be configured on this Firewall Policy. Only possible value is `UserAssigned`.
168 |
169 | Type:
170 |
171 | ```hcl
172 | object({
173 | identity_ids = optional(set(string))
174 | type = string
175 | })
176 | ```
177 |
178 | Default: `null`
179 |
180 | ### [firewall\_policy\_insights](#input\_firewall\_policy\_insights)
181 |
182 | Description: - `default_log_analytics_workspace_id` - (Required) The ID of the default Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to, when there is no location matches in the `log_analytics_workspace`.
183 | - `enabled` - (Required) Whether the insights functionality is enabled for this Firewall Policy.
184 | - `retention_in_days` - (Optional) The log retention period in days.
185 |
186 | ---
187 | `log_analytics_workspace` block supports the following:
188 | - `firewall_location` - (Required) The location of the Firewalls, that when matches this Log Analytics Workspace will be used to consume their logs.
189 | - `id` - (Required) The ID of the Log Analytics Workspace that the Firewalls associated with this Firewall Policy will send their logs to when their locations match the `firewall_location`.
190 |
191 | Type:
192 |
193 | ```hcl
194 | object({
195 | default_log_analytics_workspace_id = string
196 | enabled = bool
197 | retention_in_days = optional(number)
198 | log_analytics_workspace = optional(list(object({
199 | firewall_location = string
200 | id = string
201 | })))
202 | })
203 | ```
204 |
205 | Default: `null`
206 |
207 | ### [firewall\_policy\_intrusion\_detection](#input\_firewall\_policy\_intrusion\_detection)
208 |
209 | Description: - `mode` - (Optional) In which mode you want to run intrusion detection: `Off`, `Alert` or `Deny`.
210 | - `private_ranges` - (Optional) A list of Private IP address ranges to identify traffic direction. By default, only ranges defined by IANA RFC 1918 are considered private IP addresses.
211 |
212 | ---
213 | `signature_overrides` block supports the following:
214 | - `id` - (Optional) 12-digit number (id) which identifies your signature.
215 | - `state` - (Optional) state can be any of `Off`, `Alert` or `Deny`.
216 |
217 | ---
218 | `traffic_bypass` block supports the following:
219 | - `description` - (Optional) The description for this bypass traffic setting.
220 | - `destination_addresses` - (Optional) Specifies a list of destination IP addresses that shall be bypassed by intrusion detection.
221 | - `destination_ip_groups` - (Optional) Specifies a list of destination IP groups that shall be bypassed by intrusion detection.
222 | - `destination_ports` - (Optional) Specifies a list of destination IP ports that shall be bypassed by intrusion detection.
223 | - `name` - (Required) The name which should be used for this bypass traffic setting.
224 | - `protocol` - (Required) The protocols any of `ANY`, `TCP`, `ICMP`, `UDP` that shall be bypassed by intrusion detection.
225 | - `source_addresses` - (Optional) Specifies a list of source addresses that shall be bypassed by intrusion detection.
226 | - `source_ip_groups` - (Optional) Specifies a list of source IP groups that shall be bypassed by intrusion detection.
227 |
228 | Type:
229 |
230 | ```hcl
231 | object({
232 | mode = optional(string)
233 | private_ranges = optional(list(string))
234 | signature_overrides = optional(list(object({
235 | id = optional(string)
236 | state = optional(string)
237 | })))
238 | traffic_bypass = optional(list(object({
239 | description = optional(string)
240 | destination_addresses = optional(set(string))
241 | destination_ip_groups = optional(set(string))
242 | destination_ports = optional(set(string))
243 | name = string
244 | protocol = string
245 | source_addresses = optional(set(string))
246 | source_ip_groups = optional(set(string))
247 | })))
248 | })
249 | ```
250 |
251 | Default: `null`
252 |
253 | ### [firewall\_policy\_private\_ip\_ranges](#input\_firewall\_policy\_private\_ip\_ranges)
254 |
255 | Description: (Optional) A list of private IP ranges to which traffic will not be SNAT.
256 |
257 | Type: `list(string)`
258 |
259 | Default: `null`
260 |
261 | ### [firewall\_policy\_sku](#input\_firewall\_policy\_sku)
262 |
263 | Description: (Optional) The SKU Tier of the Firewall Policy. Possible values are `Standard`, `Premium` and `Basic`. Changing this forces a new Firewall Policy to be created.
264 |
265 | Type: `string`
266 |
267 | Default: `null`
268 |
269 | ### [firewall\_policy\_sql\_redirect\_allowed](#input\_firewall\_policy\_sql\_redirect\_allowed)
270 |
271 | Description: (Optional) Whether SQL Redirect traffic filtering is allowed. Enabling this flag requires no rule using ports between `11000`-`11999`.
272 |
273 | Type: `bool`
274 |
275 | Default: `null`
276 |
277 | ### [firewall\_policy\_threat\_intelligence\_allowlist](#input\_firewall\_policy\_threat\_intelligence\_allowlist)
278 |
279 | Description: - `fqdns` - (Optional) A list of FQDNs that will be skipped for threat detection.
280 | - `ip_addresses` - (Optional) A list of IP addresses or CIDR ranges that will be skipped for threat detection.
281 |
282 | Type:
283 |
284 | ```hcl
285 | object({
286 | fqdns = optional(set(string))
287 | ip_addresses = optional(set(string))
288 | })
289 | ```
290 |
291 | Default: `null`
292 |
293 | ### [firewall\_policy\_threat\_intelligence\_mode](#input\_firewall\_policy\_threat\_intelligence\_mode)
294 |
295 | Description: (Optional) The operation mode for Threat Intelligence. Possible values are `Alert`, `Deny` and `Off`. Defaults to `Alert`.
296 |
297 | Type: `string`
298 |
299 | Default: `null`
300 |
301 | ### [firewall\_policy\_timeouts](#input\_firewall\_policy\_timeouts)
302 |
303 | Description: - `create` - (Defaults to 30 minutes) Used when creating the Firewall Policy.
304 | - `delete` - (Defaults to 30 minutes) Used when deleting the Firewall Policy.
305 | - `read` - (Defaults to 5 minutes) Used when retrieving the Firewall Policy.
306 | - `update` - (Defaults to 30 minutes) Used when updating the Firewall Policy.
307 |
308 | Type:
309 |
310 | ```hcl
311 | object({
312 | create = optional(string)
313 | delete = optional(string)
314 | read = optional(string)
315 | update = optional(string)
316 | })
317 | ```
318 |
319 | Default: `null`
320 |
321 | ### [firewall\_policy\_tls\_certificate](#input\_firewall\_policy\_tls\_certificate)
322 |
323 | Description: - `key_vault_secret_id` - (Required) The ID of the Key Vault, where the secret or certificate is stored.
324 | - `name` - (Required) The name of the certificate.
325 |
326 | Type:
327 |
328 | ```hcl
329 | object({
330 | key_vault_secret_id = string
331 | name = string
332 | })
333 | ```
334 |
335 | Default: `null`
336 |
337 | ### [lock](#input\_lock)
338 |
339 | Description: Controls the Resource Lock configuration for this resource. The following properties can be specified:
340 |
341 | - `kind` - (Required) The type of lock. Possible values are `\"CanNotDelete\"` and `\"ReadOnly\"`.
342 | - `name` - (Optional) The name of the lock. If not specified, a name will be generated based on the `kind` value. Changing this forces the creation of a new resource.
343 |
344 | Type:
345 |
346 | ```hcl
347 | object({
348 | kind = string
349 | name = optional(string, null)
350 | })
351 | ```
352 |
353 | Default: `null`
354 |
355 | ### [role\_assignments](#input\_role\_assignments)
356 |
357 | Description: A map of role assignments to create on the . The map key is deliberately arbitrary to avoid issues where map keys maybe unknown at plan time.
358 |
359 | - `role_definition_id_or_name` - The ID or name of the role definition to assign to the principal.
360 | - `principal_id` - The ID of the principal to assign the role to.
361 | - `description` - (Optional) The description of the role assignment.
362 | - `skip_service_principal_aad_check` - (Optional) If set to true, skips the Azure Active Directory check for the service principal in the tenant. Defaults to false.
363 | - `condition` - (Optional) The condition which will be used to scope the role assignment.
364 | - `condition_version` - (Optional) The version of the condition syntax. Leave as `null` if you are not using a condition, if you are then valid values are '2.0'.
365 | - `delegated_managed_identity_resource_id` - (Optional) The delegated Azure Resource Id which contains a Managed Identity. Changing this forces a new resource to be created. This field is only used in cross-tenant scenario.
366 | - `principal_type` - (Optional) The type of the `principal_id`. Possible values are `User`, `Group` and `ServicePrincipal`. It is necessary to explicitly set this attribute when creating role assignments if the principal creating the assignment is constrained by ABAC rules that filters on the PrincipalType attribute.
367 |
368 | > Note: only set `skip_service_principal_aad_check` to true if you are assigning a role to a service principal.
369 |
370 | Type:
371 |
372 | ```hcl
373 | map(object({
374 | role_definition_id_or_name = string
375 | principal_id = string
376 | description = optional(string, null)
377 | skip_service_principal_aad_check = optional(bool, false)
378 | condition = optional(string, null)
379 | condition_version = optional(string, null)
380 | delegated_managed_identity_resource_id = optional(string, null)
381 | principal_type = optional(string, null)
382 | }))
383 | ```
384 |
385 | Default: `{}`
386 |
387 | ### [tags](#input\_tags)
388 |
389 | Description: (Optional) A mapping of tags to assign to the resource.
390 |
391 | Type: `map(string)`
392 |
393 | Default: `null`
394 |
395 | ## Outputs
396 |
397 | The following outputs are exported:
398 |
399 | ### [resource](#output\_resource)
400 |
401 | Description: "This is the full output for Firewall Policy resource. This is the default output for the module following AVM standards. Review the examples below for the correct output to use in your module."
402 | Examples:
403 | - module.firewall\_policy.resource.id
404 | - module.firewall\_policy.resource.firewalls
405 | - module.firewall\_policy.resource.child\_policies
406 | - module.firewall\_policy.resource.rule\_collection\_groups
407 |
408 | ### [resource\_id](#output\_resource\_id)
409 |
410 | Description: the resource id of the firewall policy
411 |
412 | ## Modules
413 |
414 | No modules.
415 |
416 |
417 | ## Data Collection
418 |
419 | 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. 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.
420 |
--------------------------------------------------------------------------------