diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aeceb727dd..dd7d4654fc 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -98,7 +98,7 @@ /avm/res/network/network-interface/ @Azure/avm-res-network-networkinterface-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/network-manager/ @Azure/avm-res-network-networkmanager-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/network-security-group/ @Azure/avm-res-network-networksecuritygroup-module-owners-bicep @Azure/avm-core-team-technical-bicep -#/avm/res/network/network-watcher/ @Azure/avm-res-network-networkwatcher-module-owners-bicep @Azure/avm-core-team-technical-bicep +/avm/res/network/network-watcher/ @Azure/avm-res-network-networkwatcher-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/private-dns-zone/ @Azure/avm-res-network-privatednszone-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/private-endpoint/ @Azure/avm-res-network-privateendpoint-module-owners-bicep @Azure/avm-core-team-technical-bicep /avm/res/network/private-link-service/ @Azure/avm-res-network-privatelinkservice-module-owners-bicep @Azure/avm-core-team-technical-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index a1f30bffbc..9fea2a0a2e 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -131,7 +131,7 @@ body: - "avm/res/network/network-interface" - "avm/res/network/network-manager" - "avm/res/network/network-security-group" - # - "avm/res/network/network-watcher" + - "avm/res/network/network-watcher" - "avm/res/network/private-dns-zone" - "avm/res/network/private-endpoint" - "avm/res/network/private-link-service" diff --git a/.github/workflows/avm.platform.manage-workflow-issue.yml b/.github/workflows/avm.platform.manage-workflow-issue.yml index 8d37f57d3d..9c80793d18 100644 --- a/.github/workflows/avm.platform.manage-workflow-issue.yml +++ b/.github/workflows/avm.platform.manage-workflow-issue.yml @@ -3,6 +3,7 @@ name: "avm.platform.manage-workflow-issue" on: schedule: - cron: "30 5 * * *" # Every day at 5:30 am + workflow_dispatch: jobs: manage-issues: @@ -14,16 +15,22 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - env: - GH_TOKEN: ${{ github.token }} - name: Manage issues + - uses: tibdex/github-app-token@v2 + id: generate-token + with: + app_id: ${{ secrets.APP_ID }} + private_key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Manage issues shell: pwsh + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} run: | # Load used functions . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Set-AvmGithubIssueForWorkflow.ps1') $functionInput = @{ Repo = "${{ github.repository_owner }}/${{ github.event.repository.name }}" + RepoRoot = $env:GITHUB_WORKSPACE LimitNumberOfRuns = 500 LimitInDays = 2 IgnoreWorkflows = @() diff --git a/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml b/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml index 775d83c94d..48cc265747 100644 --- a/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml +++ b/.github/workflows/avm.platform.set-avm-github-issue-owner-config.yml @@ -16,16 +16,22 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - env: - GH_TOKEN: ${{ github.token }} - name: "Run scripts" + - uses: tibdex/github-app-token@v2 + id: generate-token + with: + app_id: ${{ secrets.TEAM_LINTER_APP_ID }} + private_key: ${{ secrets.TEAM_LINTER_PRIVATE_KEY }} + - name: "Run scripts" shell: pwsh + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} run: | # Load used functions - . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Set-AvmGitHubIssueOwnerConfig.ps1') + . (Join-Path $env:GITHUB_WORKSPACE 'avm' 'utilities' 'pipelines' 'platform' 'Set-AvmGitHubIssueOwnerConfig.ps1') $functionInput = @{ - Repo = "${{ github.repository_owner }}/${{ github.event.repository.name }}" + Repo = "${{ github.repository_owner }}/${{ github.event.repository.name }}" + RepoRoot = $env:GITHUB_WORKSPACE IssueUrl = "${{ github.event.issue.url }}" } diff --git a/.github/workflows/avm.res.aad.domain-service.yml b/.github/workflows/avm.res.aad.domain-service.yml index b5eb8d5e6a..b6c0a5883f 100644 --- a/.github/workflows/avm.res.aad.domain-service.yml +++ b/.github/workflows/avm.res.aad.domain-service.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.aad.domain-service.yml" - "avm/res/aad/domain-service/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/.github/workflows/avm.res.container-instance.container-group.yml b/.github/workflows/avm.res.container-instance.container-group.yml index 5f40c3cc22..9782de00fa 100644 --- a/.github/workflows/avm.res.container-instance.container-group.yml +++ b/.github/workflows/avm.res.container-instance.container-group.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.container-instance.container-group.yml" - "avm/res/container-instance/container-group/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml b/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml index 71b6b56d1a..fc9e6fb5da 100644 --- a/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml +++ b/.github/workflows/avm.res.digital-twins.digital-twins-instance.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.digital-twins.digital-twins-instance.yml" - "avm/res/digital-twins/digital-twins-instance/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/.github/workflows/avm.res.network.network-watcher.yml b/.github/workflows/avm.res.network.network-watcher.yml new file mode 100644 index 0000000000..823b4baf3e --- /dev/null +++ b/.github/workflows/avm.res.network.network-watcher.yml @@ -0,0 +1,87 @@ +name: "avm.res.network.network-watcher" + +on: + schedule: + - cron: "0 12 1/15 * *" # Bi-Weekly Test (on 1st & 15th of month) + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.network.network-watcher.yml" + - "avm/res/network/network-watcher/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/network/network-watcher" + workflowPath: ".github/workflows/avm.res.network.network-watcher.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/.github/workflows/avm.res.network.service-endpoint-policy.yml b/.github/workflows/avm.res.network.service-endpoint-policy.yml index def975dfe0..80e26edeac 100644 --- a/.github/workflows/avm.res.network.service-endpoint-policy.yml +++ b/.github/workflows/avm.res.network.service-endpoint-policy.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.network.service-endpoint-policy.yml" - "avm/res/network/service-endpoint-policy/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/.github/workflows/avm.res.recovery-services.vault.yml b/.github/workflows/avm.res.recovery-services.vault.yml index bc630cebbc..9d5a1dc1ff 100644 --- a/.github/workflows/avm.res.recovery-services.vault.yml +++ b/.github/workflows/avm.res.recovery-services.vault.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.recovery-services.vault.yml" - "avm/res/recovery-services/vault/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/.github/workflows/avm.res.service-fabric.cluster.yml b/.github/workflows/avm.res.service-fabric.cluster.yml index 93c11bbf84..2e2c93206c 100644 --- a/.github/workflows/avm.res.service-fabric.cluster.yml +++ b/.github/workflows/avm.res.service-fabric.cluster.yml @@ -29,6 +29,7 @@ on: - ".github/workflows/avm.res.service-fabric.cluster.yml" - "avm/res/service-fabric/cluster/**" - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" - "!*/**/README.md" env: diff --git a/avm/res/aad/domain-service/README.md b/avm/res/aad/domain-service/README.md index 640ab0847b..87f33b1d5f 100644 --- a/avm/res/aad/domain-service/README.md +++ b/avm/res/aad/domain-service/README.md @@ -56,7 +56,7 @@ module domainService 'br/public:avm/res/aad/domain-service:' = { eventHubName: '' logCategoriesAndGroups: [ { - category: 'AllLogs' + categoryGroup: 'allLogs' } ] metricCategories: [ @@ -124,7 +124,7 @@ module domainService 'br/public:avm/res/aad/domain-service:' = { "eventHubName": "", "logCategoriesAndGroups": [ { - "category": "AllLogs" + "categoryGroup": "allLogs" } ], "metricCategories": [ diff --git a/avm/res/aad/domain-service/main.json b/avm/res/aad/domain-service/main.json index 84a4f00d14..c210fd41ff 100644 --- a/avm/res/aad/domain-service/main.json +++ b/avm/res/aad/domain-service/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "7386947428934165964" + "version": "0.26.54.24096", + "templateHash": "10683253750371964167" }, "name": "Azure Active Directory Domain Services", "description": "This module deploys an Azure Active Directory Domain Services (AADDS).", diff --git a/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep b/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep index e4af67fbc9..90db155b23 100644 --- a/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/aad/domain-service/tests/e2e/waf-aligned/main.test.bicep @@ -87,7 +87,7 @@ module testDeployment '../../../main.bicep' = { ] logCategoriesAndGroups: [ { - category: 'AllLogs' + categoryGroup: 'allLogs' } ] storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId @@ -155,7 +155,7 @@ module testDeploymentIdem '../../../main.bicep' = { ] logCategoriesAndGroups: [ { - category: 'AllLogs' + categoryGroup: 'allLogs' } ] storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId diff --git a/avm/res/automation/automation-account/README.md b/avm/res/automation/automation-account/README.md index 27d88eee16..26fd342e22 100644 --- a/avm/res/automation/automation-account/README.md +++ b/avm/res/automation/automation-account/README.md @@ -1463,6 +1463,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -1665,6 +1666,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/automation/automation-account/main.bicep b/avm/res/automation/automation-account/main.bicep index 4d401435a5..3f579884c4 100644 --- a/avm/res/automation/automation-account/main.bicep +++ b/avm/res/automation/automation-account/main.bicep @@ -584,6 +584,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') service: string diff --git a/avm/res/automation/automation-account/main.json b/avm/res/automation/automation-account/main.json index 758ecb9deb..ef54d7a09b 100644 --- a/avm/res/automation/automation-account/main.json +++ b/avm/res/automation/automation-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "6251765763506796385" + "templateHash": "16001446000186457588" }, "name": "Automation Accounts", "description": "This module deploys an Azure Automation Account.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "metadata": { diff --git a/avm/res/batch/batch-account/README.md b/avm/res/batch/batch-account/README.md index 045ce70467..f2d6ddd938 100644 --- a/avm/res/batch/batch-account/README.md +++ b/avm/res/batch/batch-account/README.md @@ -1093,6 +1093,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -1295,6 +1296,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/batch/batch-account/main.bicep b/avm/res/batch/batch-account/main.bicep index 84657dc22e..b74ebf3012 100644 --- a/avm/res/batch/batch-account/main.bicep +++ b/avm/res/batch/batch-account/main.bicep @@ -420,6 +420,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') service: string diff --git a/avm/res/batch/batch-account/main.json b/avm/res/batch/batch-account/main.json index 1dcab47561..918b144932 100644 --- a/avm/res/batch/batch-account/main.json +++ b/avm/res/batch/batch-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "6890367843750826610" + "templateHash": "11103817479788393007" }, "name": "Batch Accounts", "description": "This module deploys a Batch Account.", @@ -218,6 +218,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "metadata": { diff --git a/avm/res/cache/redis/README.md b/avm/res/cache/redis/README.md index 78ea24c202..a8e005dfd5 100644 --- a/avm/res/cache/redis/README.md +++ b/avm/res/cache/redis/README.md @@ -858,6 +858,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1054,6 +1055,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/cache/redis/main.bicep b/avm/res/cache/redis/main.bicep index 92250dddf6..a7975ce724 100644 --- a/avm/res/cache/redis/main.bicep +++ b/avm/res/cache/redis/main.bicep @@ -354,6 +354,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/cache/redis/main.json b/avm/res/cache/redis/main.json index d1d6787625..0dcf9d3c88 100644 --- a/avm/res/cache/redis/main.json +++ b/avm/res/cache/redis/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "14239657026051186935" + "templateHash": "7874819819895628744" }, "name": "Redis Cache", "description": "This module deploys a Redis Cache.", @@ -80,6 +80,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index ad3aa7e878..587b599762 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1241,6 +1241,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1437,6 +1438,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index fdac84cba9..d88001d7f3 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -549,6 +549,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 35f3b05f87..db28c215b9 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "4464138557763734337" + "templateHash": "1728463055074429069" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -218,6 +218,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/compute/virtual-machine/main.bicep b/avm/res/compute/virtual-machine/main.bicep index a15b26418c..1fe7b22def 100644 --- a/avm/res/compute/virtual-machine/main.bicep +++ b/avm/res/compute/virtual-machine/main.bicep @@ -330,7 +330,7 @@ var formattedUserAssignedIdentities = reduce( var identity = !empty(managedIdentities) ? { type: (extensionAadJoinConfig.enabled ? true : (managedIdentities.?systemAssigned ?? false)) - ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned,UserAssigned' : 'SystemAssigned') + ? (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'SystemAssigned, UserAssigned' : 'SystemAssigned') : (!empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : null) userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null } @@ -554,7 +554,7 @@ resource vm 'Microsoft.Compute/virtualMachines@2022-11-01' = { evictionPolicy: enableEvictionPolicy ? 'Deallocate' : null billingProfile: !empty(priority) && !empty(maxPriceForLowPriorityVm) ? { - maxPrice: maxPriceForLowPriorityVm + maxPrice: json(maxPriceForLowPriorityVm) } : null host: !empty(dedicatedHostId) diff --git a/avm/res/compute/virtual-machine/main.json b/avm/res/compute/virtual-machine/main.json index 65a9cdeb1e..5d9c60bd68 100644 --- a/avm/res/compute/virtual-machine/main.json +++ b/avm/res/compute/virtual-machine/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "11337690191653715343" + "version": "0.26.54.24096", + "templateHash": "5410471245439722622" }, "name": "Virtual Machines", "description": "This module deploys a Virtual Machine with one or multiple NICs and optionally one or multiple public IPs.", @@ -684,7 +684,7 @@ "signedProtocol": "https" }, "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", - "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(if(parameters('extensionAadJoinConfig').enabled, true(), coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false())), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Data Operator for Managed Disks": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '959f8984-c045-4866-89c7-12bf9737be2e')]", @@ -815,7 +815,7 @@ "proximityPlacementGroup": "[if(not(empty(parameters('proximityPlacementGroupResourceId'))), createObject('id', parameters('proximityPlacementGroupResourceId')), null())]", "priority": "[parameters('priority')]", "evictionPolicy": "[if(parameters('enableEvictionPolicy'), 'Deallocate', null())]", - "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', parameters('maxPriceForLowPriorityVm')), null())]", + "billingProfile": "[if(and(not(empty(parameters('priority'))), not(empty(parameters('maxPriceForLowPriorityVm')))), createObject('maxPrice', json(parameters('maxPriceForLowPriorityVm'))), null())]", "host": "[if(not(empty(parameters('dedicatedHostId'))), createObject('id', parameters('dedicatedHostId')), null())]", "licenseType": "[if(not(empty(parameters('licenseType'))), parameters('licenseType'), null())]" }, @@ -949,8 +949,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "4698911337326052062" + "version": "0.26.54.24096", + "templateHash": "13415879962041783892" } }, "definitions": { @@ -2419,8 +2419,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -2625,8 +2625,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -2827,8 +2827,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3041,8 +3041,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3239,8 +3239,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3436,8 +3436,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3637,8 +3637,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -3846,8 +3846,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4047,8 +4047,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4246,8 +4246,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4436,8 +4436,8 @@ "enableAutomaticUpgrade": "[if(contains(parameters('extensionHostPoolRegistration'), 'enableAutomaticUpgrade'), createObject('value', parameters('extensionHostPoolRegistration').enableAutomaticUpgrade), createObject('value', false()))]", "settings": { "value": { - "modulesUrl": "[parameters('extensionHostPoolRegistration').hostPoolModulesUrl]", - "configurationFunction": "[coalesce(tryGet(parameters('extensionHostPoolRegistration'), 'configurationFunction'), 'Configuration.ps1\\AddSessionHost')]", + "modulesUrl": "[parameters('extensionHostPoolRegistration').modulesUrl]", + "configurationFunction": "[parameters('extensionHostPoolRegistration').configurationFunction]", "properties": { "hostPoolName": "[parameters('extensionHostPoolRegistration').hostPoolName]", "registrationInfoToken": "[parameters('extensionHostPoolRegistration').registrationInfoToken]", @@ -4456,8 +4456,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4656,8 +4656,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "5949079428725139834" + "version": "0.26.54.24096", + "templateHash": "16251967456691023698" }, "name": "Virtual Machine Extensions", "description": "This module deploys a Virtual Machine Extension.", @@ -4855,8 +4855,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.25.53.49325", - "templateHash": "15677187951825533891" + "version": "0.26.54.24096", + "templateHash": "5385249890312845255" }, "name": "Recovery Service Vaults Protection Container Protected Item", "description": "This module deploys a Recovery Services Vault Protection Container Protected Item.", diff --git a/avm/res/compute/virtual-machine/version.json b/avm/res/compute/virtual-machine/version.json index 729ac87673..76049e1c4a 100644 --- a/avm/res/compute/virtual-machine/version.json +++ b/avm/res/compute/virtual-machine/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.2", + "version": "0.3", "pathFilters": [ "./main.json" ] diff --git a/avm/res/container-service/managed-cluster/README.md b/avm/res/container-service/managed-cluster/README.md index ec4fc5f535..9c6755ddb5 100644 --- a/avm/res/container-service/managed-cluster/README.md +++ b/avm/res/container-service/managed-cluster/README.md @@ -3233,7 +3233,9 @@ Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. | `ingressApplicationGatewayIdentityObjectId` | string | The Object ID of Application Gateway Ingress Controller (AGIC) identity. | | `keyvaultIdentityClientId` | string | The Client ID of the Key Vault Secrets Provider identity. | | `keyvaultIdentityObjectId` | string | The Object ID of the Key Vault Secrets Provider identity. | -| `kubeletidentityObjectId` | string | The Object ID of the AKS identity. | +| `kubeletIdentityClientId` | string | The Client ID of the AKS identity. | +| `kubeletIdentityObjectId` | string | The Object ID of the AKS identity. | +| `kubeletIdentityResourceId` | string | The Resource ID of the AKS identity. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the managed cluster. | | `oidcIssuerUrl` | string | The OIDC token issuer URL. | diff --git a/avm/res/container-service/managed-cluster/main.bicep b/avm/res/container-service/managed-cluster/main.bicep index 492fb55b86..d8ffe6bc8f 100644 --- a/avm/res/container-service/managed-cluster/main.bicep +++ b/avm/res/container-service/managed-cluster/main.bicep @@ -892,8 +892,14 @@ output controlPlaneFQDN string = enablePrivateCluster @description('The principal ID of the system assigned identity.') output systemAssignedMIPrincipalId string = managedCluster.?identity.?principalId ?? '' +@description('The Client ID of the AKS identity.') +output kubeletIdentityClientId string = managedCluster.properties.?identityProfile.?kubeletidentity.?clientId ?? '' + @description('The Object ID of the AKS identity.') -output kubeletidentityObjectId string = managedCluster.properties.?identityProfile.?kubeletidentity.?objectId ?? '' +output kubeletIdentityObjectId string = managedCluster.properties.?identityProfile.?kubeletidentity.?objectId ?? '' + +@description('The Resource ID of the AKS identity.') +output kubeletIdentityResourceId string = managedCluster.properties.?identityProfile.?kubeletidentity.?resourceId ?? '' @description('The Object ID of the OMS agent identity.') output omsagentIdentityObjectId string = managedCluster.properties.?addonProfiles.?omsagent.?identity.?objectId ?? '' diff --git a/avm/res/container-service/managed-cluster/main.json b/avm/res/container-service/managed-cluster/main.json index e1f4ab5d28..b8fc5076be 100644 --- a/avm/res/container-service/managed-cluster/main.json +++ b/avm/res/container-service/managed-cluster/main.json @@ -2736,13 +2736,27 @@ }, "value": "[coalesce(tryGet(tryGet(reference('managedCluster', '2023-07-02-preview', 'full'), 'identity'), 'principalId'), '')]" }, - "kubeletidentityObjectId": { + "kubeletIdentityClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'clientId'), '')]" + }, + "kubeletIdentityObjectId": { "type": "string", "metadata": { "description": "The Object ID of the AKS identity." }, "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'objectId'), '')]" }, + "kubeletIdentityResourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'resourceId'), '')]" + }, "omsagentIdentityObjectId": { "type": "string", "metadata": { diff --git a/avm/res/data-factory/factory/README.md b/avm/res/data-factory/factory/README.md index bda24aa203..7dab0aa926 100644 --- a/avm/res/data-factory/factory/README.md +++ b/avm/res/data-factory/factory/README.md @@ -912,6 +912,7 @@ Configuration Details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1108,6 +1109,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/data-factory/factory/main.bicep b/avm/res/data-factory/factory/main.bicep index c82317923d..b8214de937 100644 --- a/avm/res/data-factory/factory/main.bicep +++ b/avm/res/data-factory/factory/main.bicep @@ -408,6 +408,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/data-factory/factory/main.json b/avm/res/data-factory/factory/main.json index aad72cb4c9..660811ad99 100644 --- a/avm/res/data-factory/factory/main.json +++ b/avm/res/data-factory/factory/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "14187397977187427796" + "templateHash": "15112622274427305357" }, "name": "Data Factories", "description": "This module deploys a Data Factory.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/digital-twins/digital-twins-instance/README.md b/avm/res/digital-twins/digital-twins-instance/README.md index 1c7a729b3b..61d336db5c 100644 --- a/avm/res/digital-twins/digital-twins-instance/README.md +++ b/avm/res/digital-twins/digital-twins-instance/README.md @@ -780,6 +780,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Privte Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -976,6 +977,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Privte Endpoint into a different resource group than the main resource. diff --git a/avm/res/digital-twins/digital-twins-instance/main.bicep b/avm/res/digital-twins/digital-twins-instance/main.bicep index 7343b751e7..e1c317709d 100644 --- a/avm/res/digital-twins/digital-twins-instance/main.bicep +++ b/avm/res/digital-twins/digital-twins-instance/main.bicep @@ -362,6 +362,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/digital-twins/digital-twins-instance/main.json b/avm/res/digital-twins/digital-twins-instance/main.json index 50fc49a6d8..be1138a612 100644 --- a/avm/res/digital-twins/digital-twins-instance/main.json +++ b/avm/res/digital-twins/digital-twins-instance/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "592119492280088110" + "templateHash": "16174863317053860668" }, "name": "Digital Twins Instances", "description": "This module deploys an Azure Digital Twins Instance.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/document-db/database-account/README.md b/avm/res/document-db/database-account/README.md index 6ae99ad652..fa45217f9c 100644 --- a/avm/res/document-db/database-account/README.md +++ b/avm/res/document-db/database-account/README.md @@ -2772,6 +2772,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -2974,6 +2975,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/document-db/database-account/main.bicep b/avm/res/document-db/database-account/main.bicep index 353f3a673f..5cbfbfe85d 100644 --- a/avm/res/document-db/database-account/main.bicep +++ b/avm/res/document-db/database-account/main.bicep @@ -599,6 +599,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') service: string diff --git a/avm/res/document-db/database-account/main.json b/avm/res/document-db/database-account/main.json index bb1a275336..943fa8af42 100644 --- a/avm/res/document-db/database-account/main.json +++ b/avm/res/document-db/database-account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "4437379960992955499" + "templateHash": "9794166259717067711" }, "name": "DocumentDB Database Accounts", "description": "This module deploys a DocumentDB Database Account.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "metadata": { diff --git a/avm/res/event-grid/domain/README.md b/avm/res/event-grid/domain/README.md index ae021496d2..11e5d6818e 100644 --- a/avm/res/event-grid/domain/README.md +++ b/avm/res/event-grid/domain/README.md @@ -745,6 +745,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -941,6 +942,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/event-grid/domain/main.bicep b/avm/res/event-grid/domain/main.bicep index 9470ab66dd..0473c974c1 100644 --- a/avm/res/event-grid/domain/main.bicep +++ b/avm/res/event-grid/domain/main.bicep @@ -324,6 +324,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/event-grid/domain/main.json b/avm/res/event-grid/domain/main.json index 00d1d38a99..f47aa20bf6 100644 --- a/avm/res/event-grid/domain/main.json +++ b/avm/res/event-grid/domain/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "16218993533368650481" + "templateHash": "17171097905179773848" }, "name": "Event Grid Domains", "description": "This module deploys an Event Grid Domain.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/event-grid/namespace/README.md b/avm/res/event-grid/namespace/README.md index 856afe7f04..3be6075be5 100644 --- a/avm/res/event-grid/namespace/README.md +++ b/avm/res/event-grid/namespace/README.md @@ -1710,6 +1710,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1906,6 +1907,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/event-grid/namespace/main.bicep b/avm/res/event-grid/namespace/main.bicep index 56edb55bdb..e76d65e7c2 100644 --- a/avm/res/event-grid/namespace/main.bicep +++ b/avm/res/event-grid/namespace/main.bicep @@ -491,6 +491,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/event-grid/namespace/main.json b/avm/res/event-grid/namespace/main.json index f5d24919c4..45f6ea4550 100644 --- a/avm/res/event-grid/namespace/main.json +++ b/avm/res/event-grid/namespace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "16128168138494478881" + "templateHash": "18358017202196196766" }, "name": "Event Grid Namespaces", "description": "This module deploys an Event Grid Namespace.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/event-grid/topic/README.md b/avm/res/event-grid/topic/README.md index c611785a80..c589fdc2a3 100644 --- a/avm/res/event-grid/topic/README.md +++ b/avm/res/event-grid/topic/README.md @@ -839,6 +839,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1035,6 +1036,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/event-grid/topic/main.bicep b/avm/res/event-grid/topic/main.bicep index 6f23833d93..b99f1f0bae 100644 --- a/avm/res/event-grid/topic/main.bicep +++ b/avm/res/event-grid/topic/main.bicep @@ -334,6 +334,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/event-grid/topic/main.json b/avm/res/event-grid/topic/main.json index 5d7ac45336..8cf80a5253 100644 --- a/avm/res/event-grid/topic/main.json +++ b/avm/res/event-grid/topic/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "3980392845295222742" + "templateHash": "16219476239317554941" }, "name": "Event Grid Topics", "description": "This module deploys an Event Grid Topic.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/insights/private-link-scope/README.md b/avm/res/insights/private-link-scope/README.md index ae2484afd1..33afa6a34b 100644 --- a/avm/res/insights/private-link-scope/README.md +++ b/avm/res/insights/private-link-scope/README.md @@ -941,6 +941,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1137,6 +1138,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/insights/private-link-scope/main.bicep b/avm/res/insights/private-link-scope/main.bicep index 111bb87167..787d7aaafa 100644 --- a/avm/res/insights/private-link-scope/main.bicep +++ b/avm/res/insights/private-link-scope/main.bicep @@ -271,6 +271,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/insights/private-link-scope/main.json b/avm/res/insights/private-link-scope/main.json index b0c5d75a20..8066330d58 100644 --- a/avm/res/insights/private-link-scope/main.json +++ b/avm/res/insights/private-link-scope/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "3043663816660820718" + "templateHash": "15594611995771551731" }, "name": "Azure Monitor Private Link Scopes", "description": "This module deploys an Azure Monitor Private Link Scope.", @@ -123,6 +123,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/key-vault/vault/README.md b/avm/res/key-vault/vault/README.md index 54df61a844..f86a29fbc3 100644 --- a/avm/res/key-vault/vault/README.md +++ b/avm/res/key-vault/vault/README.md @@ -1320,6 +1320,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1516,6 +1517,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/key-vault/vault/main.bicep b/avm/res/key-vault/vault/main.bicep index 4fa14810d9..57ee7e3197 100644 --- a/avm/res/key-vault/vault/main.bicep +++ b/avm/res/key-vault/vault/main.bicep @@ -459,6 +459,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/key-vault/vault/main.json b/avm/res/key-vault/vault/main.json index 903efb61de..9a39a19b56 100644 --- a/avm/res/key-vault/vault/main.json +++ b/avm/res/key-vault/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "7617547098704473732" + "templateHash": "15417452365743513256" }, "name": "Key Vaults", "description": "This module deploys a Key Vault.", @@ -218,6 +218,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index 8629811336..da0018a179 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -444,7 +444,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-app-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -456,12 +456,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-ase-tags' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -472,12 +472,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-ase-management' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -515,7 +515,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-network-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -535,6 +535,22 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { '*' ] } + { + description: 'allow azure devops' + destinationAddresses: [ + 'AzureDevOps' + ] + destinationPorts: [ + '443' + ] + name: 'allow-azure-devops' + protocols: [ + 'Any' + ] + sourceAddresses: [ + '*' + ] + } ] } } @@ -595,7 +611,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-app-rules", "properties": { "action": { - "type": "allow" + "type": "Allow" }, "priority": 100, "rules": [ @@ -607,12 +623,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-ase-tags", "protocols": [ { - "port": "80", - "protocolType": "HTTP" + "port": 80, + "protocolType": "Http" }, { - "port": "443", - "protocolType": "HTTPS" + "port": 443, + "protocolType": "Https" } ], "sourceAddresses": [ @@ -623,12 +639,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-ase-management", "protocols": [ { - "port": "80", - "protocolType": "HTTP" + "port": 80, + "protocolType": "Http" }, { - "port": "443", - "protocolType": "HTTPS" + "port": 443, + "protocolType": "Https" } ], "sourceAddresses": [ @@ -674,7 +690,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-network-rules", "properties": { "action": { - "type": "allow" + "type": "Allow" }, "priority": 100, "rules": [ @@ -693,6 +709,22 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "sourceAddresses": [ "*" ] + }, + { + "description": "allow azure devops", + "destinationAddresses": [ + "AzureDevOps" + ], + "destinationPorts": [ + "443" + ], + "name": "allow-azure-devops", + "protocols": [ + "Any" + ], + "sourceAddresses": [ + "*" + ] } ] } @@ -766,7 +798,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-app-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -778,12 +810,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-ase-tags' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -794,12 +826,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-ase-management' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -833,7 +865,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { name: 'allow-network-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -896,7 +928,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-app-rules", "properties": { "action": { - "type": "allow" + "type": "Allow" }, "priority": 100, "rules": [ @@ -908,12 +940,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-ase-tags", "protocols": [ { - "port": "80", - "protocolType": "HTTP" + "port": 80, + "protocolType": "Http" }, { - "port": "443", - "protocolType": "HTTPS" + "port": 443, + "protocolType": "Https" } ], "sourceAddresses": [ @@ -924,12 +956,12 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-ase-management", "protocols": [ { - "port": "80", - "protocolType": "HTTP" + "port": 80, + "protocolType": "Http" }, { - "port": "443", - "protocolType": "HTTPS" + "port": 443, + "protocolType": "Https" } ], "sourceAddresses": [ @@ -969,7 +1001,7 @@ module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { "name": "allow-network-rules", "properties": { "action": { - "type": "allow" + "type": "Allow" }, "priority": 100, "rules": [ @@ -1106,7 +1138,176 @@ Collection of application rule collections used by Azure Firewall. - Required: No - Type: array -- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationrulecollectionsname) | string | Name of the application rule collection. | +| [`properties`](#parameter-applicationrulecollectionsproperties) | object | Properties of the azure firewall application rule collection. | + +### Parameter: `applicationRuleCollections.name` + +Name of the application rule collection. + +- Required: Yes +- Type: string + +### Parameter: `applicationRuleCollections.properties` + +Properties of the azure firewall application rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-applicationrulecollectionspropertiesaction) | object | The action type of a rule collection. | +| [`priority`](#parameter-applicationrulecollectionspropertiespriority) | int | Priority of the application rule collection. | +| [`rules`](#parameter-applicationrulecollectionspropertiesrules) | array | Collection of rules used by a application rule collection. | + +### Parameter: `applicationRuleCollections.properties.action` + +The action type of a rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-applicationrulecollectionspropertiesactiontype) | string | The type of action. | + +### Parameter: `applicationRuleCollections.properties.action.type` + +The type of action. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Deny' + ] + ``` + +### Parameter: `applicationRuleCollections.properties.priority` + +Priority of the application rule collection. + +- Required: Yes +- Type: int + +### Parameter: `applicationRuleCollections.properties.rules` + +Collection of rules used by a application rule collection. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-applicationrulecollectionspropertiesrulesname) | string | Name of the application rule. | +| [`protocols`](#parameter-applicationrulecollectionspropertiesrulesprotocols) | array | Array of ApplicationRuleProtocols. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-applicationrulecollectionspropertiesrulesdescription) | string | Description of the rule. | +| [`fqdnTags`](#parameter-applicationrulecollectionspropertiesrulesfqdntags) | array | List of FQDN Tags for this rule. | +| [`sourceAddresses`](#parameter-applicationrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. | +| [`sourceIpGroups`](#parameter-applicationrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. | +| [`targetFqdns`](#parameter-applicationrulecollectionspropertiesrulestargetfqdns) | array | List of FQDNs for this rule. | + +### Parameter: `applicationRuleCollections.properties.rules.name` + +Name of the application rule. + +- Required: Yes +- Type: string + +### Parameter: `applicationRuleCollections.properties.rules.protocols` + +Array of ApplicationRuleProtocols. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`protocolType`](#parameter-applicationrulecollectionspropertiesrulesprotocolsprotocoltype) | string | Protocol type. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`port`](#parameter-applicationrulecollectionspropertiesrulesprotocolsport) | int | Port number for the protocol. | + +### Parameter: `applicationRuleCollections.properties.rules.protocols.protocolType` + +Protocol type. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Http' + 'Https' + 'Mssql' + ] + ``` + +### Parameter: `applicationRuleCollections.properties.rules.protocols.port` + +Port number for the protocol. + +- Required: No +- Type: int + +### Parameter: `applicationRuleCollections.properties.rules.description` + +Description of the rule. + +- Required: No +- Type: string + +### Parameter: `applicationRuleCollections.properties.rules.fqdnTags` + +List of FQDN Tags for this rule. + +- Required: No +- Type: array + +### Parameter: `applicationRuleCollections.properties.rules.sourceAddresses` + +List of source IP addresses for this rule. + +- Required: No +- Type: array + +### Parameter: `applicationRuleCollections.properties.rules.sourceIpGroups` + +List of source IpGroups for this rule. + +- Required: No +- Type: array + +### Parameter: `applicationRuleCollections.properties.rules.targetFqdns` + +List of FQDNs for this rule. + +- Required: No +- Type: array ### Parameter: `azureSkuTier` @@ -1352,7 +1553,175 @@ Collection of NAT rule collections used by Azure Firewall. - Required: No - Type: array -- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-natrulecollectionsname) | string | Name of the NAT rule collection. | +| [`properties`](#parameter-natrulecollectionsproperties) | object | Properties of the azure firewall NAT rule collection. | + +### Parameter: `natRuleCollections.name` + +Name of the NAT rule collection. + +- Required: Yes +- Type: string + +### Parameter: `natRuleCollections.properties` + +Properties of the azure firewall NAT rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-natrulecollectionspropertiesaction) | object | The action type of a NAT rule collection. | +| [`priority`](#parameter-natrulecollectionspropertiespriority) | int | Priority of the NAT rule collection. | +| [`rules`](#parameter-natrulecollectionspropertiesrules) | array | Collection of rules used by a NAT rule collection. | + +### Parameter: `natRuleCollections.properties.action` + +The action type of a NAT rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-natrulecollectionspropertiesactiontype) | string | The type of action. | + +### Parameter: `natRuleCollections.properties.action.type` + +The type of action. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Dnat' + 'Snat' + ] + ``` + +### Parameter: `natRuleCollections.properties.priority` + +Priority of the NAT rule collection. + +- Required: Yes +- Type: int + +### Parameter: `natRuleCollections.properties.rules` + +Collection of rules used by a NAT rule collection. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-natrulecollectionspropertiesrulesname) | string | Name of the NAT rule. | +| [`protocols`](#parameter-natrulecollectionspropertiesrulesprotocols) | array | Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-natrulecollectionspropertiesrulesdescription) | string | Description of the rule. | +| [`destinationAddresses`](#parameter-natrulecollectionspropertiesrulesdestinationaddresses) | array | List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags. | +| [`destinationPorts`](#parameter-natrulecollectionspropertiesrulesdestinationports) | array | List of destination ports. | +| [`sourceAddresses`](#parameter-natrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. | +| [`sourceIpGroups`](#parameter-natrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. | +| [`translatedAddress`](#parameter-natrulecollectionspropertiesrulestranslatedaddress) | string | The translated address for this NAT rule. | +| [`translatedFqdn`](#parameter-natrulecollectionspropertiesrulestranslatedfqdn) | string | The translated FQDN for this NAT rule. | +| [`translatedPort`](#parameter-natrulecollectionspropertiesrulestranslatedport) | string | The translated port for this NAT rule. | + +### Parameter: `natRuleCollections.properties.rules.name` + +Name of the NAT rule. + +- Required: Yes +- Type: string + +### Parameter: `natRuleCollections.properties.rules.protocols` + +Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'Any' + 'ICMP' + 'TCP' + 'UDP' + ] + ``` + +### Parameter: `natRuleCollections.properties.rules.description` + +Description of the rule. + +- Required: No +- Type: string + +### Parameter: `natRuleCollections.properties.rules.destinationAddresses` + +List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags. + +- Required: No +- Type: array + +### Parameter: `natRuleCollections.properties.rules.destinationPorts` + +List of destination ports. + +- Required: No +- Type: array + +### Parameter: `natRuleCollections.properties.rules.sourceAddresses` + +List of source IP addresses for this rule. + +- Required: No +- Type: array + +### Parameter: `natRuleCollections.properties.rules.sourceIpGroups` + +List of source IpGroups for this rule. + +- Required: No +- Type: array + +### Parameter: `natRuleCollections.properties.rules.translatedAddress` + +The translated address for this NAT rule. + +- Required: No +- Type: string + +### Parameter: `natRuleCollections.properties.rules.translatedFqdn` + +The translated FQDN for this NAT rule. + +- Required: No +- Type: string + +### Parameter: `natRuleCollections.properties.rules.translatedPort` + +The translated port for this NAT rule. + +- Required: No +- Type: string ### Parameter: `networkRuleCollections` @@ -1360,7 +1729,167 @@ Collection of network rule collections used by Azure Firewall. - Required: No - Type: array -- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-networkrulecollectionsname) | string | Name of the network rule collection. | +| [`properties`](#parameter-networkrulecollectionsproperties) | object | Properties of the azure firewall network rule collection. | + +### Parameter: `networkRuleCollections.name` + +Name of the network rule collection. + +- Required: Yes +- Type: string + +### Parameter: `networkRuleCollections.properties` + +Properties of the azure firewall network rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`action`](#parameter-networkrulecollectionspropertiesaction) | object | The action type of a rule collection. | +| [`priority`](#parameter-networkrulecollectionspropertiespriority) | int | Priority of the network rule collection. | +| [`rules`](#parameter-networkrulecollectionspropertiesrules) | array | Collection of rules used by a network rule collection. | + +### Parameter: `networkRuleCollections.properties.action` + +The action type of a rule collection. + +- Required: Yes +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`type`](#parameter-networkrulecollectionspropertiesactiontype) | string | The type of action. | + +### Parameter: `networkRuleCollections.properties.action.type` + +The type of action. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'Allow' + 'Deny' + ] + ``` + +### Parameter: `networkRuleCollections.properties.priority` + +Priority of the network rule collection. + +- Required: Yes +- Type: int + +### Parameter: `networkRuleCollections.properties.rules` + +Collection of rules used by a network rule collection. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-networkrulecollectionspropertiesrulesname) | string | Name of the network rule. | +| [`protocols`](#parameter-networkrulecollectionspropertiesrulesprotocols) | array | Array of AzureFirewallNetworkRuleProtocols. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-networkrulecollectionspropertiesrulesdescription) | string | Description of the rule. | +| [`destinationAddresses`](#parameter-networkrulecollectionspropertiesrulesdestinationaddresses) | array | List of destination IP addresses. | +| [`destinationFqdns`](#parameter-networkrulecollectionspropertiesrulesdestinationfqdns) | array | List of destination FQDNs. | +| [`destinationIpGroups`](#parameter-networkrulecollectionspropertiesrulesdestinationipgroups) | array | List of destination IP groups for this rule. | +| [`destinationPorts`](#parameter-networkrulecollectionspropertiesrulesdestinationports) | array | List of destination ports. | +| [`sourceAddresses`](#parameter-networkrulecollectionspropertiesrulessourceaddresses) | array | List of source IP addresses for this rule. | +| [`sourceIpGroups`](#parameter-networkrulecollectionspropertiesrulessourceipgroups) | array | List of source IpGroups for this rule. | + +### Parameter: `networkRuleCollections.properties.rules.name` + +Name of the network rule. + +- Required: Yes +- Type: string + +### Parameter: `networkRuleCollections.properties.rules.protocols` + +Array of AzureFirewallNetworkRuleProtocols. + +- Required: Yes +- Type: array +- Allowed: + ```Bicep + [ + 'Any' + 'ICMP' + 'TCP' + 'UDP' + ] + ``` + +### Parameter: `networkRuleCollections.properties.rules.description` + +Description of the rule. + +- Required: No +- Type: string + +### Parameter: `networkRuleCollections.properties.rules.destinationAddresses` + +List of destination IP addresses. + +- Required: No +- Type: array + +### Parameter: `networkRuleCollections.properties.rules.destinationFqdns` + +List of destination FQDNs. + +- Required: No +- Type: array + +### Parameter: `networkRuleCollections.properties.rules.destinationIpGroups` + +List of destination IP groups for this rule. + +- Required: No +- Type: array + +### Parameter: `networkRuleCollections.properties.rules.destinationPorts` + +List of destination ports. + +- Required: No +- Type: array + +### Parameter: `networkRuleCollections.properties.rules.sourceAddresses` + +List of source IP addresses for this rule. + +- Required: No +- Type: array + +### Parameter: `networkRuleCollections.properties.rules.sourceIpGroups` + +List of source IpGroups for this rule. + +- Required: No +- Type: array ### Parameter: `publicIPAddressObject` diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep index 08f4af0cc2..3176534913 100644 --- a/avm/res/network/azure-firewall/main.bicep +++ b/avm/res/network/azure-firewall/main.bicep @@ -34,13 +34,13 @@ param managementIPResourceID string = '' param managementIPAddressObject object = {} @description('Optional. Collection of application rule collections used by Azure Firewall.') -param applicationRuleCollections array = [] +param applicationRuleCollections applicationRuleCollectionType @description('Optional. Collection of network rule collections used by Azure Firewall.') -param networkRuleCollections array = [] +param networkRuleCollections networkRuleCollectionType @description('Optional. Collection of NAT rule collections used by Azure Firewall.') -param natRuleCollections array = [] +param natRuleCollections natRuleCollectionType @description('Optional. Resource ID of the Firewall Policy that should be attached.') param firewallPolicyId string = '' @@ -261,41 +261,33 @@ resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = { location: location zones: length(zones) == 0 ? null : zones tags: tags - properties: azureSkuName == 'AZFW_VNet' - ? { - threatIntelMode: threatIntelMode - firewallPolicy: !empty(firewallPolicyId) - ? { - id: firewallPolicyId - } - : null - ipConfigurations: ipConfigurations - managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null - sku: { - name: azureSkuName - tier: azureSkuTier - } - applicationRuleCollections: applicationRuleCollections - natRuleCollections: natRuleCollections - networkRuleCollections: networkRuleCollections - } - : { - firewallPolicy: !empty(firewallPolicyId) - ? { - id: firewallPolicyId - } - : null - sku: { - name: azureSkuName - tier: azureSkuTier - } - hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null - virtualHub: !empty(virtualHubId) - ? { - id: virtualHubId - } - : null - } + properties: azureSkuName == 'AZFW_VNet' ? { + threatIntelMode: threatIntelMode + firewallPolicy: !empty(firewallPolicyId) ? { + id: firewallPolicyId + } : null + ipConfigurations: ipConfigurations + managementIpConfiguration: requiresManagementIp ? managementIPConfiguration : null + sku: { + name: azureSkuName + tier: azureSkuTier + } + applicationRuleCollections: applicationRuleCollections ?? [] + natRuleCollections: natRuleCollections ?? [] + networkRuleCollections: networkRuleCollections ?? [] + } : { + firewallPolicy: !empty(firewallPolicyId) ? { + id: firewallPolicyId + } : null + sku: { + name: azureSkuName + tier: azureSkuTier + } + hubIPAddresses: !empty(hubIPAddresses) ? hubIPAddresses : null + virtualHub: !empty(virtualHubId) ? { + id: virtualHubId + } : null + } } resource azureFirewall_lock 'Microsoft.Authorization/locks@2020-05-01' = @@ -379,13 +371,13 @@ output ipConfAzureFirewallSubnet object = contains(azureFirewall.properties, 'ip : {} @description('List of Application Rule Collections.') -output applicationRuleCollections array = applicationRuleCollections +output applicationRuleCollections array = applicationRuleCollections ?? [] @description('List of Network Rule Collections.') -output networkRuleCollections array = networkRuleCollections +output networkRuleCollections array = networkRuleCollections ?? [] @description('Collection of NAT rule collections used by Azure Firewall.') -output natRuleCollections array = natRuleCollections +output natRuleCollections array = natRuleCollections ?? [] @description('The location the resource was deployed into.') output location string = azureFirewall.location @@ -468,3 +460,154 @@ type diagnosticSettingType = { @description('Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs.') marketplacePartnerResourceId: string? }[]? + +type natRuleCollectionType = { + @description('Required. Name of the NAT rule collection.') + name: string + + @description('Required. Properties of the azure firewall NAT rule collection.') + properties: { + @description('Required. The action type of a NAT rule collection.') + action: { + @description('Required. The type of action.') + type: 'Dnat' | 'Snat' + } + + @description('Required. Priority of the NAT rule collection.') + @minValue(100) + @maxValue(65000) + priority: int + + @description('Required. Collection of rules used by a NAT rule collection.') + rules: { + @description('Required. Name of the NAT rule.') + name: string + + @description('Optional. Description of the rule.') + description: string? + + @description('Required. Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule.') + protocols: ('TCP' | 'UDP' | 'Any' | 'ICMP')[] + + @description('Optional. List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags.') + destinationAddresses: string[]? + + @description('Optional. List of destination ports.') + destinationPorts: string[]? + + @description('Optional. List of source IP addresses for this rule.') + sourceAddresses: string[]? + + @description('Optional. List of source IpGroups for this rule.') + sourceIpGroups: string[]? + + @description('Optional. The translated address for this NAT rule.') + translatedAddress: string? + + @description('Optional. The translated FQDN for this NAT rule.') + translatedFqdn: string? + + @description('Optional. The translated port for this NAT rule.') + translatedPort: string? + }[] + } +}[]? + +type applicationRuleCollectionType = { + @description('Required. Name of the application rule collection.') + name: string + + @description('Required. Properties of the azure firewall application rule collection.') + properties: { + @description('Required. The action type of a rule collection.') + action: { + @description('Required. The type of action.') + type: 'Allow' | 'Deny' + } + + @description('Required. Priority of the application rule collection.') + @minValue(100) + @maxValue(65000) + priority: int + + @description('Required. Collection of rules used by a application rule collection.') + rules: { + @description('Required. Name of the application rule.') + name: string + + @description('Optional. Description of the rule.') + description: string? + + @description('Required. Array of ApplicationRuleProtocols.') + protocols: { + @description('Optional. Port number for the protocol.') + @maxValue(64000) + port: int? + + @description('Required. Protocol type.') + protocolType: 'Http' | 'Https' | 'Mssql' + }[] + + @description('Optional. List of FQDN Tags for this rule.') + fqdnTags: string[]? + + @description('Optional. List of FQDNs for this rule.') + targetFqdns: string[]? + + @description('Optional. List of source IP addresses for this rule.') + sourceAddresses: string[]? + + @description('Optional. List of source IpGroups for this rule.') + sourceIpGroups: string[]? + }[] + } +}[]? + +type networkRuleCollectionType = { + @description('Required. Name of the network rule collection.') + name: string + + @description('Required. Properties of the azure firewall network rule collection.') + properties: { + @description('Required. The action type of a rule collection.') + action: { + @description('Required. The type of action.') + type: 'Allow' | 'Deny' + } + + @description('Required. Priority of the network rule collection.') + @minValue(100) + @maxValue(65000) + priority: int + + @description('Required. Collection of rules used by a network rule collection.') + rules: { + @description('Required. Name of the network rule.') + name: string + + @description('Optional. Description of the rule.') + description: string? + + @description('Required. Array of AzureFirewallNetworkRuleProtocols.') + protocols: ('TCP' | 'UDP' | 'Any' | 'ICMP')[] + + @description('Optional. List of destination IP addresses.') + destinationAddresses: string[]? + + @description('Optional. List of destination FQDNs.') + destinationFqdns: string[]? + + @description('Optional. List of destination IP groups for this rule.') + destinationIpGroups: string[]? + + @description('Optional. List of destination ports.') + destinationPorts: string[]? + + @description('Optional. List of source IP addresses for this rule.') + sourceAddresses: string[]? + + @description('Optional. List of source IpGroups for this rule.') + sourceIpGroups: string[]? + }[] + } +}[]? diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json index b38f878a9d..877e4dbea2 100644 --- a/avm/res/network/azure-firewall/main.json +++ b/avm/res/network/azure-firewall/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "1527004517287633679" + "templateHash": "3831870271484638637" }, "name": "Azure Firewalls", "description": "This module deploys an Azure Firewall.", @@ -223,6 +223,440 @@ } }, "nullable": true + }, + "natRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the NAT rule collection." + } + }, + "properties": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Dnat", + "Snat" + ], + "metadata": { + "description": "Required. The type of action." + } + } + }, + "metadata": { + "description": "Required. The action type of a NAT rule collection." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 65000, + "metadata": { + "description": "Required. Priority of the NAT rule collection." + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the NAT rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the rule." + } + }, + "protocols": { + "type": "array", + "allowedValues": [ + "Any", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. Array of AzureFirewallNetworkRuleProtocols applicable to this NAT rule." + } + }, + "destinationAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination IP addresses for this rule. Supports IP ranges, prefixes, and service tags." + } + }, + "destinationPorts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination ports." + } + }, + "sourceAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IP addresses for this rule." + } + }, + "sourceIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IpGroups for this rule." + } + }, + "translatedAddress": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The translated address for this NAT rule." + } + }, + "translatedFqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The translated FQDN for this NAT rule." + } + }, + "translatedPort": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The translated port for this NAT rule." + } + } + } + }, + "metadata": { + "description": "Required. Collection of rules used by a NAT rule collection." + } + } + }, + "metadata": { + "description": "Required. Properties of the azure firewall NAT rule collection." + } + } + } + }, + "nullable": true + }, + "applicationRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the application rule collection." + } + }, + "properties": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. The type of action." + } + } + }, + "metadata": { + "description": "Required. The action type of a rule collection." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 65000, + "metadata": { + "description": "Required. Priority of the application rule collection." + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the application rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the rule." + } + }, + "protocols": { + "type": "array", + "items": { + "type": "object", + "properties": { + "port": { + "type": "int", + "nullable": true, + "maxValue": 64000, + "metadata": { + "description": "Optional. Port number for the protocol." + } + }, + "protocolType": { + "type": "string", + "allowedValues": [ + "Http", + "Https", + "Mssql" + ], + "metadata": { + "description": "Required. Protocol type." + } + } + } + }, + "metadata": { + "description": "Required. Array of ApplicationRuleProtocols." + } + }, + "fqdnTags": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of FQDN Tags for this rule." + } + }, + "targetFqdns": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of FQDNs for this rule." + } + }, + "sourceAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IP addresses for this rule." + } + }, + "sourceIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IpGroups for this rule." + } + } + } + }, + "metadata": { + "description": "Required. Collection of rules used by a application rule collection." + } + } + }, + "metadata": { + "description": "Required. Properties of the azure firewall application rule collection." + } + } + } + }, + "nullable": true + }, + "networkRuleCollectionType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the network rule collection." + } + }, + "properties": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Required. The type of action." + } + } + }, + "metadata": { + "description": "Required. The action type of a rule collection." + } + }, + "priority": { + "type": "int", + "minValue": 100, + "maxValue": 65000, + "metadata": { + "description": "Required. Priority of the network rule collection." + } + }, + "rules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the network rule." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Description of the rule." + } + }, + "protocols": { + "type": "array", + "allowedValues": [ + "Any", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. Array of AzureFirewallNetworkRuleProtocols." + } + }, + "destinationAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination IP addresses." + } + }, + "destinationFqdns": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination FQDNs." + } + }, + "destinationIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination IP groups for this rule." + } + }, + "destinationPorts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of destination ports." + } + }, + "sourceAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IP addresses for this rule." + } + }, + "sourceIpGroups": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of source IpGroups for this rule." + } + } + } + }, + "metadata": { + "description": "Required. Collection of rules used by a network rule collection." + } + } + }, + "metadata": { + "description": "Required. Properties of the azure firewall network rule collection." + } + } + } + }, + "nullable": true } }, "parameters": { @@ -289,22 +723,19 @@ } }, "applicationRuleCollections": { - "type": "array", - "defaultValue": [], + "$ref": "#/definitions/applicationRuleCollectionType", "metadata": { "description": "Optional. Collection of application rule collections used by Azure Firewall." } }, "networkRuleCollections": { - "type": "array", - "defaultValue": [], + "$ref": "#/definitions/networkRuleCollectionType", "metadata": { "description": "Optional. Collection of network rule collections used by Azure Firewall." } }, "natRuleCollections": { - "type": "array", - "defaultValue": [], + "$ref": "#/definitions/natRuleCollectionType", "metadata": { "description": "Optional. Collection of NAT rule collections used by Azure Firewall." } @@ -445,7 +876,7 @@ "location": "[parameters('location')]", "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]", "tags": "[parameters('tags')]", - "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('managementIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value))), createObject()))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', parameters('applicationRuleCollections'), 'natRuleCollections', parameters('natRuleCollections'), 'networkRuleCollections', parameters('networkRuleCollections')), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]", + "properties": "[if(equals(variables('azureSkuName'), 'AZFW_VNet'), createObject('threatIntelMode', parameters('threatIntelMode'), 'firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'ipConfigurations', concat(createArray(createObject('name', if(not(empty(parameters('publicIPResourceID'))), last(split(parameters('publicIPResourceID'), '/')), reference('publicIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('publicIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('publicIPResourceID'))), parameters('publicIPResourceID'), reference('publicIPAddress').outputs.resourceId.value))), createObject())))), variables('additionalPublicIpConfigurationsVar')), 'managementIpConfiguration', if(variables('requiresManagementIp'), createObject('name', if(not(empty(parameters('managementIPResourceID'))), last(split(parameters('managementIPResourceID'), '/')), reference('managementIPAddress').outputs.name.value), 'properties', union(createObject('subnet', createObject('id', format('{0}/subnets/AzureFirewallManagementSubnet', parameters('virtualNetworkResourceId')))), if(or(not(empty(parameters('publicIPResourceID'))), not(empty(parameters('managementIPAddressObject')))), createObject('publicIPAddress', createObject('id', if(not(empty(parameters('managementIPResourceID'))), parameters('managementIPResourceID'), reference('managementIPAddress').outputs.resourceId.value))), createObject()))), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'applicationRuleCollections', coalesce(parameters('applicationRuleCollections'), createArray()), 'natRuleCollections', coalesce(parameters('natRuleCollections'), createArray()), 'networkRuleCollections', coalesce(parameters('networkRuleCollections'), createArray())), createObject('firewallPolicy', if(not(empty(parameters('firewallPolicyId'))), createObject('id', parameters('firewallPolicyId')), null()), 'sku', createObject('name', variables('azureSkuName'), 'tier', parameters('azureSkuTier')), 'hubIPAddresses', if(not(empty(parameters('hubIPAddresses'))), parameters('hubIPAddresses'), null()), 'virtualHub', if(not(empty(parameters('virtualHubId'))), createObject('id', parameters('virtualHubId')), null())))]", "dependsOn": [ "managementIPAddress", "publicIPAddress" @@ -1757,21 +2188,21 @@ "metadata": { "description": "List of Application Rule Collections." }, - "value": "[parameters('applicationRuleCollections')]" + "value": "[coalesce(parameters('applicationRuleCollections'), createArray())]" }, "networkRuleCollections": { "type": "array", "metadata": { "description": "List of Network Rule Collections." }, - "value": "[parameters('networkRuleCollections')]" + "value": "[coalesce(parameters('networkRuleCollections'), createArray())]" }, "natRuleCollections": { "type": "array", "metadata": { "description": "Collection of NAT rule collections used by Azure Firewall." }, - "value": "[parameters('natRuleCollections')]" + "value": "[coalesce(parameters('natRuleCollections'), createArray())]" }, "location": { "type": "string", diff --git a/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep index 7a69b2eebf..07ce848092 100644 --- a/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep +++ b/avm/res/network/azure-firewall/tests/e2e/max/main.test.bicep @@ -74,7 +74,7 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-app-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -86,12 +86,12 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-ase-tags' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -102,12 +102,12 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-ase-management' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -145,7 +145,7 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-network-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -165,6 +165,22 @@ module testDeployment '../../../main.bicep' = [ '*' ] } + { + name: 'allow-azure-devops' + protocols: [ + 'Any' + ] + description: 'allow azure devops' + sourceAddresses: [ + '*' + ] + destinationAddresses: [ + 'AzureDevOps' + ] + destinationPorts: [ + '443' + ] + } ] } } diff --git a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep index de9bfec4ea..4e6ccd3d21 100644 --- a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep +++ b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/dependencies.bicep @@ -60,5 +60,8 @@ output virtualNetworkResourceId string = virtualNetwork.id @description('The resource ID of the created Public IP.') output publicIPResourceId string = publicIP.id +@description('The public IP Address of the created Public IP.') +output publicIPAddress string = publicIP.properties.ipAddress + @description('The principal ID of the created Managed Identity.') output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep index ca84384701..33bd48b938 100644 --- a/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/network/azure-firewall/tests/e2e/waf-aligned/main.test.bicep @@ -74,7 +74,7 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-app-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ @@ -86,12 +86,12 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-ase-tags' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -102,12 +102,12 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-ase-management' protocols: [ { - port: '80' - protocolType: 'HTTP' + port: 80 + protocolType: 'Http' } { - port: '443' - protocolType: 'HTTPS' + port: 443 + protocolType: 'Https' } ] sourceAddresses: [ @@ -141,7 +141,7 @@ module testDeployment '../../../main.bicep' = [ name: 'allow-network-rules' properties: { action: { - type: 'allow' + type: 'Allow' } priority: 100 rules: [ diff --git a/avm/res/network/azure-firewall/version.json b/avm/res/network/azure-firewall/version.json index 83083db694..1c035df49f 100644 --- a/avm/res/network/azure-firewall/version.json +++ b/avm/res/network/azure-firewall/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.1", + "version": "0.2", "pathFilters": [ "./main.json" ] diff --git a/avm/res/network/network-watcher/README.md b/avm/res/network/network-watcher/README.md new file mode 100644 index 0000000000..b415feec56 --- /dev/null +++ b/avm/res/network/network-watcher/README.md @@ -0,0 +1,712 @@ +# Network Watchers `[Microsoft.Network/networkWatchers]` + +This module deploys a Network Watcher. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Network/networkWatchers` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers) | +| `Microsoft.Network/networkWatchers/connectionMonitors` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/connectionMonitors) | +| `Microsoft.Network/networkWatchers/flowLogs` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/flowLogs) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/network/network-watcher:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) +- [WAF-aligned](#example-3-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +
+ +via Bicep module + +```bicep +module networkWatcher 'br/public:avm/res/network/network-watcher:' = { + name: 'networkWatcherDeployment' + params: { + location: '' + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "location": { + "value": "" + } + } +} +``` + +
+

+ +### Example 2: _Using large parameter set_ + +This instance deploys the module with most of its features enabled. + + +

+ +via Bicep module + +```bicep +module networkWatcher 'br/public:avm/res/network/network-watcher:' = { + name: 'networkWatcherDeployment' + params: { + connectionMonitors: [ + { + endpoints: [ + { + name: '' + resourceId: '' + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + name: 'nnwmax-cm-001' + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + 'subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } + ] + flowLogs: [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwmax-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } + ] + location: '' + name: '' + roleAssignments: [ + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "connectionMonitors": { + "value": [ + { + "endpoints": [ + { + "name": "", + "resourceId": "", + "type": "AzureVM" + }, + { + "address": "www.bing.com", + "name": "Bing", + "type": "ExternalAddress" + } + ], + "name": "nnwmax-cm-001", + "testConfigurations": [ + { + "httpConfiguration": { + "method": "Get", + "port": 80, + "preferHTTPS": false, + "requestHeaders": [], + "validStatusCodeRanges": [ + "200" + ] + }, + "name": "HTTP Bing Test", + "protocol": "Http", + "successThreshold": { + "checksFailedPercent": 5, + "roundTripTimeMs": 100 + }, + "testFrequencySec": 30 + } + ], + "testGroups": [ + { + "destinations": [ + "Bing" + ], + "disable": false, + "name": "test-http-Bing", + "sources": [ + "subnet-001(${resourceGroup.name})" + ], + "testConfigurations": [ + "HTTP Bing Test" + ] + } + ], + "workspaceResourceId": "" + } + ] + }, + "flowLogs": { + "value": [ + { + "enabled": false, + "storageId": "", + "targetResourceId": "" + }, + { + "formatVersion": 1, + "name": "nnwmax-fl-001", + "retentionInDays": 8, + "storageId": "", + "targetResourceId": "", + "trafficAnalyticsInterval": 10, + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "name": { + "value": "" + }, + "roleAssignments": { + "value": [ + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ +### Example 3: _WAF-aligned_ + +This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. + + +

+ +via Bicep module + +```bicep +module networkWatcher 'br/public:avm/res/network/network-watcher:' = { + name: 'networkWatcherDeployment' + params: { + connectionMonitors: [ + { + endpoints: [ + { + name: '' + resourceId: '' + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + name: 'nnwwaf-cm-001' + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + 'subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: '' + } + ] + flowLogs: [ + { + enabled: false + storageId: '' + targetResourceId: '' + } + { + formatVersion: 1 + name: 'nnwwaf-fl-001' + retentionInDays: 8 + storageId: '' + targetResourceId: '' + trafficAnalyticsInterval: 10 + workspaceResourceId: '' + } + ] + location: '' + name: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +} +``` + +
+

+ +

+ +via JSON Parameter file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "connectionMonitors": { + "value": [ + { + "endpoints": [ + { + "name": "", + "resourceId": "", + "type": "AzureVM" + }, + { + "address": "www.bing.com", + "name": "Bing", + "type": "ExternalAddress" + } + ], + "name": "nnwwaf-cm-001", + "testConfigurations": [ + { + "httpConfiguration": { + "method": "Get", + "port": 80, + "preferHTTPS": false, + "requestHeaders": [], + "validStatusCodeRanges": [ + "200" + ] + }, + "name": "HTTP Bing Test", + "protocol": "Http", + "successThreshold": { + "checksFailedPercent": 5, + "roundTripTimeMs": 100 + }, + "testFrequencySec": 30 + } + ], + "testGroups": [ + { + "destinations": [ + "Bing" + ], + "disable": false, + "name": "test-http-Bing", + "sources": [ + "subnet-001(${resourceGroup.name})" + ], + "testConfigurations": [ + "HTTP Bing Test" + ] + } + ], + "workspaceResourceId": "" + } + ] + }, + "flowLogs": { + "value": [ + { + "enabled": false, + "storageId": "", + "targetResourceId": "" + }, + { + "formatVersion": 1, + "name": "nnwwaf-fl-001", + "retentionInDays": 8, + "storageId": "", + "targetResourceId": "", + "trafficAnalyticsInterval": 10, + "workspaceResourceId": "" + } + ] + }, + "location": { + "value": "" + }, + "name": { + "value": "" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + } +} +``` + +
+

+ + +## Parameters + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`connectionMonitors`](#parameter-connectionmonitors) | array | Array that contains the Connection Monitors. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`flowLogs`](#parameter-flowlogs) | array | Array that contains the Flow Logs. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`name`](#parameter-name) | string | Name of the Network Watcher resource (hidden). | +| [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `connectionMonitors` + +Array that contains the Connection Monitors. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `flowLogs` + +Array that contains the Flow Logs. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `name` + +Name of the Network Watcher resource (hidden). + +- Required: No +- Type: string +- Default: `[format('NetworkWatcher_{0}', parameters('location'))]` + +### Parameter: `roleAssignments` + +Array of role assignments to create. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed network watcher. | +| `resourceGroupName` | string | The resource group the network watcher was deployed into. | +| `resourceId` | string | The resource ID of the deployed network watcher. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/network/network-watcher/connection-monitor/README.md b/avm/res/network/network-watcher/connection-monitor/README.md new file mode 100644 index 0000000000..8ca9cfd750 --- /dev/null +++ b/avm/res/network/network-watcher/connection-monitor/README.md @@ -0,0 +1,117 @@ +# Network Watchers Connection Monitors `[Microsoft.Network/networkWatchers/connectionMonitors]` + +This module deploys a Network Watcher Connection Monitor. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkWatchers/connectionMonitors` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/connectionMonitors) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | Name of the resource. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`endpoints`](#parameter-endpoints) | array | List of connection monitor endpoints. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`networkWatcherName`](#parameter-networkwatchername) | string | Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`testConfigurations`](#parameter-testconfigurations) | array | List of connection monitor test configurations. | +| [`testGroups`](#parameter-testgroups) | array | List of connection monitor test groups. | +| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Specify the Log Analytics Workspace Resource ID. | + +### Parameter: `name` + +Name of the resource. + +- Required: Yes +- Type: string + +### Parameter: `endpoints` + +List of connection monitor endpoints. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `networkWatcherName` + +Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. + +- Required: No +- Type: string +- Default: `[format('NetworkWatcher_{0}', resourceGroup().location)]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `testConfigurations` + +List of connection monitor test configurations. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `testGroups` + +List of connection monitor test groups. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `workspaceResourceId` + +Specify the Log Analytics Workspace Resource ID. + +- Required: No +- Type: string +- Default: `''` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the deployed connection monitor. | +| `resourceGroupName` | string | The resource group the connection monitor was deployed into. | +| `resourceId` | string | The resource ID of the deployed connection monitor. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/network/network-watcher/connection-monitor/main.bicep b/avm/res/network/network-watcher/connection-monitor/main.bicep new file mode 100644 index 0000000000..0823dabe66 --- /dev/null +++ b/avm/res/network/network-watcher/connection-monitor/main.bicep @@ -0,0 +1,66 @@ +metadata name = 'Network Watchers Connection Monitors' +metadata description = 'This module deploys a Network Watcher Connection Monitor.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.') +param networkWatcherName string = 'NetworkWatcher_${resourceGroup().location}' + +@description('Required. Name of the resource.') +param name string + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. List of connection monitor endpoints.') +param endpoints array = [] + +@description('Optional. List of connection monitor test configurations.') +param testConfigurations array = [] + +@description('Optional. List of connection monitor test groups.') +param testGroups array = [] + +@description('Optional. Specify the Log Analytics Workspace Resource ID.') +param workspaceResourceId string = '' + + +resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' existing = { + name: networkWatcherName +} + +resource connectionMonitor 'Microsoft.Network/networkWatchers/connectionMonitors@2023-04-01' = { + name: name + parent: networkWatcher + tags: tags + location: location + properties: { + endpoints: endpoints + testConfigurations: testConfigurations + testGroups: testGroups + outputs: !empty(workspaceResourceId) + ? [ + { + type: 'Workspace' + workspaceSettings: { + workspaceResourceId: workspaceResourceId + } + } + ] + : null + } +} + +@description('The name of the deployed connection monitor.') +output name string = connectionMonitor.name + +@description('The resource ID of the deployed connection monitor.') +output resourceId string = connectionMonitor.id + +@description('The resource group the connection monitor was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = connectionMonitor.location diff --git a/avm/res/network/network-watcher/connection-monitor/main.json b/avm/res/network/network-watcher/connection-monitor/main.json new file mode 100644 index 0000000000..6c3fd5c843 --- /dev/null +++ b/avm/res/network/network-watcher/connection-monitor/main.json @@ -0,0 +1,126 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "13403868700445795620" + }, + "name": "Network Watchers Connection Monitors", + "description": "This module deploys a Network Watcher Connection Monitor.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "endpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor endpoints." + } + }, + "testConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test configurations." + } + }, + "testGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test groups." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + } + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2023-04-01", + "name": "[parameters('networkWatcherName')]" + }, + "connectionMonitor": { + "type": "Microsoft.Network/networkWatchers/connectionMonitors", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "endpoints": "[parameters('endpoints')]", + "testConfigurations": "[parameters('testConfigurations')]", + "testGroups": "[parameters('testGroups')]", + "outputs": "[if(not(empty(parameters('workspaceResourceId'))), createArray(createObject('type', 'Workspace', 'workspaceSettings', createObject('workspaceResourceId', parameters('workspaceResourceId')))), null())]" + }, + "dependsOn": [ + "networkWatcher" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed connection monitor." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed connection monitor." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/connectionMonitors', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the connection monitor was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('connectionMonitor', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/network-watcher/flow-log/README.md b/avm/res/network/network-watcher/flow-log/README.md new file mode 100644 index 0000000000..93c1ac0144 --- /dev/null +++ b/avm/res/network/network-watcher/flow-log/README.md @@ -0,0 +1,158 @@ +# NSG Flow Logs `[Microsoft.Network/networkWatchers/flowLogs]` + +This module controls the Network Security Group Flow Logs and analytics settings. +**Note: this module must be run on the Resource Group where Network Watcher is deployed** + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Network/networkWatchers/flowLogs` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/networkWatchers/flowLogs) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`storageId`](#parameter-storageid) | string | Resource ID of the diagnostic storage account. | +| [`targetResourceId`](#parameter-targetresourceid) | string | Resource ID of the NSG that must be enabled for Flow Logs. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enabled`](#parameter-enabled) | bool | If the flow log should be enabled. | +| [`formatVersion`](#parameter-formatversion) | int | The flow log format version. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`name`](#parameter-name) | string | Name of the resource. | +| [`networkWatcherName`](#parameter-networkwatchername) | string | Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. | +| [`retentionInDays`](#parameter-retentionindays) | int | Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`trafficAnalyticsInterval`](#parameter-trafficanalyticsinterval) | int | The interval in minutes which would decide how frequently TA service should do flow analytics. | +| [`workspaceResourceId`](#parameter-workspaceresourceid) | string | Specify the Log Analytics Workspace Resource ID. | + +### Parameter: `storageId` + +Resource ID of the diagnostic storage account. + +- Required: Yes +- Type: string + +### Parameter: `targetResourceId` + +Resource ID of the NSG that must be enabled for Flow Logs. + +- Required: Yes +- Type: string + +### Parameter: `enabled` + +If the flow log should be enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `formatVersion` + +The flow log format version. + +- Required: No +- Type: int +- Default: `2` +- Allowed: + ```Bicep + [ + 1 + 2 + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `name` + +Name of the resource. + +- Required: No +- Type: string +- Default: `[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]` + +### Parameter: `networkWatcherName` + +Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG. + +- Required: No +- Type: string +- Default: `[format('NetworkWatcher_{0}', resourceGroup().location)]` + +### Parameter: `retentionInDays` + +Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely. + +- Required: No +- Type: int +- Default: `365` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `trafficAnalyticsInterval` + +The interval in minutes which would decide how frequently TA service should do flow analytics. + +- Required: No +- Type: int +- Default: `60` +- Allowed: + ```Bicep + [ + 10 + 60 + ] + ``` + +### Parameter: `workspaceResourceId` + +Specify the Log Analytics Workspace Resource ID. + +- Required: No +- Type: string +- Default: `''` + + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the flow log. | +| `resourceGroupName` | string | The resource group the flow log was deployed into. | +| `resourceId` | string | The resource ID of the flow log. | + +## Cross-referenced modules + +_None_ + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/res/network/network-watcher/flow-log/main.bicep b/avm/res/network/network-watcher/flow-log/main.bicep new file mode 100644 index 0000000000..89a14ccc38 --- /dev/null +++ b/avm/res/network/network-watcher/flow-log/main.bicep @@ -0,0 +1,97 @@ +metadata name = 'NSG Flow Logs' +metadata description = '''This module controls the Network Security Group Flow Logs and analytics settings. +**Note: this module must be run on the Resource Group where Network Watcher is deployed**''' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG.') +param networkWatcherName string = 'NetworkWatcher_${resourceGroup().location}' + +@description('Optional. Name of the resource.') +param name string = '${last(split(targetResourceId, '/'))}-${split(targetResourceId, '/')[4]}-flowlog' + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. Resource ID of the NSG that must be enabled for Flow Logs.') +param targetResourceId string + +@description('Required. Resource ID of the diagnostic storage account.') +param storageId string + +@description('Optional. If the flow log should be enabled.') +param enabled bool = true + +@description('Optional. The flow log format version.') +@allowed([ + 1 + 2 +]) +param formatVersion int = 2 + +@description('Optional. Specify the Log Analytics Workspace Resource ID.') +param workspaceResourceId string = '' + +@description('Optional. The interval in minutes which would decide how frequently TA service should do flow analytics.') +@allowed([ + 10 + 60 +]) +param trafficAnalyticsInterval int = 60 + +@description('Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely.') +@minValue(0) +@maxValue(365) +param retentionInDays int = 365 + +var flowAnalyticsConfiguration = !empty(workspaceResourceId) && enabled == true + ? { + networkWatcherFlowAnalyticsConfiguration: { + enabled: true + workspaceResourceId: workspaceResourceId + trafficAnalyticsInterval: trafficAnalyticsInterval + } + } + : { + networkWatcherFlowAnalyticsConfiguration: { + enabled: false + } + } + +resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' existing = { + name: networkWatcherName +} + +resource flowLog 'Microsoft.Network/networkWatchers/flowLogs@2023-04-01' = { + name: name + parent: networkWatcher + tags: tags + location: location + properties: { + targetResourceId: targetResourceId + storageId: storageId + enabled: enabled + retentionPolicy: { + days: retentionInDays + enabled: retentionInDays == 0 ? false : true + } + format: { + type: 'JSON' + version: formatVersion + } + flowAnalyticsConfiguration: flowAnalyticsConfiguration + } +} +@description('The name of the flow log.') +output name string = flowLog.name + +@description('The resource ID of the flow log.') +output resourceId string = flowLog.id + +@description('The resource group the flow log was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = flowLog.location diff --git a/avm/res/network/network-watcher/flow-log/main.json b/avm/res/network/network-watcher/flow-log/main.json new file mode 100644 index 0000000000..1338480468 --- /dev/null +++ b/avm/res/network/network-watcher/flow-log/main.json @@ -0,0 +1,167 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "7721211688474892554" + }, + "name": "NSG Flow Logs", + "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]", + "metadata": { + "description": "Optional. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "targetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the NSG that must be enabled for Flow Logs." + } + }, + "storageId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the diagnostic storage account." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If the flow log should be enabled." + } + }, + "formatVersion": { + "type": "int", + "defaultValue": 2, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. The flow log format version." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + }, + "trafficAnalyticsInterval": { + "type": "int", + "defaultValue": 60, + "allowedValues": [ + 10, + 60 + ], + "metadata": { + "description": "Optional. The interval in minutes which would decide how frequently TA service should do flow analytics." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + } + }, + "variables": { + "flowAnalyticsConfiguration": "[if(and(not(empty(parameters('workspaceResourceId'))), equals(parameters('enabled'), true())), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', true(), 'workspaceResourceId', parameters('workspaceResourceId'), 'trafficAnalyticsInterval', parameters('trafficAnalyticsInterval'))), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', false())))]" + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2023-04-01", + "name": "[parameters('networkWatcherName')]" + }, + "flowLog": { + "type": "Microsoft.Network/networkWatchers/flowLogs", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "targetResourceId": "[parameters('targetResourceId')]", + "storageId": "[parameters('storageId')]", + "enabled": "[parameters('enabled')]", + "retentionPolicy": { + "days": "[parameters('retentionInDays')]", + "enabled": "[if(equals(parameters('retentionInDays'), 0), false(), true())]" + }, + "format": { + "type": "JSON", + "version": "[parameters('formatVersion')]" + }, + "flowAnalyticsConfiguration": "[variables('flowAnalyticsConfiguration')]" + }, + "dependsOn": [ + "networkWatcher" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the flow log." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the flow log." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/flowLogs', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the flow log was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('flowLog', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/network-watcher/main.bicep b/avm/res/network/network-watcher/main.bicep new file mode 100644 index 0000000000..71f388d98f --- /dev/null +++ b/avm/res/network/network-watcher/main.bicep @@ -0,0 +1,188 @@ +metadata name = 'Network Watchers' +metadata description = 'This module deploys a Network Watcher.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. Name of the Network Watcher resource (hidden).') +@minLength(1) +param name string = 'NetworkWatcher_${location}' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Array that contains the Connection Monitors.') +param connectionMonitors array = [] + +@description('Optional. Array that contains the Flow Logs.') +param flowLogs array = [] + +@description('Optional. The lock settings of the service.') +param lock lockType + +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var builtInRoleNames = { + Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Network Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '4d97b98b-1d4f-4787-a291-c67834d212e7' + ) + Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +resource avmTelemetry 'Microsoft.Resources/deployments@2023-07-01' = + if (enableTelemetry) { + name: '46d3xbcp.res.network-networkwatcher.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } + } + +resource networkWatcher 'Microsoft.Network/networkWatchers@2023-04-01' = { + name: name + location: location + tags: tags + properties: {} +} + +resource networkWatcher_lock 'Microsoft.Authorization/locks@2020-05-01' = + if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: networkWatcher + } + +resource networkWatcher_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (roleAssignments ?? []): { + name: guid(networkWatcher.id, roleAssignment.principalId, roleAssignment.roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleAssignment.roleDefinitionIdOrName) + ? builtInRoleNames[roleAssignment.roleDefinitionIdOrName] + : contains(roleAssignment.roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/') + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName) + principalId: roleAssignment.principalId + description: roleAssignment.?description + principalType: roleAssignment.?principalType + condition: roleAssignment.?condition + conditionVersion: !empty(roleAssignment.?condition) ? (roleAssignment.?conditionVersion ?? '2.0') : null // Must only be set if condtion is set + delegatedManagedIdentityResourceId: roleAssignment.?delegatedManagedIdentityResourceId + } + scope: networkWatcher + } +] + +module networkWatcher_connectionMonitors 'connection-monitor/main.bicep' = [ + for (connectionMonitor, index) in connectionMonitors: { + name: '${uniqueString(deployment().name, location)}-NW-ConnectionMonitor-${index}' + params: { + endpoints: contains(connectionMonitor, 'endpoints') ? connectionMonitor.endpoints : [] + name: connectionMonitor.name + location: location + networkWatcherName: networkWatcher.name + testConfigurations: contains(connectionMonitor, 'testConfigurations') ? connectionMonitor.testConfigurations : [] + testGroups: contains(connectionMonitor, 'testGroups') ? connectionMonitor.testGroups : [] + workspaceResourceId: contains(connectionMonitor, 'workspaceResourceId') + ? connectionMonitor.workspaceResourceId + : '' + } + } +] + +module networkWatcher_flowLogs 'flow-log/main.bicep' = [ + for (flowLog, index) in flowLogs: { + name: '${uniqueString(deployment().name, location)}-NW-FlowLog-${index}' + params: { + enabled: contains(flowLog, 'enabled') ? flowLog.enabled : true + formatVersion: contains(flowLog, 'formatVersion') ? flowLog.formatVersion : 2 + location: contains(flowLog, 'location') ? flowLog.location : location + name: contains(flowLog, 'name') + ? flowLog.name + : '${last(split(flowLog.targetResourceId, '/'))}-${split(flowLog.targetResourceId, '/')[4]}-flowlog' + networkWatcherName: networkWatcher.name + retentionInDays: contains(flowLog, 'retentionInDays') ? flowLog.retentionInDays : 365 + storageId: flowLog.storageId + targetResourceId: flowLog.targetResourceId + trafficAnalyticsInterval: contains(flowLog, 'trafficAnalyticsInterval') ? flowLog.trafficAnalyticsInterval : 60 + workspaceResourceId: contains(flowLog, 'workspaceResourceId') ? flowLog.workspaceResourceId : '' + } + } +] + +@description('The name of the deployed network watcher.') +output name string = networkWatcher.name + +@description('The resource ID of the deployed network watcher.') +output resourceId string = networkWatcher.id + +@description('The resource group the network watcher was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The location the resource was deployed into.') +output location string = networkWatcher.location + +// =============== // +// Definitions // +// =============== // + +type lockType = { + @description('Optional. Specify the name of lock.') + name: string? + + @description('Optional. Specify the type of lock.') + kind: ('CanNotDelete' | 'ReadOnly' | 'None')? +}? + +type roleAssignmentType = { + @description('Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'.') + roleDefinitionIdOrName: string + + @description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') + principalId: string + + @description('Optional. The principal type of the assigned principal ID.') + principalType: ('ServicePrincipal' | 'Group' | 'User' | 'ForeignGroup' | 'Device')? + + @description('Optional. The description of the role assignment.') + description: string? + + @description('Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container".') + condition: string? + + @description('Optional. Version of the condition.') + conditionVersion: '2.0'? + + @description('Optional. The Resource Id of the delegated managed identity resource.') + delegatedManagedIdentityResourceId: string? +}[]? diff --git a/avm/res/network/network-watcher/main.json b/avm/res/network/network-watcher/main.json new file mode 100644 index 0000000000..1a74c3d9f4 --- /dev/null +++ b/avm/res/network/network-watcher/main.json @@ -0,0 +1,633 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "4063023963915633324" + }, + "name": "Network Watchers", + "description": "This module deploys a Network Watcher.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', parameters('location'))]", + "minLength": 1, + "metadata": { + "description": "Optional. Name of the Network Watcher resource (hidden)." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "connectionMonitors": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array that contains the Connection Monitors." + } + }, + "flowLogs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array that contains the Flow Logs." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-networkwatcher.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "networkWatcher": { + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": {} + }, + "networkWatcher_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/networkWatchers/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "networkWatcher" + ] + }, + "networkWatcher_roleAssignments": { + "copy": { + "name": "networkWatcher_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/networkWatchers/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/networkWatchers', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "networkWatcher" + ] + }, + "networkWatcher_connectionMonitors": { + "copy": { + "name": "networkWatcher_connectionMonitors", + "count": "[length(parameters('connectionMonitors'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NW-ConnectionMonitor-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "endpoints": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'endpoints'), createObject('value', parameters('connectionMonitors')[copyIndex()].endpoints), createObject('value', createArray()))]", + "name": { + "value": "[parameters('connectionMonitors')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "networkWatcherName": { + "value": "[parameters('name')]" + }, + "testConfigurations": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'testConfigurations'), createObject('value', parameters('connectionMonitors')[copyIndex()].testConfigurations), createObject('value', createArray()))]", + "testGroups": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'testGroups'), createObject('value', parameters('connectionMonitors')[copyIndex()].testGroups), createObject('value', createArray()))]", + "workspaceResourceId": "[if(contains(parameters('connectionMonitors')[copyIndex()], 'workspaceResourceId'), createObject('value', parameters('connectionMonitors')[copyIndex()].workspaceResourceId), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "13403868700445795620" + }, + "name": "Network Watchers Connection Monitors", + "description": "This module deploys a Network Watcher Connection Monitor.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "endpoints": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor endpoints." + } + }, + "testConfigurations": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test configurations." + } + }, + "testGroups": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of connection monitor test groups." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + } + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2023-04-01", + "name": "[parameters('networkWatcherName')]" + }, + "connectionMonitor": { + "type": "Microsoft.Network/networkWatchers/connectionMonitors", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "endpoints": "[parameters('endpoints')]", + "testConfigurations": "[parameters('testConfigurations')]", + "testGroups": "[parameters('testGroups')]", + "outputs": "[if(not(empty(parameters('workspaceResourceId'))), createArray(createObject('type', 'Workspace', 'workspaceSettings', createObject('workspaceResourceId', parameters('workspaceResourceId')))), null())]" + }, + "dependsOn": [ + "networkWatcher" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed connection monitor." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed connection monitor." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/connectionMonitors', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the connection monitor was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('connectionMonitor', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkWatcher" + ] + }, + "networkWatcher_flowLogs": { + "copy": { + "name": "networkWatcher_flowLogs", + "count": "[length(parameters('flowLogs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-NW-FlowLog-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enabled": "[if(contains(parameters('flowLogs')[copyIndex()], 'enabled'), createObject('value', parameters('flowLogs')[copyIndex()].enabled), createObject('value', true()))]", + "formatVersion": "[if(contains(parameters('flowLogs')[copyIndex()], 'formatVersion'), createObject('value', parameters('flowLogs')[copyIndex()].formatVersion), createObject('value', 2))]", + "location": "[if(contains(parameters('flowLogs')[copyIndex()], 'location'), createObject('value', parameters('flowLogs')[copyIndex()].location), createObject('value', parameters('location')))]", + "name": "[if(contains(parameters('flowLogs')[copyIndex()], 'name'), createObject('value', parameters('flowLogs')[copyIndex()].name), createObject('value', format('{0}-{1}-flowlog', last(split(parameters('flowLogs')[copyIndex()].targetResourceId, '/')), split(parameters('flowLogs')[copyIndex()].targetResourceId, '/')[4])))]", + "networkWatcherName": { + "value": "[parameters('name')]" + }, + "retentionInDays": "[if(contains(parameters('flowLogs')[copyIndex()], 'retentionInDays'), createObject('value', parameters('flowLogs')[copyIndex()].retentionInDays), createObject('value', 365))]", + "storageId": { + "value": "[parameters('flowLogs')[copyIndex()].storageId]" + }, + "targetResourceId": { + "value": "[parameters('flowLogs')[copyIndex()].targetResourceId]" + }, + "trafficAnalyticsInterval": "[if(contains(parameters('flowLogs')[copyIndex()], 'trafficAnalyticsInterval'), createObject('value', parameters('flowLogs')[copyIndex()].trafficAnalyticsInterval), createObject('value', 60))]", + "workspaceResourceId": "[if(contains(parameters('flowLogs')[copyIndex()], 'workspaceResourceId'), createObject('value', parameters('flowLogs')[copyIndex()].workspaceResourceId), createObject('value', ''))]" + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.26.54.24096", + "templateHash": "7721211688474892554" + }, + "name": "NSG Flow Logs", + "description": "This module controls the Network Security Group Flow Logs and analytics settings.\n**Note: this module must be run on the Resource Group where Network Watcher is deployed**", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "networkWatcherName": { + "type": "string", + "defaultValue": "[format('NetworkWatcher_{0}', resourceGroup().location)]", + "metadata": { + "description": "Optional. Name of the network watcher resource. Must be in the resource group where the Flow log will be created and same region as the NSG." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-{1}-flowlog', last(split(parameters('targetResourceId'), '/')), split(parameters('targetResourceId'), '/')[4])]", + "metadata": { + "description": "Optional. Name of the resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "targetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the NSG that must be enabled for Flow Logs." + } + }, + "storageId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the diagnostic storage account." + } + }, + "enabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. If the flow log should be enabled." + } + }, + "formatVersion": { + "type": "int", + "defaultValue": 2, + "allowedValues": [ + 1, + 2 + ], + "metadata": { + "description": "Optional. The flow log format version." + } + }, + "workspaceResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Specify the Log Analytics Workspace Resource ID." + } + }, + "trafficAnalyticsInterval": { + "type": "int", + "defaultValue": 60, + "allowedValues": [ + 10, + 60 + ], + "metadata": { + "description": "Optional. The interval in minutes which would decide how frequently TA service should do flow analytics." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 365, + "metadata": { + "description": "Optional. Specifies the number of days that logs will be kept for; a value of 0 will retain data indefinitely." + } + } + }, + "variables": { + "flowAnalyticsConfiguration": "[if(and(not(empty(parameters('workspaceResourceId'))), equals(parameters('enabled'), true())), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', true(), 'workspaceResourceId', parameters('workspaceResourceId'), 'trafficAnalyticsInterval', parameters('trafficAnalyticsInterval'))), createObject('networkWatcherFlowAnalyticsConfiguration', createObject('enabled', false())))]" + }, + "resources": { + "networkWatcher": { + "existing": true, + "type": "Microsoft.Network/networkWatchers", + "apiVersion": "2023-04-01", + "name": "[parameters('networkWatcherName')]" + }, + "flowLog": { + "type": "Microsoft.Network/networkWatchers/flowLogs", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('networkWatcherName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "properties": { + "targetResourceId": "[parameters('targetResourceId')]", + "storageId": "[parameters('storageId')]", + "enabled": "[parameters('enabled')]", + "retentionPolicy": { + "days": "[parameters('retentionInDays')]", + "enabled": "[if(equals(parameters('retentionInDays'), 0), false(), true())]" + }, + "format": { + "type": "JSON", + "version": "[parameters('formatVersion')]" + }, + "flowAnalyticsConfiguration": "[variables('flowAnalyticsConfiguration')]" + }, + "dependsOn": [ + "networkWatcher" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the flow log." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the flow log." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers/flowLogs', parameters('networkWatcherName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the flow log was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('flowLog', '2023-04-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "networkWatcher" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed network watcher." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed network watcher." + }, + "value": "[resourceId('Microsoft.Network/networkWatchers', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the network watcher was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('networkWatcher', '2023-04-01', 'full').location]" + } + } +} \ No newline at end of file diff --git a/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..9fcca025ef --- /dev/null +++ b/avm/res/network/network-watcher/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,51 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. + +@description('Optional. The location to deploy resources to.') +#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically +param resourceLocation string = deployment().location + +@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +param tempLocation string = 'uksouth' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnwmin' + +#disable-next-line no-unused-params +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: tempLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + params: { + // Note: This value is not required and only set to enable testing + location: tempLocation + } +}] diff --git a/avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep b/avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..c20f841f30 --- /dev/null +++ b/avm/res/network/network-watcher/tests/e2e/max/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the first Network Security Group to create.') +param firstNetworkSecurityGroupName string + +@description('Required. The name of the second Network Security Group to create.') +param secondNetworkSecurityGroupName string + +@description('Required. The name of the Virtual Machine to create.') +param virtualMachineName string + +@description('Optional. The password to leverage for the VM login.') +@secure() +param password string = newGuid() + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: firstNetworkSecurityGroupName + location: location +} + +resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: secondNetworkSecurityGroupName + location: location +} + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = { + name: '${virtualMachineName}-nic' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig01' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = { + name: virtualMachineName + location: location + properties: { + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + properties: { + deleteOption: 'Delete' + primary: true + } + } + ] + } + storageProfile: { + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + osDisk: { + deleteOption: 'Delete' + createOption: 'FromImage' + } + } + hardwareProfile: { + vmSize: 'Standard_B1ms' + } + osProfile: { + adminUsername: '${virtualMachineName}cake' + adminPassword: password + computerName: virtualMachineName + linuxConfiguration: { + disablePasswordAuthentication: false + } + } + } +} + +resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = { + name: 'NetworkWatcherAgent' + parent: virtualMachine + location: location + properties: { + publisher: 'Microsoft.Azure.NetworkWatcher' + type: 'NetworkWatcherAgentLinux' + typeHandlerVersion: '1.4' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: false + settings: {} + protectedSettings: {} + suppressFailures: false + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Machine.') +output virtualMachineResourceId string = virtualMachine.id + +@description('The resource ID of the first created Network Security Group.') +output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id + +@description('The resource ID of the second created Network Security Group.') +output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id diff --git a/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..4386fe3d6e --- /dev/null +++ b/avm/res/network/network-watcher/tests/e2e/max/main.test.bicep @@ -0,0 +1,172 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. + +@description('Optional. The location to deploy resources to.') +#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnwmax' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +param tempLocation string = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: tempLocation +} + +resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg' + location: tempLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}' + secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}' + virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: tempLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: tempLocation + } +} + +// ============== // +// Test Execution // +// ============== // +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'NetworkWatcher_${tempLocation}' + location: tempLocation + connectionMonitors: [ + { + name: '${namePrefix}-${serviceShort}-cm-001' + endpoints: [ + { + name: '${namePrefix}-subnet-001(${resourceGroup.name})' + resourceId: nestedDependencies.outputs.virtualMachineResourceId + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + '${namePrefix}-subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + flowLogs: [ + { + enabled: false + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId + } + { + formatVersion: 1 + name: '${namePrefix}-${serviceShort}-fl-001' + retentionInDays: 8 + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId + trafficAnalyticsInterval: 10 + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + roleAssignments: [ + { + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..c20f841f30 --- /dev/null +++ b/avm/res/network/network-watcher/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,144 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the first Network Security Group to create.') +param firstNetworkSecurityGroupName string + +@description('Required. The name of the second Network Security Group to create.') +param secondNetworkSecurityGroupName string + +@description('Required. The name of the Virtual Machine to create.') +param virtualMachineName string + +@description('Optional. The password to leverage for the VM login.') +@secure() +param password string = newGuid() + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'defaultSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 16, 0) + } + } + ] + } +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource firstNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: firstNetworkSecurityGroupName + location: location +} + +resource secondNetworkSecurityGroup 'Microsoft.Network/networkSecurityGroups@2023-04-01' = { + name: secondNetworkSecurityGroupName + location: location +} + +resource networkInterface 'Microsoft.Network/networkInterfaces@2023-04-01' = { + name: '${virtualMachineName}-nic' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig01' + properties: { + subnet: { + id: virtualNetwork.properties.subnets[0].id + } + } + } + ] + } +} + +resource virtualMachine 'Microsoft.Compute/virtualMachines@2022-08-01' = { + name: virtualMachineName + location: location + properties: { + networkProfile: { + networkInterfaces: [ + { + id: networkInterface.id + properties: { + deleteOption: 'Delete' + primary: true + } + } + ] + } + storageProfile: { + imageReference: { + publisher: 'Canonical' + offer: '0001-com-ubuntu-server-jammy' + sku: '22_04-lts-gen2' + version: 'latest' + } + osDisk: { + deleteOption: 'Delete' + createOption: 'FromImage' + } + } + hardwareProfile: { + vmSize: 'Standard_B1ms' + } + osProfile: { + adminUsername: '${virtualMachineName}cake' + adminPassword: password + computerName: virtualMachineName + linuxConfiguration: { + disablePasswordAuthentication: false + } + } + } +} + +resource extension 'Microsoft.Compute/virtualMachines/extensions@2021-07-01' = { + name: 'NetworkWatcherAgent' + parent: virtualMachine + location: location + properties: { + publisher: 'Microsoft.Azure.NetworkWatcher' + type: 'NetworkWatcherAgentLinux' + typeHandlerVersion: '1.4' + autoUpgradeMinorVersion: true + enableAutomaticUpgrade: false + settings: {} + protectedSettings: {} + suppressFailures: false + } +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Machine.') +output virtualMachineResourceId string = virtualMachine.id + +@description('The resource ID of the first created Network Security Group.') +output firstNetworkSecurityGroupResourceId string = firstNetworkSecurityGroup.id + +@description('The resource ID of the second created Network Security Group.') +output secondNetworkSecurityGroupResourceId string = secondNetworkSecurityGroup.id diff --git a/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..32fc738840 --- /dev/null +++ b/avm/res/network/network-watcher/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,156 @@ +targetScope = 'subscription' + +metadata name = 'WAF-aligned' +metadata description = 'This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'NetworkWatcherRG' // Note, this is the default NetworkWatcher resource group. Do not change. + +@description('Optional. The location to deploy resources to.') +#disable-next-line no-unused-params // A rotation location cannot be used for this test as NetworkWatcher Resource Groups are created for any test location automatically +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'nnwwaf' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The static location of the resource group & resources.') // Note, we set the location of the NetworkWatcherRG to avoid conflicts with the already existing NetworkWatcherRG +param tempLocation string = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: tempLocation +} + +resource resourceGroupDependencies 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'dep-${namePrefix}-network.networkwatcher-${serviceShort}-rg' + location: tempLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, tempLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + firstNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-1-${serviceShort}' + secondNetworkSecurityGroupName: 'dep-${namePrefix}-nsg-2-${serviceShort}' + virtualMachineName: 'dep-${namePrefix}-vm-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + location: tempLocation + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroupDependencies + name: '${uniqueString(deployment().name, tempLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}01' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}' + location: tempLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [for iteration in [ 'init', 'idem' ]: { + scope: resourceGroup + name: '${uniqueString(deployment().name, tempLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'NetworkWatcher_${tempLocation}' + location: tempLocation + connectionMonitors: [ + { + name: '${namePrefix}-${serviceShort}-cm-001' + endpoints: [ + { + name: '${namePrefix}-subnet-001(${resourceGroup.name})' + resourceId: nestedDependencies.outputs.virtualMachineResourceId + type: 'AzureVM' + } + { + address: 'www.bing.com' + name: 'Bing' + type: 'ExternalAddress' + } + ] + testConfigurations: [ + { + httpConfiguration: { + method: 'Get' + port: 80 + preferHTTPS: false + requestHeaders: [] + validStatusCodeRanges: [ + '200' + ] + } + name: 'HTTP Bing Test' + protocol: 'Http' + successThreshold: { + checksFailedPercent: 5 + roundTripTimeMs: 100 + } + testFrequencySec: 30 + } + ] + testGroups: [ + { + destinations: [ + 'Bing' + ] + disable: false + name: 'test-http-Bing' + sources: [ + '${namePrefix}-subnet-001(${resourceGroup.name})' + ] + testConfigurations: [ + 'HTTP Bing Test' + ] + } + ] + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + flowLogs: [ + { + enabled: false + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.firstNetworkSecurityGroupResourceId + } + { + formatVersion: 1 + name: '${namePrefix}-${serviceShort}-fl-001' + retentionInDays: 8 + storageId: diagnosticDependencies.outputs.storageAccountResourceId + targetResourceId: nestedDependencies.outputs.secondNetworkSecurityGroupResourceId + trafficAnalyticsInterval: 10 + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } +}] diff --git a/avm/res/network/network-watcher/version.json b/avm/res/network/network-watcher/version.json new file mode 100644 index 0000000000..7fa401bdf7 --- /dev/null +++ b/avm/res/network/network-watcher/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} diff --git a/avm/res/purview/account/README.md b/avm/res/purview/account/README.md index e8c88a8d1b..5f52f7ce62 100644 --- a/avm/res/purview/account/README.md +++ b/avm/res/purview/account/README.md @@ -667,6 +667,7 @@ Configuration details for Purview Account private endpoints. For security reason | [`name`](#parameter-accountprivateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-accountprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-accountprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-accountprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-accountprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-accountprivateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-accountprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -863,6 +864,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `accountPrivateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `accountPrivateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. @@ -1156,6 +1164,7 @@ Configuration details for Purview Managed Event Hub namespace private endpoints. | [`name`](#parameter-eventhubprivateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-eventhubprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-eventhubprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-eventhubprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-eventhubprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-eventhubprivateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-eventhubprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1352,6 +1361,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `eventHubPrivateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `eventHubPrivateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. @@ -1563,6 +1579,7 @@ Configuration details for Purview Portal private endpoints. For security reasons | [`name`](#parameter-portalprivateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-portalprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-portalprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-portalprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-portalprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-portalprivateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-portalprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1759,6 +1776,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `portalPrivateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `portalPrivateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. @@ -2003,6 +2027,7 @@ Configuration details for Purview Managed Storage Account blob private endpoints | [`name`](#parameter-storageblobprivateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-storageblobprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-storageblobprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-storageblobprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-storageblobprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-storageblobprivateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-storageblobprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -2199,6 +2224,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `storageBlobPrivateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `storageBlobPrivateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. @@ -2338,6 +2370,7 @@ Configuration details for Purview Managed Storage Account queue private endpoint | [`name`](#parameter-storagequeueprivateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-storagequeueprivateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-storagequeueprivateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-storagequeueprivateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-storagequeueprivateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-storagequeueprivateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-storagequeueprivateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -2534,6 +2567,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `storageQueuePrivateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `storageQueuePrivateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/purview/account/main.bicep b/avm/res/purview/account/main.bicep index 42a4f887f9..b0beba41f6 100644 --- a/avm/res/purview/account/main.bicep +++ b/avm/res/purview/account/main.bicep @@ -558,6 +558,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + // Variant 1: A default service can be assumed (i.e., for services that only have one private endpoint type) @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/purview/account/main.json b/avm/res/purview/account/main.json index 79ece163df..b7c2504156 100644 --- a/avm/res/purview/account/main.json +++ b/avm/res/purview/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "10478276284688945005" + "templateHash": "17174301778360799299" }, "name": "Purview Accounts", "description": "This module deploys a Purview Account.", @@ -258,6 +258,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/recovery-services/vault/README.md b/avm/res/recovery-services/vault/README.md index 60cb4dddd3..445ea28d6f 100644 --- a/avm/res/recovery-services/vault/README.md +++ b/avm/res/recovery-services/vault/README.md @@ -2181,6 +2181,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -2377,6 +2378,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/recovery-services/vault/main.bicep b/avm/res/recovery-services/vault/main.bicep index 293e839c67..8e50e68716 100644 --- a/avm/res/recovery-services/vault/main.bicep +++ b/avm/res/recovery-services/vault/main.bicep @@ -444,6 +444,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/recovery-services/vault/main.json b/avm/res/recovery-services/vault/main.json index 42225dc535..577dc26077 100644 --- a/avm/res/recovery-services/vault/main.json +++ b/avm/res/recovery-services/vault/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "7655373586022764690" + "templateHash": "2215975966866051299" }, "name": "Recovery Services Vaults", "description": "This module deploys a Recovery Services Vault.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/relay/namespace/README.md b/avm/res/relay/namespace/README.md index c9a6931fbf..00e11010ba 100644 --- a/avm/res/relay/namespace/README.md +++ b/avm/res/relay/namespace/README.md @@ -927,6 +927,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1123,6 +1124,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/relay/namespace/main.bicep b/avm/res/relay/namespace/main.bicep index 18ca612874..1152aa1dfc 100644 --- a/avm/res/relay/namespace/main.bicep +++ b/avm/res/relay/namespace/main.bicep @@ -381,6 +381,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/relay/namespace/main.json b/avm/res/relay/namespace/main.json index 20a1a87e84..bd8938cde5 100644 --- a/avm/res/relay/namespace/main.json +++ b/avm/res/relay/namespace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "18413649405351363659" + "templateHash": "17233437629149406382" }, "name": "Relay Namespaces", "description": "This module deploys a Relay Namespace", @@ -123,6 +123,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/search/search-service/README.md b/avm/res/search/search-service/README.md index b2b9d3299b..fddc70b242 100644 --- a/avm/res/search/search-service/README.md +++ b/avm/res/search/search-service/README.md @@ -942,6 +942,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1138,6 +1139,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/search/search-service/main.bicep b/avm/res/search/search-service/main.bicep index 755034072f..3beb423d54 100644 --- a/avm/res/search/search-service/main.bicep +++ b/avm/res/search/search-service/main.bicep @@ -379,6 +379,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/search/search-service/main.json b/avm/res/search/search-service/main.json index 303cb2d214..df489a9cab 100644 --- a/avm/res/search/search-service/main.json +++ b/avm/res/search/search-service/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "13049058701753751229" + "templateHash": "13069544635575133650" }, "name": "Search Services", "description": "This module deploys a Search Service.", @@ -136,6 +136,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/service-bus/namespace/README.md b/avm/res/service-bus/namespace/README.md index 125cf687fa..4ef8712ce2 100644 --- a/avm/res/service-bus/namespace/README.md +++ b/avm/res/service-bus/namespace/README.md @@ -294,9 +294,11 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { } } ] + name: 'myPrivateEndpoint' privateDnsZoneResourceIds: [ '' ] + privateLinkServiceConnectionName: 'customLinkName' subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -526,9 +528,11 @@ module namespace 'br/public:avm/res/service-bus/namespace:' = { } } ], + "name": "myPrivateEndpoint", "privateDnsZoneResourceIds": [ "" ], + "privateLinkServiceConnectionName": "customLinkName", "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1647,6 +1651,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1843,6 +1848,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/service-bus/namespace/main.bicep b/avm/res/service-bus/namespace/main.bicep index 8f3a7c22ab..66b8bc38c8 100644 --- a/avm/res/service-bus/namespace/main.bicep +++ b/avm/res/service-bus/namespace/main.bicep @@ -499,6 +499,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/service-bus/namespace/main.json b/avm/res/service-bus/namespace/main.json index e9e7ee32e7..86701b3773 100644 --- a/avm/res/service-bus/namespace/main.json +++ b/avm/res/service-bus/namespace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "12101686609428052773" + "templateHash": "9228932977984857525" }, "name": "Service Bus Namespaces", "description": "This module deploys a Service Bus Namespace.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep b/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep index a1a500e934..b08e017836 100644 --- a/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep +++ b/avm/res/service-bus/namespace/tests/e2e/max/main.test.bicep @@ -213,6 +213,8 @@ module testDeployment '../../../main.bicep' = [ ] privateEndpoints: [ { + name: 'myPrivateEndpoint' + privateLinkServiceConnectionName: 'customLinkName' subnetResourceId: nestedDependencies.outputs.subnetResourceId privateDnsZoneResourceIds: [ nestedDependencies.outputs.privateDNSZoneResourceId diff --git a/avm/res/signal-r-service/signal-r/README.md b/avm/res/signal-r-service/signal-r/README.md index 28819bb5be..9466ec00a2 100644 --- a/avm/res/signal-r-service/signal-r/README.md +++ b/avm/res/signal-r-service/signal-r/README.md @@ -695,6 +695,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -891,6 +892,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/signal-r-service/signal-r/main.bicep b/avm/res/signal-r-service/signal-r/main.bicep index 66afadbde1..a1ddf132b0 100644 --- a/avm/res/signal-r-service/signal-r/main.bicep +++ b/avm/res/signal-r-service/signal-r/main.bicep @@ -368,6 +368,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/signal-r-service/signal-r/main.json b/avm/res/signal-r-service/signal-r/main.json index fda5c481ab..6a3345bbfc 100644 --- a/avm/res/signal-r-service/signal-r/main.json +++ b/avm/res/signal-r-service/signal-r/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "3713977800764774886" + "templateHash": "15213574724705700339" }, "name": "SignalR Service SignalR", "description": "This module deploys a SignalR Service SignalR.", @@ -123,6 +123,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/signal-r-service/web-pub-sub/README.md b/avm/res/signal-r-service/web-pub-sub/README.md index 303f1a02c5..bd364eb46f 100644 --- a/avm/res/signal-r-service/web-pub-sub/README.md +++ b/avm/res/signal-r-service/web-pub-sub/README.md @@ -664,6 +664,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -860,6 +861,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/signal-r-service/web-pub-sub/main.bicep b/avm/res/signal-r-service/web-pub-sub/main.bicep index 7df5cef044..6f0d42ceb5 100644 --- a/avm/res/signal-r-service/web-pub-sub/main.bicep +++ b/avm/res/signal-r-service/web-pub-sub/main.bicep @@ -340,6 +340,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/signal-r-service/web-pub-sub/main.json b/avm/res/signal-r-service/web-pub-sub/main.json index b0cd717eea..bb5da794c7 100644 --- a/avm/res/signal-r-service/web-pub-sub/main.json +++ b/avm/res/signal-r-service/web-pub-sub/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "5123587026582880440" + "templateHash": "17706812200280440535" }, "name": "SignalR Web PubSub Services", "description": "This module deploys a SignalR Web PubSub Service.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/sql/server/README.md b/avm/res/sql/server/README.md index ed1f6f52c9..31d607a435 100644 --- a/avm/res/sql/server/README.md +++ b/avm/res/sql/server/README.md @@ -1251,6 +1251,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -1447,6 +1448,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/sql/server/main.bicep b/avm/res/sql/server/main.bicep index 1b95eb7fb0..b068331ee2 100644 --- a/avm/res/sql/server/main.bicep +++ b/avm/res/sql/server/main.bicep @@ -529,6 +529,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/sql/server/main.json b/avm/res/sql/server/main.json index ef545418bd..5611ff656f 100644 --- a/avm/res/sql/server/main.json +++ b/avm/res/sql/server/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "16217985022425971907" + "templateHash": "7285009334035421293" }, "name": "Azure SQL Servers", "description": "This module deploys an Azure SQL Server.", @@ -146,6 +146,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/synapse/private-link-hub/README.md b/avm/res/synapse/private-link-hub/README.md index 676a1ea168..0fe999a92c 100644 --- a/avm/res/synapse/private-link-hub/README.md +++ b/avm/res/synapse/private-link-hub/README.md @@ -420,6 +420,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`service`](#parameter-privateendpointsservice) | string | The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory". | @@ -616,6 +617,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/synapse/private-link-hub/main.bicep b/avm/res/synapse/private-link-hub/main.bicep index c704bb0d20..f7294f8188 100644 --- a/avm/res/synapse/private-link-hub/main.bicep +++ b/avm/res/synapse/private-link-hub/main.bicep @@ -204,6 +204,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Optional. The subresource to deploy the private endpoint for. For example "vault", "mysqlServer" or "dataFactory".') service: string? diff --git a/avm/res/synapse/private-link-hub/main.json b/avm/res/synapse/private-link-hub/main.json index edf4acca71..fd84d2835d 100644 --- a/avm/res/synapse/private-link-hub/main.json +++ b/avm/res/synapse/private-link-hub/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "13337660618824697392" + "templateHash": "10734135538553335635" }, "name": "Azure Synapse Analytics", "description": "This module deploys an Azure Synapse Analytics (Private Link Hub).", @@ -123,6 +123,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "nullable": true, diff --git a/avm/res/synapse/workspace/README.md b/avm/res/synapse/workspace/README.md index e3b70632bd..62fbe376dd 100644 --- a/avm/res/synapse/workspace/README.md +++ b/avm/res/synapse/workspace/README.md @@ -1144,6 +1144,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | | [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if privateDnsZoneResourceIds were provided. | | [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | | [`tags`](#parameter-privateendpointstags) | object | Tags to be applied on all resources/resource groups in this deployment. | @@ -1346,6 +1347,13 @@ The private DNS zone groups to associate the private endpoint with. A DNS zone g - Required: No - Type: array +### Parameter: `privateEndpoints.privateLinkServiceConnectionName` + +The name of the private link connection to create. + +- Required: No +- Type: string + ### Parameter: `privateEndpoints.resourceGroupName` Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. diff --git a/avm/res/synapse/workspace/main.bicep b/avm/res/synapse/workspace/main.bicep index cd2ebc4b68..1e9c17624b 100644 --- a/avm/res/synapse/workspace/main.bicep +++ b/avm/res/synapse/workspace/main.bicep @@ -451,6 +451,9 @@ type privateEndpointType = { @description('Optional. The location to deploy the private endpoint to.') location: string? + @description('Optional. The name of the private link connection to create.') + privateLinkServiceConnectionName: string? + @description('Required. The subresource to deploy the private endpoint for. For example "blob", "table", "queue" or "file".') service: string diff --git a/avm/res/synapse/workspace/main.json b/avm/res/synapse/workspace/main.json index 4ae63838c2..89049892d8 100644 --- a/avm/res/synapse/workspace/main.json +++ b/avm/res/synapse/workspace/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.26.54.24096", - "templateHash": "229457556089965339" + "templateHash": "456170449467900103" }, "name": "Synapse Workspaces", "description": "This module deploys a Synapse Workspace.", @@ -138,6 +138,13 @@ "description": "Optional. The location to deploy the private endpoint to." } }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, "service": { "type": "string", "metadata": { diff --git a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 index 7a30bfa96d..a2c1a5f98d 100644 --- a/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 +++ b/avm/utilities/pipelines/platform/Set-AvmGithubIssueForWorkflow.ps1 @@ -6,7 +6,10 @@ Check for failing pipelines and create issues for those, that are failing. If a pipeline fails, a new issue will be created, with a link to the failed pipeline. If the issue is already existing, a comment will be added, if a new run failed (with the link for the new failed run). If a pipeline run succeeds and an issue is open for the failed run, it will be closed (and a link to the successful run is added to the issue). .PARAMETER Repo -Mandatory. The name of the respository to scan. Needs to have the structure "/" +Mandatory. The name of the respository to scan. Needs to have the structure "/", like 'Azure/bicep-registry-modules/' + +.PARAMETER RepoRoot +Optional. Path to the root of the repository. .PARAMETER LimitNumberOfRuns Optional. Number of recent runs to scan for failed runs. Default is 100. @@ -23,7 +26,7 @@ Set-AvmGithubIssueForWorkflow -Repo 'owner/repo01' -LimitNumberOfRuns 100 -Limit Check the last 100 workflow runs in the repository 'owner/repo01' that happened in the last 2 days. If the workflow name is 'Pipeline 01', then ignore the workflow run. .NOTES -The function requires GitHub CLI to be installed. +Will be triggered by the workflow avm.platform.manage-workflow-issue.yml #> function Set-AvmGithubIssueForWorkflow { [CmdletBinding(SupportsShouldProcess)] @@ -31,6 +34,9 @@ function Set-AvmGithubIssueForWorkflow { [Parameter(Mandatory = $true)] [string] $Repo, + [Parameter(Mandatory = $false)] + [string] $RepoRoot = (Get-Item -Path $PSScriptRoot).parent.parent.parent.parent.FullName, + [Parameter(Mandatory = $false)] [int] $LimitNumberOfRuns = 100, @@ -41,6 +47,10 @@ function Set-AvmGithubIssueForWorkflow { [String[]] $IgnoreWorkflows = @() ) + # Loading helper functions + . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'platform' 'helper' 'Get-AvmCsvData.ps1') + . (Join-Path $RepoRoot 'avm' 'utilities' 'pipelines' 'platform' 'helper' 'Add-GithubIssueToProject.ps1') + $issues = gh issue list --state open --limit 500 --label 'Type: AVM :a: :v: :m:,Type: Bug :bug:' --json 'title,url,body,comments,labels' --repo $Repo | ConvertFrom-Json -Depth 100 $runs = gh run list --json 'url,workflowName,headBranch,startedAt' --limit $LimitNumberOfRuns --repo $Repo | ConvertFrom-Json -Depth 100 $workflowRuns = @{} @@ -81,7 +91,45 @@ function Set-AvmGithubIssueForWorkflow { if ($issues.title -notcontains $issueName) { if ($PSCmdlet.ShouldProcess("Issue [$issueName]", 'Create')) { - gh issue create --title "$issueName" --body "$failedrun" --label 'Type: AVM :a: :v: :m:,Type: Bug :bug:' --repo $Repo + $issueUrl = gh issue create --title "$issueName" --body "$failedrun" --label 'Type: AVM :a: :v: :m:,Type: Bug :bug:' --repo $Repo + $ProjectNumber = 538 # AVM - Issue Triage + $comment = @" +> [!IMPORTANT] +> @Azure/avm-core-team-technical-bicep, the workflow for the ``$moduleName`` module has failed. Please investigate the failed workflow run. +"@ + + if ($workflowRun.workflowName -match 'avm.(?:res|ptn)') { + $moduleName = $workflowRun.workflowName.Replace('.', '/') + $moduleIndex = $moduleName.StartsWith('avm/res') ? 'Bicep-Resource' : 'Bicep-Pattern' + # get CSV data + $module = Get-AvmCsvData -ModuleIndex $moduleIndex | Where-Object ModuleName -EQ $moduleName + + if (($module.ModuleStatus -ne 'Module Orphaned :eyes:') -and (-not ([string]::IsNullOrEmpty($module.PrimaryModuleOwnerGHHandle)))) { + $ProjectNumber = 566 # AVM - Module Issues + $comment = @" +> [!IMPORTANT] +> @$($module.ModuleOwnersGHTeam), the workflow for the ``$moduleName`` module has failed. Please investigate the failed workflow run. If you are not able to do so, please inform the AVM core team to take over. +"@ + # assign owner + $assign = gh issue edit $issue.url --add-assignee $module.PrimaryModuleOwnerGHHandle --repo $Repo + + if ([String]::IsNullOrEmpty($assign)) { + if ($PSCmdlet.ShouldProcess("missing user comment to issue [$($issue.title)]", 'Add')) { + $comment = @" +> [!WARNING] +> This issue couldn't be assigend due to an internal error. @$($module.PrimaryModuleOwnerGHHandle), please make sure this issue is assigned to you and please provide an initial response as soon as possible, in accordance with the [AVM Support statement](https://aka.ms/AVM/Support). +"@ + + gh issue comment $issue.url --body $reply --repo $Repo + } + } + } + } + + # add issue to project + Add-GithubIssueToProject -Repo $Repo -ProjectNumber $ProjectNumber -IssueUrl $issueUrl + # add comment + gh issue comment $issueUrl --body $comment --repo $Repo } $issuesCreated++ diff --git a/avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1 b/avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1 new file mode 100644 index 0000000000..cd9d0222e4 --- /dev/null +++ b/avm/utilities/pipelines/platform/helper/Add-GithubIssueToProject.ps1 @@ -0,0 +1,57 @@ +<# +.SYNOPSIS +Adds an existing GitHub issue to an existing GitHub project (the new type, not the classic ones) + +.DESCRIPTION +Adds an existing GitHub issue to an existing GitHub project (the new type, not the classic ones) + +.PARAMETER Repo +Mandatory. The name of the respository to scan. Needs to have the structure "/", like 'Azure/bicep-registry-modules/' + +.PARAMETER ProjectNumber +Mandatory. The GitHub project number (see last part of project URL, for example 538 for https://github.com/orgs/Azure/projects/538) + +.PARAMETER IssueUrl +Mandatory. The URL of the GitHub issue, like 'https://github.com/Azure/bicep-registry-modules/issues/757' + +.EXAMPLE +Add-GithubIssueToProject -Repo 'Azure/bicep-registry-modules' -ProjectNumber 538 -IssueUrl 'https://github.com/Azure/bicep-registry-modules/issues/757' + +.NOTES +Needs to run under a context with the permissions to read/write organization projects +#> +function Add-GithubIssueToProject { + param ( + [Parameter(Mandatory = $true)] + [string] $Repo, + + [Parameter(Mandatory = $true)] + [int] $ProjectNumber, + + [Parameter(Mandatory = $true)] + [string] $IssueUrl + ) + + $Organization = $Repo.Split('/')[0] + + $Project = gh api graphql -f query=' + query($organization: String! $number: Int!){ + organization(login: $organization){ + projectV2(number: $number) { + id + } + } + }' -f organization=$Organization -F number=$ProjectNumber | ConvertFrom-Json -Depth 10 + + $ProjectId = $Project.data.organization.projectV2.id + $IssueId = (gh issue view $IssueUrl --repo $Repo --json 'id' | ConvertFrom-Json -Depth 100).id + + gh api graphql -f query=' + mutation($project:ID!, $issue:ID!) { + addProjectV2ItemById(input: {projectId: $project, contentId: $issue}) { + item { + id + } + } + }' -f project=$ProjectId -f issue=$IssueId +} diff --git a/avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1 b/avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1 new file mode 100644 index 0000000000..821f476bb7 --- /dev/null +++ b/avm/utilities/pipelines/platform/helper/Get-AvmCsvData.ps1 @@ -0,0 +1,59 @@ +<# +.SYNOPSIS +Parses AVM module CSV file + +.DESCRIPTION +Depending on the parameter, the correct CSV file will be parsed and returned a an object + +.PARAMETER ModuleIndex +Mandatory. Type of CSV file, that should be parsed ('Bicep-Resource', 'Bicep-Pattern') + +.EXAMPLE +Get-AvmCsvData -ModuleIndex 'Bicep-Resource' + +Parse the AVM Bicep modules +#> +Function Get-AvmCsvData { + [CmdletBinding()] + param ( + [Parameter(Mandatory)] + [ValidateSet('Bicep-Resource', 'Bicep-Pattern')] + [string] $ModuleIndex + ) + + # CSV file URLs + $BicepResourceUrl = 'https://aka.ms/avm/index/bicep/res/csv' + $BicepPatternUrl = 'https://aka.ms/avm/index/bicep/ptn/csv' + + # Retrieve the CSV file + switch ($ModuleIndex) { + 'Bicep-Resource' { + try { + $unfilteredCSV = Invoke-WebRequest -Uri $BicepResourceUrl + } catch { + throw 'Unable to retrieve CSV file - Check network connection.' + } + } + 'Bicep-Pattern' { + try { + $unfilteredCSV = Invoke-WebRequest -Uri $BicepPatternUrl + } catch { + throw 'Unable to retrieve CSV file - Check network connection.' + } + } + } + + # Convert the CSV content to a PowerShell object + $formattedBicepFullCsv = ConvertFrom-Csv $unfilteredCSV.Content + + # Loop through each item in the filtered data + foreach ($item in $formattedBicepFullCsv) { + # Remove '@Azure/' from the ModuleOwnersGHTeam property + $item.ModuleOwnersGHTeam = $item.ModuleOwnersGHTeam -replace '@Azure\/', '' + # Remove '@Azure/' from the ModuleContributorsGHTeam property + $item.ModuleContributorsGHTeam = $item.ModuleContributorsGHTeam -replace '@Azure\/', '' + } + + # Return the modified data + return $formattedBicepFullCsv +}